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.zookeeper;
019
020import static org.apache.hadoop.hbase.HConstants.DEFAULT_META_REPLICA_NUM;
021import static org.apache.hadoop.hbase.HConstants.DEFAULT_ZOOKEEPER_ZNODE_PARENT;
022import static org.apache.hadoop.hbase.HConstants.META_REPLICAS_NUM;
023import static org.apache.hadoop.hbase.HConstants.SPLIT_LOGDIR_NAME;
024import static org.apache.hadoop.hbase.HConstants.ZOOKEEPER_ZNODE_PARENT;
025import static org.apache.hadoop.hbase.client.RegionInfo.DEFAULT_REPLICA_ID;
026
027import java.util.Collection;
028import java.util.Optional;
029import java.util.stream.IntStream;
030import org.apache.hadoop.conf.Configuration;
031import org.apache.hadoop.hbase.client.RegionInfo;
032import org.apache.yetus.audience.InterfaceAudience;
033
034import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap;
035
036/**
037 * Class that hold all the paths of znode for HBase.
038 */
039@InterfaceAudience.Private
040public class ZNodePaths {
041  // TODO: Replace this with ZooKeeper constant when ZOOKEEPER-277 is resolved.
042  public static final char ZNODE_PATH_SEPARATOR = '/';
043
044  public static final String META_ZNODE_PREFIX_CONF_KEY = "zookeeper.znode.metaserver";
045  public static final String META_ZNODE_PREFIX = "meta-region-server";
046  private static final String DEFAULT_SNAPSHOT_CLEANUP_ZNODE = "snapshot-cleanup";
047
048  // base znode for this cluster
049  public final String baseZNode;
050
051  /**
052   * The prefix of meta znode. Does not include baseZNode.
053   * Its a 'prefix' because meta replica id integer can be tagged on the end (if
054   * no number present, it is 'default' replica).
055   */
056  private final String metaZNodePrefix;
057
058  /**
059   * znodes containing the locations of the servers hosting the meta replicas
060   */
061  private final ImmutableMap<Integer, String> metaReplicaZNodes;
062
063  // znode containing ephemeral nodes of the regionservers
064  public final String rsZNode;
065  // znode containing ephemeral nodes of the draining regionservers
066  public final String drainingZNode;
067  // znode of currently active master
068  public final String masterAddressZNode;
069  // znode of this master in backup master directory, if not the active master
070  public final String backupMasterAddressesZNode;
071  // znode containing the current cluster state
072  public final String clusterStateZNode;
073  // znode used for table disabling/enabling
074  // Still used in hbase2 by MirroringTableStateManager; it mirrors internal table state out to
075  // zookeeper for hbase1 clients to make use of. If no hbase1 clients disable. See
076  // MirroringTableStateManager. To be removed in hbase3.
077  @Deprecated
078  public final String tableZNode;
079  // znode containing the unique cluster ID
080  public final String clusterIdZNode;
081  // znode used for log splitting work assignment
082  public final String splitLogZNode;
083  // znode containing the state of the load balancer
084  public final String balancerZNode;
085  // znode containing the state of region normalizer
086  public final String regionNormalizerZNode;
087  // znode containing the state of all switches, currently there are split and merge child node.
088  public final String switchZNode;
089  // znode containing namespace descriptors
090  public final String namespaceZNode;
091  // znode of indicating master maintenance mode
092  public final String masterMaintZNode;
093
094  // znode containing all replication state.
095  public final String replicationZNode;
096  // znode containing a list of all remote slave (i.e. peer) clusters.
097  public final String peersZNode;
098  // znode containing all replication queues
099  public final String queuesZNode;
100  // znode containing queues of hfile references to be replicated
101  public final String hfileRefsZNode;
102  // znode containing the state of the snapshot auto-cleanup
103  final String snapshotCleanupZNode;
104
105  public ZNodePaths(Configuration conf) {
106    baseZNode = conf.get(ZOOKEEPER_ZNODE_PARENT, DEFAULT_ZOOKEEPER_ZNODE_PARENT);
107    ImmutableMap.Builder<Integer, String> builder = ImmutableMap.builder();
108    metaZNodePrefix = conf.get(META_ZNODE_PREFIX_CONF_KEY, META_ZNODE_PREFIX);
109    String defaultMetaReplicaZNode = ZNodePaths.joinZNode(baseZNode, metaZNodePrefix);
110    builder.put(DEFAULT_REPLICA_ID, defaultMetaReplicaZNode);
111    int numMetaReplicas = conf.getInt(META_REPLICAS_NUM, DEFAULT_META_REPLICA_NUM);
112    IntStream.range(1, numMetaReplicas)
113        .forEachOrdered(i -> builder.put(i, defaultMetaReplicaZNode + "-" + i));
114    metaReplicaZNodes = builder.build();
115    rsZNode = joinZNode(baseZNode, conf.get("zookeeper.znode.rs", "rs"));
116    drainingZNode = joinZNode(baseZNode, conf.get("zookeeper.znode.draining.rs", "draining"));
117    masterAddressZNode = joinZNode(baseZNode, conf.get("zookeeper.znode.master", "master"));
118    backupMasterAddressesZNode =
119        joinZNode(baseZNode, conf.get("zookeeper.znode.backup.masters", "backup-masters"));
120    clusterStateZNode = joinZNode(baseZNode, conf.get("zookeeper.znode.state", "running"));
121    tableZNode = joinZNode(baseZNode, conf.get("zookeeper.znode.tableEnableDisable", "table"));
122    clusterIdZNode = joinZNode(baseZNode, conf.get("zookeeper.znode.clusterId", "hbaseid"));
123    splitLogZNode = joinZNode(baseZNode, conf.get("zookeeper.znode.splitlog", SPLIT_LOGDIR_NAME));
124    balancerZNode = joinZNode(baseZNode, conf.get("zookeeper.znode.balancer", "balancer"));
125    regionNormalizerZNode =
126        joinZNode(baseZNode, conf.get("zookeeper.znode.regionNormalizer", "normalizer"));
127    switchZNode = joinZNode(baseZNode, conf.get("zookeeper.znode.switch", "switch"));
128    namespaceZNode = joinZNode(baseZNode, conf.get("zookeeper.znode.namespace", "namespace"));
129    masterMaintZNode =
130        joinZNode(baseZNode, conf.get("zookeeper.znode.masterMaintenance", "master-maintenance"));
131    replicationZNode = joinZNode(baseZNode, conf.get("zookeeper.znode.replication", "replication"));
132    peersZNode =
133        joinZNode(replicationZNode, conf.get("zookeeper.znode.replication.peers", "peers"));
134    queuesZNode = joinZNode(replicationZNode, conf.get("zookeeper.znode.replication.rs", "rs"));
135    hfileRefsZNode = joinZNode(replicationZNode,
136      conf.get("zookeeper.znode.replication.hfile.refs", "hfile-refs"));
137    snapshotCleanupZNode = joinZNode(baseZNode,
138        conf.get("zookeeper.znode.snapshot.cleanup", DEFAULT_SNAPSHOT_CLEANUP_ZNODE));
139  }
140
141  @Override
142  public String toString() {
143    return new StringBuilder()
144        .append("ZNodePaths [baseZNode=").append(baseZNode)
145        .append(", metaReplicaZNodes=").append(metaReplicaZNodes)
146        .append(", rsZNode=").append(rsZNode)
147        .append(", drainingZNode=").append(drainingZNode)
148        .append(", masterAddressZNode=").append(masterAddressZNode)
149        .append(", backupMasterAddressesZNode=").append(backupMasterAddressesZNode)
150        .append(", clusterStateZNode=").append(clusterStateZNode)
151        .append(", tableZNode=").append(tableZNode)
152        .append(", clusterIdZNode=").append(clusterIdZNode)
153        .append(", splitLogZNode=").append(splitLogZNode)
154        .append(", balancerZNode=").append(balancerZNode)
155        .append(", regionNormalizerZNode=").append(regionNormalizerZNode)
156        .append(", switchZNode=").append(switchZNode)
157        .append(", namespaceZNode=").append(namespaceZNode)
158        .append(", masterMaintZNode=").append(masterMaintZNode)
159        .append(", replicationZNode=").append(replicationZNode)
160        .append(", peersZNode=").append(peersZNode)
161        .append(", queuesZNode=").append(queuesZNode)
162        .append(", hfileRefsZNode=").append(hfileRefsZNode)
163        .append(", snapshotCleanupZNode=").append(snapshotCleanupZNode)
164        .append("]").toString();
165  }
166
167  /**
168   * @return true if the znode is a meta region replica
169   */
170  public boolean isAnyMetaReplicaZNode(String node) {
171    return this.metaReplicaZNodes.containsValue(node);
172  }
173
174  /**
175   * @return Meta Replica ZNodes
176   */
177  public Collection<String> getMetaReplicaZNodes() {
178    return this.metaReplicaZNodes.values();
179  }
180
181  /**
182   * @return the znode string corresponding to a replicaId
183   */
184  public String getZNodeForReplica(int replicaId) {
185    // return a newly created path but don't update the cache of paths
186    // This is mostly needed for tests that attempt to create meta replicas
187    // from outside the master
188    return Optional.ofNullable(metaReplicaZNodes.get(replicaId))
189        .orElseGet(() -> metaReplicaZNodes.get(DEFAULT_REPLICA_ID) + "-" + replicaId);
190  }
191
192  /**
193   * Parses the meta replicaId from the passed path.
194   * @param path the name of the full path which includes baseZNode.
195   * @return replicaId
196   */
197  public int getMetaReplicaIdFromPath(String path) {
198    // Extract the znode from path. The prefix is of the following format.
199    // baseZNode + PATH_SEPARATOR.
200    int prefixLen = baseZNode.length() + 1;
201    return getMetaReplicaIdFromZnode(path.substring(prefixLen));
202  }
203
204  /**
205   * Parse the meta replicaId from the passed znode
206   * @param znode the name of the znode, does not include baseZNode
207   * @return replicaId
208   */
209  public int getMetaReplicaIdFromZnode(String znode) {
210    return znode.equals(metaZNodePrefix)?
211        RegionInfo.DEFAULT_REPLICA_ID:
212        Integer.parseInt(znode.substring(metaZNodePrefix.length() + 1));
213  }
214
215  /**
216   * @return True if meta znode.
217   */
218  public boolean isMetaZNodePrefix(String znode) {
219    return znode != null && znode.startsWith(this.metaZNodePrefix);
220  }
221
222  /**
223   * Returns whether the znode is supposed to be readable by the client and DOES NOT contain
224   * sensitive information (world readable).
225   */
226  public boolean isClientReadable(String node) {
227    // Developer notice: These znodes are world readable. DO NOT add more znodes here UNLESS
228    // all clients need to access this data to work. Using zk for sharing data to clients (other
229    // than service lookup case is not a recommended design pattern.
230    return node.equals(baseZNode) || isAnyMetaReplicaZNode(node) ||
231      node.equals(masterAddressZNode) || node.equals(clusterIdZNode) || node.equals(rsZNode) ||
232      // /hbase/table and /hbase/table/foo is allowed, /hbase/table-lock is not
233      node.equals(tableZNode) || node.startsWith(tableZNode + "/");
234  }
235
236  /**
237   * Join the prefix znode name with the suffix znode name to generate a proper full znode name.
238   * <p>
239   * Assumes prefix does not end with slash and suffix does not begin with it.
240   * @param prefix beginning of znode name
241   * @param suffix ending of znode name
242   * @return result of properly joining prefix with suffix
243   */
244  public static String joinZNode(String prefix, String suffix) {
245    return prefix + ZNodePaths.ZNODE_PATH_SEPARATOR + suffix;
246  }
247}