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.master;
020
021import java.io.IOException;
022import java.util.List;
023import org.apache.hadoop.hbase.HConstants;
024import org.apache.hadoop.hbase.ServerName;
025import org.apache.hadoop.hbase.client.RegionInfo;
026import org.apache.hadoop.hbase.client.RegionInfoBuilder;
027import org.apache.hadoop.hbase.client.RegionReplicaUtil;
028import org.apache.hadoop.hbase.master.assignment.AssignmentManager;
029import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
030import org.apache.hadoop.hbase.zookeeper.ZKUtil;
031import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
032import org.apache.yetus.audience.InterfaceAudience;
033import org.apache.zookeeper.KeeperException;
034import org.slf4j.Logger;
035import org.slf4j.LoggerFactory;
036
037/**
038 * Used by the HMaster on startup to split meta logs and assign the meta table.
039 */
040@InterfaceAudience.Private
041class MasterMetaBootstrap {
042  private static final Logger LOG = LoggerFactory.getLogger(MasterMetaBootstrap.class);
043
044  private final HMaster master;
045
046  public MasterMetaBootstrap(HMaster master) {
047    this.master = master;
048  }
049
050  /**
051   * For assigning hbase:meta replicas only.
052   * TODO: The way this assign runs, nothing but chance to stop all replicas showing up on same
053   * server as the hbase:meta region.
054   */
055  void assignMetaReplicas()
056      throws IOException, InterruptedException, KeeperException {
057    int numReplicas = master.getConfiguration().getInt(HConstants.META_REPLICAS_NUM,
058           HConstants.DEFAULT_META_REPLICA_NUM);
059    if (numReplicas <= 1) {
060      // No replicaas to assign. Return.
061      return;
062    }
063    final AssignmentManager assignmentManager = master.getAssignmentManager();
064    if (!assignmentManager.isMetaLoaded()) {
065      throw new IllegalStateException("hbase:meta must be initialized first before we can " +
066          "assign out its replicas");
067    }
068    ServerName metaServername = MetaTableLocator.getMetaRegionLocation(this.master.getZooKeeper());
069    for (int i = 1; i < numReplicas; i++) {
070      // Get current meta state for replica from zk.
071      RegionState metaState = MetaTableLocator.getMetaRegionState(master.getZooKeeper(), i);
072      RegionInfo hri = RegionReplicaUtil.getRegionInfoForReplica(
073          RegionInfoBuilder.FIRST_META_REGIONINFO, i);
074      LOG.debug(hri.getRegionNameAsString() + " replica region state from zookeeper=" + metaState);
075      if (metaServername.equals(metaState.getServerName())) {
076        metaState = null;
077        LOG.info(hri.getRegionNameAsString() +
078          " old location is same as current hbase:meta location; setting location as null...");
079      }
080      // These assigns run inline. All is blocked till they complete. Only interrupt is shutting
081      // down hosting server which calls AM#stop.
082      if (metaState != null && metaState.getServerName() != null) {
083        // Try to retain old assignment.
084        assignmentManager.assignAsync(hri, metaState.getServerName());
085      } else {
086        assignmentManager.assignAsync(hri);
087      }
088    }
089    unassignExcessMetaReplica(numReplicas);
090  }
091
092  private void unassignExcessMetaReplica(int numMetaReplicasConfigured) {
093    final ZKWatcher zooKeeper = master.getZooKeeper();
094    // unassign the unneeded replicas (for e.g., if the previous master was configured
095    // with a replication of 3 and now it is 2, we need to unassign the 1 unneeded replica)
096    try {
097      List<String> metaReplicaZnodes = zooKeeper.getMetaReplicaNodes();
098      for (String metaReplicaZnode : metaReplicaZnodes) {
099        int replicaId = zooKeeper.getZNodePaths().getMetaReplicaIdFromZnode(metaReplicaZnode);
100        if (replicaId >= numMetaReplicasConfigured) {
101          RegionState r = MetaTableLocator.getMetaRegionState(zooKeeper, replicaId);
102          LOG.info("Closing excess replica of meta region " + r.getRegion());
103          // send a close and wait for a max of 30 seconds
104          ServerManager.closeRegionSilentlyAndWait(master.getClusterConnection(),
105              r.getServerName(), r.getRegion(), 30000);
106          ZKUtil.deleteNode(zooKeeper, zooKeeper.getZNodePaths().getZNodeForReplica(replicaId));
107        }
108      }
109    } catch (Exception ex) {
110      // ignore the exception since we don't want the master to be wedged due to potential
111      // issues in the cleanup of the extra regions. We can do that cleanup via hbck or manually
112      LOG.warn("Ignoring exception " + ex);
113    }
114  }
115}