/** * Creates or force updates an unassigned node to the OFFLINE state for the specified region. * * <p>Attempts to create the node but if it exists will force it to transition to and OFFLINE * state. * * <p>Sets a watcher on the unassigned region node if the method is successful. * * <p>This method should be used when assigning a region. * * @param zkw zk reference * @param region region to be created as offline * @param serverName server event originates from * @throws KeeperException if unexpected zookeeper exception * @throws KeeperException.NodeExistsException if node already exists */ public static boolean createOrForceNodeOffline( ZooKeeperWatcher zkw, HRegionInfo region, String serverName) throws KeeperException { LOG.debug( zkw.prefix( "Creating (or updating) unassigned node for " + region.getEncodedName() + " with OFFLINE state")); RegionTransitionData data = new RegionTransitionData(EventType.M_ZK_REGION_OFFLINE, region.getRegionName(), serverName); synchronized (zkw.getNodes()) { String node = getNodeName(zkw, region.getEncodedName()); zkw.sync(node); zkw.getNodes().add(node); int version = ZKUtil.checkExists(zkw, node); if (version == -1) { ZKUtil.createAndWatch(zkw, node, data.getBytes()); } else { if (!ZKUtil.setData(zkw, node, data.getBytes(), version)) { return false; } else { // We successfully forced to OFFLINE, reset watch and handle if // the state changed in between our set and the watch RegionTransitionData curData = ZKAssign.getData(zkw, region.getEncodedName()); if (curData.getEventType() != data.getEventType()) { // state changed, need to process return false; } } } } return true; }
public static void createNodeOffline( ZooKeeperWatcher zkw, HRegionInfo region, String serverName, final EventType event) throws KeeperException, KeeperException.NodeExistsException { LOG.debug( zkw.prefix( "Creating unassigned node for " + region.getEncodedName() + " in OFFLINE state")); RegionTransitionData data = new RegionTransitionData(event, region.getRegionName(), serverName); synchronized (zkw.getNodes()) { String node = getNodeName(zkw, region.getEncodedName()); zkw.getNodes().add(node); ZKUtil.createAndWatch(zkw, node, data.getBytes()); } }
/** * Forces an existing unassigned node to the OFFLINE state for the specified region. * * <p>Does not create a new node. If a node does not already exist for this region, a {@link * NoNodeException} will be thrown. * * <p>Sets a watcher on the unassigned region node if the method is successful. * * <p>This method should only be used during recovery of regionserver failure. * * @param zkw zk reference * @param region region to be forced as offline * @param serverName server event originates from * @throws KeeperException if unexpected zookeeper exception * @throws KeeperException.NoNodeException if node does not exist */ public static void forceNodeOffline(ZooKeeperWatcher zkw, HRegionInfo region, String serverName) throws KeeperException, KeeperException.NoNodeException { LOG.debug( zkw.prefix( "Forcing existing unassigned node for " + region.getEncodedName() + " to OFFLINE state")); RegionTransitionData data = new RegionTransitionData(EventType.M_ZK_REGION_OFFLINE, region.getRegionName(), serverName); synchronized (zkw.getNodes()) { String node = getNodeName(zkw, region.getEncodedName()); zkw.getNodes().add(node); ZKUtil.setData(zkw, node, data.getBytes()); } }
/** * Creates a new unassigned node in the CLOSING state for the specified region. * * <p>Does not transition nodes from any states. If a node already exists for this region, a * {@link NodeExistsException} will be thrown. * * <p>If creation is successful, returns the version number of the CLOSING node created. * * <p>Does not set any watches. * * <p>This method should only be used by a RegionServer when initiating a close of a region after * receiving a CLOSE RPC from the Master. * * @param zkw zk reference * @param region region to be created as closing * @param serverName server event originates from * @return version of node after transition, -1 if unsuccessful transition * @throws KeeperException if unexpected zookeeper exception * @throws KeeperException.NodeExistsException if node already exists */ public static int createNodeClosing(ZooKeeperWatcher zkw, HRegionInfo region, String serverName) throws KeeperException, KeeperException.NodeExistsException { LOG.debug( zkw.prefix( "Creating unassigned node for " + region.getEncodedName() + " in a CLOSING state")); RegionTransitionData data = new RegionTransitionData( EventType.RS_ZK_REGION_CLOSING, region.getRegionName(), serverName); synchronized (zkw.getNodes()) { String node = getNodeName(zkw, region.getEncodedName()); zkw.getNodes().add(node); return ZKUtil.createAndWatch(zkw, node, data.getBytes()); } }
/** * Deletes an existing unassigned node that is in the specified state for the specified region. * * <p>If a node does not already exist for this region, a {@link NoNodeException} will be thrown. * * <p>No watcher is set whether this succeeds or not. * * <p>Returns false if the node was not in the proper state but did exist. * * <p>This method is used during table disables when a region finishes successfully closing. This * is the Master acknowledging completion of the specified regions transition to being closed. * * @param zkw zk reference * @param regionName region to be deleted from zk * @param expectedState state region must be in for delete to complete * @param expectedVersion of the znode that is to be deleted. If expectedVersion need not be * compared while deleting the znode pass -1 * @throws KeeperException if unexpected zookeeper exception * @throws KeeperException.NoNodeException if node does not exist */ public static boolean deleteNode( ZooKeeperWatcher zkw, String regionName, EventType expectedState, int expectedVersion) throws KeeperException, KeeperException.NoNodeException { LOG.debug( zkw.prefix( "Deleting existing unassigned " + "node for " + regionName + " that is in expected state " + expectedState)); String node = getNodeName(zkw, regionName); zkw.sync(node); Stat stat = new Stat(); byte[] bytes = ZKUtil.getDataNoWatch(zkw, node, stat); if (bytes == null) { // If it came back null, node does not exist. throw KeeperException.create(Code.NONODE); } RegionTransitionData data = RegionTransitionData.fromBytes(bytes); if (!data.getEventType().equals(expectedState)) { LOG.warn( zkw.prefix( "Attempting to delete unassigned " + "node " + regionName + " in " + expectedState + " state but node is in " + data.getEventType() + " state")); return false; } if (expectedVersion != -1 && stat.getVersion() != expectedVersion) { LOG.warn( "The node we are trying to delete is not the expected one. " + "Got a version mismatch"); return false; } synchronized (zkw.getNodes()) { // TODO: Does this go here or only if we successfully delete node? zkw.getNodes().remove(node); if (!ZKUtil.deleteNode(zkw, node, stat.getVersion())) { LOG.warn( zkw.prefix( "Attempting to delete " + "unassigned node in " + expectedState + " state but " + "after verifying it was in OPENED state, we got a version mismatch")); return false; } LOG.debug( zkw.prefix( "Successfully deleted unassigned node for region " + regionName + " in expected state " + expectedState)); return true; } }
/** * Creates an unassigned node in the OFFLINE state for the specified region. * * <p>Runs asynchronously. Depends on no pre-existing znode. * * <p>Sets a watcher on the unassigned region node. * * @param zkw zk reference * @param region region to be created as offline * @param serverName server event originates from * @param cb * @param ctx * @throws KeeperException if unexpected zookeeper exception * @throws KeeperException.NodeExistsException if node already exists */ public static void asyncCreateNodeOffline( ZooKeeperWatcher zkw, HRegionInfo region, String serverName, final AsyncCallback.StringCallback cb, final Object ctx) throws KeeperException { LOG.debug( zkw.prefix( "Async create of unassigned node for " + region.getEncodedName() + " with OFFLINE state")); RegionTransitionData data = new RegionTransitionData(EventType.M_ZK_REGION_OFFLINE, region.getRegionName(), serverName); synchronized (zkw.getNodes()) { String node = getNodeName(zkw, region.getEncodedName()); zkw.getNodes().add(node); ZKUtil.asyncCreate(zkw, node, data.getBytes(), cb, ctx); } }
public void deleteMetaLocation(ZooKeeperWatcher zookeeper, int replicaId) throws KeeperException { if (replicaId == HRegionInfo.DEFAULT_REPLICA_ID) { LOG.info("Deleting hbase:meta region location in ZooKeeper"); } else { LOG.info("Deleting hbase:meta for " + replicaId + " region location in ZooKeeper"); } try { // Just delete the node. Don't need any watches. ZKUtil.deleteNode(zookeeper, zookeeper.getZNodeForReplica(replicaId)); } catch (KeeperException.NoNodeException nne) { // Has already been deleted } }
/** * Sets the location of <code>hbase:meta</code> in ZooKeeper to the specified server address. * * @param zookeeper * @param serverName * @param replicaId * @param state * @throws KeeperException */ public static void setMetaLocation( ZooKeeperWatcher zookeeper, ServerName serverName, int replicaId, RegionState.State state) throws KeeperException { LOG.info("Setting hbase:meta region location in ZooKeeper as " + serverName); // Make the MetaRegionServer pb and then get its bytes and save this as // the znode content. MetaRegionServer pbrsr = MetaRegionServer.newBuilder() .setServer(ProtobufUtil.toServerName(serverName)) .setRpcVersion(HConstants.RPC_CURRENT_VERSION) .setState(state.convert()) .build(); byte[] data = ProtobufUtil.prependPBMagic(pbrsr.toByteArray()); try { ZKUtil.setData(zookeeper, zookeeper.getZNodeForReplica(replicaId), data); } catch (KeeperException.NoNodeException nne) { if (replicaId == HRegionInfo.DEFAULT_REPLICA_ID) { LOG.debug("META region location doesn't exist, create it"); } else { LOG.debug("META region location doesn't exist for replicaId " + replicaId + ", create it"); } ZKUtil.createAndWatch(zookeeper, zookeeper.getZNodeForReplica(replicaId), data); } }
/** * Wait until the primary meta region is available. Get the secondary locations as well but don't * block for those. * * @param zkw * @param timeout * @param conf * @return ServerName or null if we timed out. * @throws InterruptedException */ public List<ServerName> blockUntilAvailable( final ZooKeeperWatcher zkw, final long timeout, Configuration conf) throws InterruptedException { int numReplicasConfigured = 1; try { List<String> metaReplicaNodes = zkw.getMetaReplicaNodes(); numReplicasConfigured = metaReplicaNodes.size(); } catch (KeeperException e) { LOG.warn("Got ZK exception " + e); } List<ServerName> servers = new ArrayList<ServerName>(numReplicasConfigured); ServerName server = blockUntilAvailable(zkw, timeout); if (server == null) return null; servers.add(server); for (int replicaId = 1; replicaId < numReplicasConfigured; replicaId++) { // return all replica locations for the meta servers.add(getMetaRegionLocation(zkw, replicaId)); } return servers; }
/** * Verifies that the specified region is in the specified state in ZooKeeper. * * <p>Returns true if region is in transition and in the specified state in ZooKeeper. Returns * false if the region does not exist in ZK or is in a different state. * * <p>Method synchronizes() with ZK so will yield an up-to-date result but is a slow read. * * @param zkw * @param region * @param expectedState * @return true if region exists and is in expected state */ public static boolean verifyRegionState( ZooKeeperWatcher zkw, HRegionInfo region, EventType expectedState) throws KeeperException { String encoded = region.getEncodedName(); String node = getNodeName(zkw, encoded); zkw.sync(node); // Read existing data of the node byte[] existingBytes = null; try { existingBytes = ZKUtil.getDataAndWatch(zkw, node); } catch (KeeperException.NoNodeException nne) { return false; } catch (KeeperException e) { throw e; } if (existingBytes == null) return false; RegionTransitionData existingData = RegionTransitionData.fromBytes(existingBytes); if (existingData.getEventType() == expectedState) { return true; } return false; }
/** * Load the meta region state from the meta server ZNode. * * @param zkw * @param replicaId * @return regionstate * @throws KeeperException */ public static RegionState getMetaRegionState(ZooKeeperWatcher zkw, int replicaId) throws KeeperException { RegionState.State state = RegionState.State.OPEN; ServerName serverName = null; try { byte[] data = ZKUtil.getData(zkw, zkw.getZNodeForReplica(replicaId)); if (data != null && data.length > 0 && ProtobufUtil.isPBMagicPrefix(data)) { try { int prefixLen = ProtobufUtil.lengthOfPBMagic(); ZooKeeperProtos.MetaRegionServer rl = ZooKeeperProtos.MetaRegionServer.PARSER.parseFrom( data, prefixLen, data.length - prefixLen); if (rl.hasState()) { state = RegionState.State.convert(rl.getState()); } HBaseProtos.ServerName sn = rl.getServer(); serverName = ServerName.valueOf(sn.getHostName(), sn.getPort(), sn.getStartCode()); } catch (InvalidProtocolBufferException e) { throw new DeserializationException("Unable to parse meta region location"); } } else { // old style of meta region location? serverName = ServerName.parseFrom(data); } } catch (DeserializationException e) { throw ZKUtil.convert(e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } if (serverName == null) { state = RegionState.State.OFFLINE; } return new RegionState( RegionReplicaUtil.getRegionInfoForReplica(HRegionInfo.FIRST_META_REGIONINFO, replicaId), state, serverName); }
/** * Private method that actually performs unassigned node transitions. * * <p>Attempts to transition the unassigned node for the specified region from the expected state * to the state in the specified transition data. * * <p>Method first reads existing data and verifies it is in the expected state. If the node does * not exist or the node is not in the expected state, the method returns -1. If the transition is * successful, the version number of the node following the transition is returned. * * <p>If the read state is what is expected, it attempts to write the new state and data into the * node. When doing this, it includes the expected version (determined when the existing state was * verified) to ensure that only one transition is successful. If there is a version mismatch, the * method returns -1. * * <p>If the write is successful, no watch is set and the method returns true. * * @param zkw zk reference * @param region region to be transitioned to opened * @param serverName server event originates from * @param endState state to transition node to if all checks pass * @param beginState state the node must currently be in to do transition * @param expectedVersion expected version of data before modification, or -1 * @return version of node after transition, -1 if unsuccessful transition * @throws KeeperException if unexpected zookeeper exception */ public static int transitionNode( ZooKeeperWatcher zkw, HRegionInfo region, String serverName, EventType beginState, EventType endState, int expectedVersion) throws KeeperException { String encoded = region.getEncodedName(); if (LOG.isDebugEnabled()) { LOG.debug( zkw.prefix( "Attempting to transition node " + HRegionInfo.prettyPrint(encoded) + " from " + beginState.toString() + " to " + endState.toString())); } String node = getNodeName(zkw, encoded); zkw.sync(node); // Read existing data of the node Stat stat = new Stat(); byte[] existingBytes = ZKUtil.getDataNoWatch(zkw, node, stat); if (existingBytes == null) { // Node no longer exists. Return -1. It means unsuccessful transition. return -1; } RegionTransitionData existingData = RegionTransitionData.fromBytes(existingBytes); // Verify it is the expected version if (expectedVersion != -1 && stat.getVersion() != expectedVersion) { LOG.warn( zkw.prefix( "Attempt to transition the " + "unassigned node for " + encoded + " from " + beginState + " to " + endState + " failed, " + "the node existed but was version " + stat.getVersion() + " not the expected version " + expectedVersion)); return -1; } // Verify it is in expected state if (!existingData.getEventType().equals(beginState)) { LOG.warn( zkw.prefix( "Attempt to transition the " + "unassigned node for " + encoded + " from " + beginState + " to " + endState + " failed, " + "the node existed but was in the state " + existingData.getEventType() + " set by the server " + existingData.getServerName())); return -1; } // Write new data, ensuring data has not changed since we last read it try { RegionTransitionData data = new RegionTransitionData(endState, region.getRegionName(), serverName); if (!ZKUtil.setData(zkw, node, data.getBytes(), stat.getVersion())) { LOG.warn( zkw.prefix( "Attempt to transition the " + "unassigned node for " + encoded + " from " + beginState + " to " + endState + " failed, " + "the node existed and was in the expected state but then when " + "setting data we got a version mismatch")); return -1; } if (LOG.isDebugEnabled()) { LOG.debug( zkw.prefix( "Successfully transitioned node " + encoded + " from " + beginState + " to " + endState)); } return stat.getVersion() + 1; } catch (KeeperException.NoNodeException nne) { LOG.warn( zkw.prefix( "Attempt to transition the " + "unassigned node for " + encoded + " from " + beginState + " to " + endState + " failed, " + "the node existed and was in the expected state but then when " + "setting data it no longer existed")); return -1; } }
/** * Deletes all unassigned nodes regardless of their state. * * <p>No watchers are set. * * <p>This method is used by the Master during cluster startup to clear out any existing state * from other cluster runs. * * @param zkw zk reference * @throws KeeperException if unexpected zookeeper exception */ public static void deleteAllNodes(ZooKeeperWatcher zkw) throws KeeperException { LOG.debug(zkw.prefix("Deleting any existing unassigned nodes")); ZKUtil.deleteChildrenRecursively(zkw, zkw.assignmentZNode); }