/** * Copyright 2010 The Apache Software Foundation * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.hbase.zookeeper; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.executor.RegionTransitionData; import org.apache.hadoop.hbase.executor.EventHandler.EventType; import org.apache.zookeeper.AsyncCallback; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException.Code; import org.apache.zookeeper.KeeperException.NoNodeException; import org.apache.zookeeper.KeeperException.NodeExistsException; import org.apache.zookeeper.data.Stat; /** * Utility class for doing region assignment in ZooKeeper. This class extends * stuff done in {@link ZKUtil} to cover specific assignment operations. * <p> * Contains only static methods and constants. * <p> * Used by both the Master and RegionServer. * <p> * All valid transitions outlined below: * <p> * <b>MASTER</b> * <ol> * <li> * Master creates an unassigned node as OFFLINE. * - Cluster startup and table enabling. * </li> * <li> * Master forces an existing unassigned node to OFFLINE. * - RegionServer failure. * - Allows transitions from all states to OFFLINE. * </li> * <li> * Master deletes an unassigned node that was in a OPENED state. * - Normal region transitions. Besides cluster startup, no other deletions * of unassigned nodes is allowed. * </li> * <li> * Master deletes all unassigned nodes regardless of state. * - Cluster startup before any assignment happens. * </li> * </ol> * <p> * <b>REGIONSERVER</b> * <ol> * <li> * RegionServer creates an unassigned node as CLOSING. * - All region closes will do this in response to a CLOSE RPC from Master. * - A node can never be transitioned to CLOSING, only created. * </li> * <li> * RegionServer transitions an unassigned node from CLOSING to CLOSED. * - Normal region closes. CAS operation. * </li> * <li> * RegionServer transitions an unassigned node from OFFLINE to OPENING. * - All region opens will do this in response to an OPEN RPC from the Master. * - Normal region opens. CAS operation. * </li> * <li> * RegionServer transitions an unassigned node from OPENING to OPENED. * - Normal region opens. CAS operation. * </li> * </ol> */ public class ZKAssign { private static final Log LOG = LogFactory.getLog(ZKAssign.class); /** * Gets the full path node name for the unassigned node for the specified * region. * @param zkw zk reference * @param regionName region name * @return full path node name */ public static String getNodeName(ZooKeeperWatcher zkw, String regionName) { return ZKUtil.joinZNode(zkw.assignmentZNode, regionName); } /** * Gets the region name from the full path node name of an unassigned node. * @param path full zk path * @return region name */ public static String getRegionName(ZooKeeperWatcher zkw, String path) { return path.substring(zkw.assignmentZNode.length()+1); } // Master methods /** * Creates a new unassigned node in the OFFLINE state for the specified region. * * <p>Does not transition nodes from other states. If a node already exists * for this region, a {@link NodeExistsException} 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 cluster startup and the enabling * of a table. * * @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 void createNodeOffline(ZooKeeperWatcher zkw, HRegionInfo region, String serverName) throws KeeperException, KeeperException.NodeExistsException { createNodeOffline(zkw, region, serverName, EventType.M_ZK_REGION_OFFLINE); } 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()); } } /** * 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); } } /** * 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 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; } /** * Deletes an existing unassigned node that is in the OPENED 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 normal region transitions when a region * finishes successfully opening. This is the Master acknowledging completion * of the specified regions transition. * * @param zkw zk reference * @param regionName opened region to be deleted from zk * @throws KeeperException if unexpected zookeeper exception * @throws KeeperException.NoNodeException if node does not exist */ public static boolean deleteOpenedNode(ZooKeeperWatcher zkw, String regionName) throws KeeperException, KeeperException.NoNodeException { return deleteNode(zkw, regionName, EventType.RS_ZK_REGION_OPENED); } /** * Deletes an existing unassigned node that is in the OFFLINE 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 master failover when the regions on an RS * that has died are all set to OFFLINE before being processed. * * @param zkw zk reference * @param regionName closed region to be deleted from zk * @throws KeeperException if unexpected zookeeper exception * @throws KeeperException.NoNodeException if node does not exist */ public static boolean deleteOfflineNode(ZooKeeperWatcher zkw, String regionName) throws KeeperException, KeeperException.NoNodeException { return deleteNode(zkw, regionName, EventType.M_ZK_REGION_OFFLINE); } /** * Deletes an existing unassigned node that is in the CLOSED 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 closed region to be deleted from zk * @throws KeeperException if unexpected zookeeper exception * @throws KeeperException.NoNodeException if node does not exist */ public static boolean deleteClosedNode(ZooKeeperWatcher zkw, String regionName) throws KeeperException, KeeperException.NoNodeException { return deleteNode(zkw, regionName, EventType.RS_ZK_REGION_CLOSED); } /** * Deletes an existing unassigned node that is in the CLOSING 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 region closing region to be deleted from zk * @throws KeeperException if unexpected zookeeper exception * @throws KeeperException.NoNodeException if node does not exist */ public static boolean deleteClosingNode(ZooKeeperWatcher zkw, HRegionInfo region) throws KeeperException, KeeperException.NoNodeException { String regionName = region.getEncodedName(); return deleteNode(zkw, regionName, EventType.RS_ZK_REGION_CLOSING); } /** * 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 * @throws KeeperException if unexpected zookeeper exception * @throws KeeperException.NoNodeException if node does not exist */ private static boolean deleteNode(ZooKeeperWatcher zkw, String regionName, EventType expectedState) 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) { throw KeeperException.create(Code.NONODE); } RegionTransitionData data = RegionTransitionData.fromBytes(bytes); if(!data.getEventType().equals(expectedState)) { LOG.warn(zkw.prefix("Attempting to delete unassigned " + "node in " + expectedState + " state but node is in " + data.getEventType() + " state")); 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; } } /** * 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); } // RegionServer methods /** * 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()); } } /** * Transitions an existing unassigned node for the specified region which is * currently in the CLOSING state to be in the CLOSED state. * * <p>Does not transition nodes from other states. If for some reason the * node could not be transitioned, the method returns -1. If the transition * is successful, the version of the node after transition is returned. * * <p>This method can fail and return false for three different reasons: * <ul><li>Unassigned node for this region does not exist</li> * <li>Unassigned node for this region is not in CLOSING state</li> * <li>After verifying CLOSING state, update fails because of wrong version * (someone else already transitioned the node)</li> * </ul> * * <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 transitioned to closed * @param serverName server event originates from * @return version of node after transition, -1 if unsuccessful transition * @throws KeeperException if unexpected zookeeper exception */ public static int transitionNodeClosed(ZooKeeperWatcher zkw, HRegionInfo region, String serverName, int expectedVersion) throws KeeperException { return transitionNode(zkw, region, serverName, EventType.RS_ZK_REGION_CLOSING, EventType.RS_ZK_REGION_CLOSED, expectedVersion); } /** * Transitions an existing unassigned node for the specified region which is * currently in the OFFLINE state to be in the OPENING state. * * <p>Does not transition nodes from other states. If for some reason the * node could not be transitioned, the method returns -1. If the transition * is successful, the version of the node written as OPENING is returned. * * <p>This method can fail and return -1 for three different reasons: * <ul><li>Unassigned node for this region does not exist</li> * <li>Unassigned node for this region is not in OFFLINE state</li> * <li>After verifying OFFLINE state, update fails because of wrong version * (someone else already transitioned the node)</li> * </ul> * * <p>Does not set any watches. * * <p>This method should only be used by a RegionServer when initiating an * open of a region after receiving an OPEN RPC from the Master. * * @param zkw zk reference * @param region region to be transitioned to opening * @param serverName server event originates from * @return version of node after transition, -1 if unsuccessful transition * @throws KeeperException if unexpected zookeeper exception */ public static int transitionNodeOpening(ZooKeeperWatcher zkw, HRegionInfo region, String serverName) throws KeeperException { return transitionNodeOpening(zkw, region, serverName, EventType.M_ZK_REGION_OFFLINE); } public static int transitionNodeOpening(ZooKeeperWatcher zkw, HRegionInfo region, String serverName, final EventType beginState) throws KeeperException { return transitionNode(zkw, region, serverName, beginState, EventType.RS_ZK_REGION_OPENING, -1); } /** * Retransitions an existing unassigned node for the specified region which is * currently in the OPENING state to be in the OPENING state. * * <p>Does not transition nodes from other states. If for some reason the * node could not be transitioned, the method returns -1. If the transition * is successful, the version of the node rewritten as OPENING is returned. * * <p>This method can fail and return -1 for three different reasons: * <ul><li>Unassigned node for this region does not exist</li> * <li>Unassigned node for this region is not in OPENING state</li> * <li>After verifying OPENING state, update fails because of wrong version * (someone else already transitioned the node)</li> * </ul> * * <p>Does not set any watches. * * <p>This method should only be used by a RegionServer when initiating an * open of a region after receiving an OPEN RPC from the Master. * * @param zkw zk reference * @param region region to be transitioned to opening * @param serverName server event originates from * @return version of node after transition, -1 if unsuccessful transition * @throws KeeperException if unexpected zookeeper exception */ public static int retransitionNodeOpening(ZooKeeperWatcher zkw, HRegionInfo region, String serverName, int expectedVersion) throws KeeperException { return transitionNode(zkw, region, serverName, EventType.RS_ZK_REGION_OPENING, EventType.RS_ZK_REGION_OPENING, expectedVersion); } /** * Transitions an existing unassigned node for the specified region which is * currently in the OPENING state to be in the OPENED state. * * <p>Does not transition nodes from other states. If for some reason the * node could not be transitioned, the method returns -1. If the transition * is successful, the version of the node after transition is returned. * * <p>This method can fail and return false for three different reasons: * <ul><li>Unassigned node for this region does not exist</li> * <li>Unassigned node for this region is not in OPENING state</li> * <li>After verifying OPENING state, update fails because of wrong version * (this should never actually happen since an RS only does this transition * following a transition to OPENING. if two RS are conflicting, one would * fail the original transition to OPENING and not this transition)</li> * </ul> * * <p>Does not set any watches. * * <p>This method should only be used by a RegionServer when completing the * open of a region. * * @param zkw zk reference * @param region region to be transitioned to opened * @param serverName server event originates from * @return version of node after transition, -1 if unsuccessful transition * @throws KeeperException if unexpected zookeeper exception */ public static int transitionNodeOpened(ZooKeeperWatcher zkw, HRegionInfo region, String serverName, int expectedVersion) throws KeeperException { return transitionNode(zkw, region, serverName, EventType.RS_ZK_REGION_OPENING, EventType.RS_ZK_REGION_OPENED, expectedVersion); } /** * 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); 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())); 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; } } /** * Gets the current data in the unassigned node for the specified region name * or fully-qualified path. * * <p>Returns null if the region does not currently have a node. * * <p>Sets a watch on the node if the node exists. * * @param zkw zk reference * @param pathOrRegionName fully-specified path or region name * @return data for the unassigned node * @throws KeeperException if unexpected zookeeper exception */ public static RegionTransitionData getData(ZooKeeperWatcher zkw, String pathOrRegionName) throws KeeperException { String node = pathOrRegionName.startsWith("/") ? pathOrRegionName : getNodeName(zkw, pathOrRegionName); byte [] data = ZKUtil.getDataAndWatch(zkw, node); if(data == null) { return null; } return RegionTransitionData.fromBytes(data); } /** * Gets the current data in the unassigned node for the specified region name * or fully-qualified path. * * <p>Returns null if the region does not currently have a node. * * <p>Does not set a watch. * * @param zkw zk reference * @param pathOrRegionName fully-specified path or region name * @param stat object to store node info into on getData call * @return data for the unassigned node * @throws KeeperException if unexpected zookeeper exception */ public static RegionTransitionData getDataNoWatch(ZooKeeperWatcher zkw, String pathOrRegionName, Stat stat) throws KeeperException { String node = pathOrRegionName.startsWith("/") ? pathOrRegionName : getNodeName(zkw, pathOrRegionName); byte [] data = ZKUtil.getDataNoWatch(zkw, node, stat); if(data == null) { return null; } return RegionTransitionData.fromBytes(data); } /** * Delete the assignment node regardless of its current state. * <p> * Fail silent even if the node does not exist at all. * @param watcher * @param regionInfo * @throws KeeperException */ public static void deleteNodeFailSilent(ZooKeeperWatcher watcher, HRegionInfo regionInfo) throws KeeperException { String node = getNodeName(watcher, regionInfo.getEncodedName()); ZKUtil.deleteNodeFailSilent(watcher, node); } /** * Blocks until there are no node in regions in transition. * <p> * Used in testing only. * @param zkw zk reference * @throws KeeperException * @throws InterruptedException */ public static void blockUntilNoRIT(ZooKeeperWatcher zkw) throws KeeperException, InterruptedException { while (ZKUtil.nodeHasChildren(zkw, zkw.assignmentZNode)) { List<String> znodes = ZKUtil.listChildrenAndWatchForNewChildren(zkw, zkw.assignmentZNode); if (znodes != null && !znodes.isEmpty()) { for (String znode : znodes) { LOG.debug("ZK RIT -> " + znode); } } Thread.sleep(100); } } /** * Blocks until there is at least one node in regions in transition. * <p> * Used in testing only. * @param zkw zk reference * @throws KeeperException * @throws InterruptedException */ public static void blockUntilRIT(ZooKeeperWatcher zkw) throws KeeperException, InterruptedException { while (!ZKUtil.nodeHasChildren(zkw, zkw.assignmentZNode)) { List<String> znodes = ZKUtil.listChildrenAndWatchForNewChildren(zkw, zkw.assignmentZNode); if (znodes == null || znodes.isEmpty()) { LOG.debug("No RIT in ZK"); } Thread.sleep(100); } } /** * 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; } }