/** * 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; }
/** * 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()); } }
/** * 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); } }
/** * 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; } }