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
021
022import java.util.ArrayList;
023import java.util.Collections;
024import java.util.List;
025
026import org.apache.yetus.audience.InterfaceAudience;
027import org.slf4j.Logger;
028import org.slf4j.LoggerFactory;
029import org.apache.hadoop.hbase.ServerName;
030
031/**
032 * This class is responsible for the parsing logic for a znode representing a queue.
033 * It will extract the peerId if it's recovered as well as the dead region servers
034 * that were part of the queue's history.
035 */
036@InterfaceAudience.Private
037public class ReplicationQueueInfo {
038  private static final Logger LOG = LoggerFactory.getLogger(ReplicationQueueInfo.class);
039
040  private final String peerId;
041  private final String peerClusterZnode;
042  private boolean queueRecovered;
043  // List of all the dead region servers that had this queue (if recovered)
044  private List<ServerName> deadRegionServers = new ArrayList<>();
045
046  /**
047   * The passed znode will be either the id of the peer cluster or
048   * the handling story of that queue in the form of id-servername-*
049   */
050  public ReplicationQueueInfo(String znode) {
051    this.peerClusterZnode = znode;
052    String[] parts = znode.split("-", 2);
053    this.queueRecovered = parts.length != 1;
054    this.peerId = this.queueRecovered ?
055        parts[0] : peerClusterZnode;
056    if (parts.length >= 2) {
057      // extract dead servers
058      extractDeadServersFromZNodeString(parts[1], this.deadRegionServers);
059    }
060  }
061
062  /**
063   * Parse dead server names from znode string servername can contain "-" such as
064   * "ip-10-46-221-101.ec2.internal", so we need skip some "-" during parsing for the following
065   * cases: 2-ip-10-46-221-101.ec2.internal,52170,1364333181125-&lt;server name>-...
066   */
067  private static void
068      extractDeadServersFromZNodeString(String deadServerListStr, List<ServerName> result) {
069
070    if(deadServerListStr == null || result == null || deadServerListStr.isEmpty()) return;
071
072    // valid server name delimiter "-" has to be after "," in a server name
073    int seenCommaCnt = 0;
074    int startIndex = 0;
075    int len = deadServerListStr.length();
076
077    for (int i = 0; i < len; i++) {
078      switch (deadServerListStr.charAt(i)) {
079      case ',':
080        seenCommaCnt += 1;
081        break;
082      case '-':
083        if(seenCommaCnt>=2) {
084          if (i > startIndex) {
085            String serverName = deadServerListStr.substring(startIndex, i);
086            if(ServerName.isFullServerName(serverName)){
087              result.add(ServerName.valueOf(serverName));
088            } else {
089              LOG.error("Found invalid server name:" + serverName);
090            }
091            startIndex = i + 1;
092          }
093          seenCommaCnt = 0;
094        }
095        break;
096      default:
097        break;
098      }
099    }
100
101    // add tail
102    if(startIndex < len - 1){
103      String serverName = deadServerListStr.substring(startIndex, len);
104      if(ServerName.isFullServerName(serverName)){
105        result.add(ServerName.valueOf(serverName));
106      } else {
107        LOG.error("Found invalid server name at the end:" + serverName);
108      }
109    }
110
111    LOG.debug("Found dead servers:" + result);
112  }
113
114  public List<ServerName> getDeadRegionServers() {
115    return Collections.unmodifiableList(this.deadRegionServers);
116  }
117
118  public String getPeerId() {
119    return this.peerId;
120  }
121
122  public String getPeerClusterZnode() {
123    return this.peerClusterZnode;
124  }
125
126  public boolean isQueueRecovered() {
127    return queueRecovered;
128  }
129}