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.Objects;
021import java.util.Optional;
022import org.apache.hadoop.hbase.ServerName;
023import org.apache.hadoop.hbase.util.Bytes;
024import org.apache.yetus.audience.InterfaceAudience;
025
026@InterfaceAudience.Private
027public class ReplicationQueueId {
028
029  private final ServerName serverName;
030
031  private final String peerId;
032
033  private final Optional<ServerName> sourceServerName;
034
035  // we do not allow '-' in peer names so it is safe to use it as the separator for peer id and
036  // server name
037  private static final char PEER_ID_SEPARATOR = '-';
038
039  // The '/' character is not valid for a hostname or a nodename(FQDN, so it is safe to use it as
040  // the separator for server names)
041  private static final char SERVER_NAME_SEPARATOR = '/';
042
043  public ReplicationQueueId(ServerName serverName, String peerId) {
044    this.serverName = Objects.requireNonNull(serverName);
045    this.peerId = Objects.requireNonNull(peerId);
046    this.sourceServerName = Optional.empty();
047  }
048
049  public ReplicationQueueId(ServerName serverName, String peerId, ServerName sourceServerName) {
050    this.serverName = Objects.requireNonNull(serverName);
051    this.peerId = Objects.requireNonNull(peerId);
052    this.sourceServerName = Optional.of(sourceServerName);
053  }
054
055  public ServerName getServerName() {
056    return serverName;
057  }
058
059  public String getPeerId() {
060    return peerId;
061  }
062
063  public Optional<ServerName> getSourceServerName() {
064    return sourceServerName;
065  }
066
067  public ServerName getServerWALsBelongTo() {
068    return sourceServerName.orElse(serverName);
069  }
070
071  public boolean isRecovered() {
072    return sourceServerName.isPresent();
073  }
074
075  public ReplicationQueueId claim(ServerName targetServerName) {
076    ServerName newSourceServerName = sourceServerName.orElse(serverName);
077    return new ReplicationQueueId(targetServerName, peerId, newSourceServerName);
078  }
079
080  @Override
081  public int hashCode() {
082    return Objects.hash(peerId, serverName, sourceServerName);
083  }
084
085  @Override
086  public boolean equals(Object obj) {
087    if (this == obj) {
088      return true;
089    }
090    if (!(obj instanceof ReplicationQueueId)) {
091      return false;
092    }
093    ReplicationQueueId other = (ReplicationQueueId) obj;
094    return Objects.equals(peerId, other.peerId) && Objects.equals(serverName, other.serverName)
095      && Objects.equals(sourceServerName, other.sourceServerName);
096  }
097
098  @Override
099  public String toString() {
100    StringBuilder sb =
101      new StringBuilder().append(peerId).append(PEER_ID_SEPARATOR).append(serverName);
102    sourceServerName.ifPresent(s -> sb.append(SERVER_NAME_SEPARATOR).append(s.toString()));
103    return sb.toString();
104  }
105
106  public static ReplicationQueueId parse(String str) {
107    int dashIndex = str.indexOf(PEER_ID_SEPARATOR);
108    String peerId = str.substring(0, dashIndex);
109    int slashIndex = str.indexOf(SERVER_NAME_SEPARATOR, dashIndex + 1);
110    if (slashIndex < 0) {
111      String serverName = str.substring(dashIndex + 1);
112      return new ReplicationQueueId(ServerName.valueOf(serverName), peerId);
113    } else {
114      String serverName = str.substring(dashIndex + 1, slashIndex);
115      String sourceServerName = str.substring(slashIndex + 1);
116      return new ReplicationQueueId(ServerName.valueOf(serverName), peerId,
117        ServerName.valueOf(sourceServerName));
118    }
119  }
120
121  public static String getPeerId(String str) {
122    int dashIndex = str.indexOf(PEER_ID_SEPARATOR);
123    return str.substring(0, dashIndex);
124  }
125
126  public static byte[] getScanPrefix(ServerName serverName, String peerId) {
127    return Bytes.toBytes(peerId + PEER_ID_SEPARATOR + serverName.toString());
128  }
129
130  public static byte[] getScanPrefix(String peerId) {
131    return Bytes.toBytes(peerId + PEER_ID_SEPARATOR);
132  }
133
134  private static char getNextChar(char c) {
135    return (char) ((int) c + 1);
136  }
137
138  public static byte[] getScanStartRowForNextPeerId(String peerId) {
139    return Bytes.toBytes(peerId + getNextChar(PEER_ID_SEPARATOR));
140  }
141}