/** * 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; } }
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()); } }
/** * 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 or null if node does not exist * @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); }
/** * 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); } }
/** * 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; }
/** * 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; }
/** * 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; } }