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 =
069        this.master.getMetaTableLocator().getMetaRegionLocation(this.master.getZooKeeper());
070    for (int i = 1; i < numReplicas; i++) {
071      // Get current meta state for replica from zk.
072      RegionState metaState = MetaTableLocator.getMetaRegionState(master.getZooKeeper(), i);
073      RegionInfo hri = RegionReplicaUtil.getRegionInfoForReplica(
074          RegionInfoBuilder.FIRST_META_REGIONINFO, i);
075      LOG.debug(hri.getRegionNameAsString() + " replica region state from zookeeper=" + metaState);
076      if (metaServername.equals(metaState.getServerName())) {
077        metaState = null;
078        LOG.info(hri.getRegionNameAsString() +
079          " old location is same as current hbase:meta location; setting location as null...");
080      }
081      // These assigns run inline. All is blocked till they complete. Only interrupt is shutting
082      // down hosting server which calls AM#stop.
083      if (metaState != null && metaState.getServerName() != null) {
084        // Try to retain old assignment.
085        assignmentManager.assign(hri, metaState.getServerName());
086      } else {
087        assignmentManager.assign(hri);
088      }
089    }
090    unassignExcessMetaReplica(numReplicas);
091  }
092
093  private void unassignExcessMetaReplica(int numMetaReplicasConfigured) {
094    final ZKWatcher zooKeeper = master.getZooKeeper();
095    // unassign the unneeded replicas (for e.g., if the previous master was configured
096    // with a replication of 3 and now it is 2, we need to unassign the 1 unneeded replica)
097    try {
098      List<String> metaReplicaZnodes = zooKeeper.getMetaReplicaNodes();
099      for (String metaReplicaZnode : metaReplicaZnodes) {
100        int replicaId = zooKeeper.znodePaths.getMetaReplicaIdFromZnode(metaReplicaZnode);
101        if (replicaId >= numMetaReplicasConfigured) {
102          RegionState r = MetaTableLocator.getMetaRegionState(zooKeeper, replicaId);
103          LOG.info("Closing excess replica of meta region " + r.getRegion());
104          // send a close and wait for a max of 30 seconds
105          ServerManager.closeRegionSilentlyAndWait(master.getClusterConnection(),
106              r.getServerName(), r.getRegion(), 30000);
107          ZKUtil.deleteNode(zooKeeper, zooKeeper.znodePaths.getZNodeForReplica(replicaId));
108        }
109      }
110    } catch (Exception ex) {
111      // ignore the exception since we don't want the master to be wedged due to potential
112      // issues in the cleanup of the extra regions. We can do that cleanup via hbck or manually
113      LOG.warn("Ignoring exception " + ex);
114    }
115  }
116}