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