001/*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase.replication;
020
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.List;
024
025import org.apache.hadoop.hbase.ServerName;
026import org.apache.yetus.audience.InterfaceAudience;
027import org.slf4j.Logger;
028import org.slf4j.LoggerFactory;
029
030/**
031 * This class is responsible for the parsing logic for a queue id representing a queue.
032 * It will extract the peerId if it's recovered as well as the dead region servers
033 * that were part of the queue's history.
034 */
035@InterfaceAudience.Private
036public class ReplicationQueueInfo {
037  private static final Logger LOG = LoggerFactory.getLogger(ReplicationQueueInfo.class);
038
039  private final String peerId;
040  private final String queueId;
041  private boolean queueRecovered;
042  // List of all the dead region servers that had this queue (if recovered)
043  private List<ServerName> deadRegionServers = new ArrayList<>();
044
045  /**
046   * The passed queueId will be either the id of the peer or the handling story of that queue
047   * in the form of id-servername-*
048   */
049  public ReplicationQueueInfo(String queueId) {
050    this.queueId = queueId;
051    String[] parts = queueId.split("-", 2);
052    this.queueRecovered = parts.length != 1;
053    this.peerId = this.queueRecovered ? parts[0] : queueId;
054    if (parts.length >= 2) {
055      // extract dead servers
056      extractDeadServersFromZNodeString(parts[1], this.deadRegionServers);
057    }
058  }
059
060  /**
061   * Parse dead server names from queue id. servername can contain "-" such as
062   * "ip-10-46-221-101.ec2.internal", so we need skip some "-" during parsing for the following
063   * cases: 2-ip-10-46-221-101.ec2.internal,52170,1364333181125-&lt;server name>-...
064   */
065  private static void
066      extractDeadServersFromZNodeString(String deadServerListStr, List<ServerName> result) {
067    if(deadServerListStr == null || result == null || deadServerListStr.isEmpty()) {
068      return;
069    }
070
071    // valid server name delimiter "-" has to be after "," in a server name
072    int seenCommaCnt = 0;
073    int startIndex = 0;
074    int len = deadServerListStr.length();
075
076    for (int i = 0; i < len; i++) {
077      switch (deadServerListStr.charAt(i)) {
078        case ',':
079          seenCommaCnt += 1;
080          break;
081        case '-':
082          if(seenCommaCnt>=2) {
083            if (i > startIndex) {
084              String serverName = deadServerListStr.substring(startIndex, i);
085              if(ServerName.isFullServerName(serverName)){
086                result.add(ServerName.valueOf(serverName));
087              } else {
088                LOG.error("Found invalid server name:" + serverName);
089              }
090              startIndex = i + 1;
091            }
092            seenCommaCnt = 0;
093          }
094          break;
095        default:
096          break;
097      }
098    }
099
100    // add tail
101    if(startIndex < len - 1){
102      String serverName = deadServerListStr.substring(startIndex, len);
103      if(ServerName.isFullServerName(serverName)){
104        result.add(ServerName.valueOf(serverName));
105      } else {
106        LOG.error("Found invalid server name at the end:" + serverName);
107      }
108    }
109
110    LOG.debug("Found dead servers:" + result);
111  }
112
113  public List<ServerName> getDeadRegionServers() {
114    return Collections.unmodifiableList(this.deadRegionServers);
115  }
116
117  public String getPeerId() {
118    return this.peerId;
119  }
120
121  public String getQueueId() {
122    return this.queueId;
123  }
124
125  public boolean isQueueRecovered() {
126    return queueRecovered;
127  }
128}