/** * Creates a new ephemeral node in the PENDING_SPLIT state for the specified region. Create it * ephemeral in case regionserver dies mid-split. * <p> * Does not transition nodes from other states. If a node already exists for this region, an * Exception will be thrown. * @param parent region to be created as offline * @param serverName server event originates from * @param hri_a daughter region * @param hri_b daughter region * @throws IOException */ @Override public void startSplitTransaction(HRegion parent, ServerName serverName, HRegionInfo hri_a, HRegionInfo hri_b) throws IOException { HRegionInfo region = parent.getRegionInfo(); try { LOG.debug(watcher.prefix("Creating ephemeral node for " + region.getEncodedName() + " in PENDING_SPLIT state")); byte[] payload = HRegionInfo.toDelimitedByteArray(hri_a, hri_b); RegionTransition rt = RegionTransition.createRegionTransition(RS_ZK_REQUEST_REGION_SPLIT, region.getRegionName(), serverName, payload); String node = ZKAssign.getNodeName(watcher, region.getEncodedName()); if (!ZKUtil.createEphemeralNodeAndWatch(watcher, node, rt.toByteArray())) { throw new IOException("Failed create of ephemeral " + node); } } catch (KeeperException e) { throw new IOException("Failed creating PENDING_SPLIT znode on " + parent.getRegionInfo().getRegionNameAsString(), e); } }
/** * Creates a new ephemeral node in the PENDING_MERGE state for the merged region. * Create it ephemeral in case regionserver dies mid-merge. * * <p> * Does not transition nodes from other states. If a node already exists for * this region, a {@link org.apache.zookeeper.KeeperException.NodeExistsException} will be thrown. * * @param region region to be created as offline * @param serverName server event originates from * @throws IOException */ @Override public void startRegionMergeTransaction(final HRegionInfo region, final ServerName serverName, final HRegionInfo a, final HRegionInfo b) throws IOException { LOG.debug(watcher.prefix("Creating ephemeral node for " + region.getEncodedName() + " in PENDING_MERGE state")); byte[] payload = HRegionInfo.toDelimitedByteArray(region, a, b); RegionTransition rt = RegionTransition.createRegionTransition(RS_ZK_REQUEST_REGION_MERGE, region.getRegionName(), serverName, payload); String node = ZKAssign.getNodeName(watcher, region.getEncodedName()); try { if (!ZKUtil.createEphemeralNodeAndWatch(watcher, node, rt.toByteArray())) { throw new IOException("Failed create of ephemeral " + node); } } catch (KeeperException e) { throw new IOException(e); } }
/** * Update a region state. It will be put in transition if not already there. * * If we can't find the region info based on the region name in * the transition, log a warning and return null. */ public RegionState updateRegionState( final RegionTransition transition, final State state) { byte [] regionName = transition.getRegionName(); HRegionInfo regionInfo = getRegionInfo(regionName); if (regionInfo == null) { String prettyRegionName = HRegionInfo.prettyPrint( HRegionInfo.encodeRegionName(regionName)); LOG.warn("Failed to find region " + prettyRegionName + " in updating its state to " + state + " based on region transition " + transition); return null; } return updateRegionState(regionInfo, state, transition.getServerName()); }
/** * 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 * @throws DeserializationException */ static boolean verifyRegionState(ZooKeeperWatcher zkw, HRegionInfo region, EventType expectedState) throws KeeperException, DeserializationException { String encoded = region.getEncodedName(); String node = ZKAssign.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; RegionTransition rt = RegionTransition.parseFrom(existingBytes); return rt.getEventType().equals(expectedState); }
private void OpenRegion(Server server, RegionServerServices rss, HTableDescriptor htd, HRegionInfo hri, OpenRegionCoordination coordination) throws IOException, NodeExistsException, KeeperException, DeserializationException { // Create it OFFLINE node, which is what Master set before sending OPEN RPC ZKAssign.createNodeOffline(server.getZooKeeper(), hri, server.getServerName()); OpenRegionCoordination.OpenRegionDetails ord = coordination.getDetailsForNonCoordinatedOpening(); OpenRegionHandler openHandler = new OpenRegionHandler(server, rss, hri, htd, -1, coordination, ord); rss.getRegionsInTransitionInRS().put(hri.getEncodedNameAsBytes(), Boolean.TRUE); openHandler.process(); // This parse is not used? RegionTransition.parseFrom(ZKAssign.getData(server.getZooKeeper(), hri.getEncodedName())); // delete the node, which is what Master do after the region is opened ZKAssign.deleteNode(server.getZooKeeper(), hri.getEncodedName(), EventType.RS_ZK_REGION_OPENED, server.getServerName()); }
/** * Creates a new ephemeral node in the PENDING_SPLIT state for the specified region. Create it * ephemeral in case regionserver dies mid-split. * <p> * Does not transition nodes from other states. If a node already exists for this region, an * Exception will be thrown. * @param parent region to be created as offline * @param serverName server event originates from * @param hri_a daughter region * @param hri_b daughter region * @throws IOException */ @Override public void startSplitTransaction(HRegion parent, ServerName serverName, HRegionInfo hri_a, HRegionInfo hri_b) throws IOException { HRegionInfo region = parent.getRegionInfo(); try { LOG.debug(watcher.prefix("Creating ephemeral node for " + region.getEncodedName() + " in PENDING_SPLIT state")); byte[] payload = HRegionInfo.toDelimitedByteArray(hri_a, hri_b); RegionTransition rt = RegionTransition.createRegionTransition(RS_ZK_REQUEST_REGION_SPLIT, region.getRegionName(), serverName, payload); String node = ZKAssign.getNodeName(watcher, region.getEncodedName()); if (!ZKUtil.createEphemeralNodeAndWatch(watcher, node, rt.toByteArray())) { throw new IOException("Failed create of ephemeral " + node); } } catch (KeeperException e) { throw new IOException("Failed creating PENDING_SPLIT znode on " + parent.getRegionNameAsString(), e); } }
/** * Creates a new ephemeral node in the SPLITTING state for the specified region. * Create it ephemeral in case regionserver dies mid-split. * * <p>Does not transition nodes from other states. If a node already exists * for this region, a {@link NodeExistsException} will be thrown. * * @param zkw zk reference * @param region region to be created as offline * @param serverName server event originates from * @return Version of znode created. * @throws KeeperException * @throws IOException */ // Copied from SplitTransaction rather than open the method over there in // the regionserver package. private static int createNodeSplitting(final ZooKeeperWatcher zkw, final HRegionInfo region, final ServerName serverName) throws KeeperException, IOException { RegionTransition rt = RegionTransition.createRegionTransition(EventType.RS_ZK_REGION_SPLITTING, region.getRegionName(), serverName); String node = ZKAssign.getNodeName(zkw, region.getEncodedName()); if (!ZKUtil.createEphemeralNodeAndWatch(zkw, node, rt.toByteArray())) { throw new IOException("Failed create of ephemeral " + node); } // Transition node from SPLITTING to SPLITTING and pick up version so we // can be sure this znode is ours; version is needed deleting. return transitionNodeSplitting(zkw, region, serverName, -1); }
private void OpenRegion(Server server, RegionServerServices rss, HTableDescriptor htd, HRegionInfo hri, OpenRegionCoordination coordination) throws IOException, NodeExistsException, KeeperException, DeserializationException { // Create it OFFLINE node, which is what Master set before sending OPEN RPC ZKAssign.createNodeOffline(server.getZooKeeper(), hri, server.getServerName()); OpenRegionCoordination.OpenRegionDetails ord = coordination.getDetailsForNonCoordinatedOpening(); OpenRegionHandler openHandler = new OpenRegionHandler(server, rss, hri, htd, coordination, ord); rss.getRegionsInTransitionInRS().put(hri.getEncodedNameAsBytes(), Boolean.TRUE); openHandler.process(); // This parse is not used? RegionTransition.parseFrom(ZKAssign.getData(server.getZooKeeper(), hri.getEncodedName())); // delete the node, which is what Master do after the region is opened ZKAssign.deleteNode(server.getZooKeeper(), hri.getEncodedName(), EventType.RS_ZK_REGION_OPENED, server.getServerName()); }
/** * Update a region state. It will be put in transition if not already there. * * If we can't find the region info based on the region name in * the transition, log a warning and return null. */ public synchronized RegionState updateRegionState( final RegionTransition transition, final State state) { byte [] regionName = transition.getRegionName(); HRegionInfo regionInfo = getRegionInfo(regionName); if (regionInfo == null) { String prettyRegionName = HRegionInfo.prettyPrint( HRegionInfo.encodeRegionName(regionName)); LOG.warn("Failed to find region " + prettyRegionName + " in updating its state to " + state + " based on region transition " + transition); return null; } return updateRegionState(regionInfo, state, transition.getServerName()); }
/** * Test the scenario when the master is in failover and trying to process a * region which is in Opening state on a dead RS. Master should immediately * assign the region and not wait for Timeout Monitor.(Hbase-5882). */ @Test(timeout = 60000) public void testRegionInOpeningStateOnDeadRSWhileMasterFailover() throws IOException, KeeperException, ServiceException, InterruptedException { AssignmentManagerWithExtrasForTesting am = setUpMockedAssignmentManager( this.server, this.serverManager); ZKAssign.createNodeOffline(this.watcher, REGIONINFO, SERVERNAME_A); int version = ZKAssign.getVersion(this.watcher, REGIONINFO); ZKAssign.transitionNode(this.watcher, REGIONINFO, SERVERNAME_A, EventType.M_ZK_REGION_OFFLINE, EventType.RS_ZK_REGION_OPENING, version); RegionTransition rt = RegionTransition.createRegionTransition(EventType.RS_ZK_REGION_OPENING, REGIONINFO.getRegionName(), SERVERNAME_A, HConstants.EMPTY_BYTE_ARRAY); version = ZKAssign.getVersion(this.watcher, REGIONINFO); Mockito.when(this.serverManager.isServerOnline(SERVERNAME_A)).thenReturn(false); am.getRegionStates().logSplit(SERVERNAME_A); // Assume log splitting is done am.getRegionStates().createRegionState(REGIONINFO); am.gate.set(false); am.processRegionsInTransition(rt, REGIONINFO, version); // Waiting for the assignment to get completed. while (!am.gate.get()) { Thread.sleep(10); } assertTrue("The region should be assigned immediately.", null != am.regionPlans.get(REGIONINFO .getEncodedName())); }
/** * Update a region state. If it is not splitting, * it will be put in transition if not already there. * * If we can't find the region info based on the region name in * the transition, log a warning and return null. */ public synchronized RegionState updateRegionState( final RegionTransition transition, final State state) { byte[] regionName = transition.getRegionName(); HRegionInfo regionInfo = getRegionInfo(regionName); if (regionInfo == null) { String prettyRegionName = HRegionInfo.prettyPrint( HRegionInfo.encodeRegionName(regionName)); LOG.warn("Failed to find region " + prettyRegionName + " in updating its state to " + state + " based on region transition " + transition); return null; } return updateRegionState(regionInfo, state, transition.getServerName()); }
/** * @param path * @return True if znode is in SPLIT or SPLITTING state. * @throws KeeperException Can happen if the znode went away in meantime. * @throws DeserializationException */ private boolean isSplitOrSplitting(final String path) throws KeeperException, DeserializationException { boolean result = false; // This may fail if the SPLIT or SPLITTING znode gets cleaned up before we // can get data from it. byte [] data = ZKAssign.getData(watcher, path); if (data == null) return false; RegionTransition rt = RegionTransition.parseFrom(data); switch (rt.getEventType()) { case RS_ZK_REGION_SPLIT: case RS_ZK_REGION_SPLITTING: result = true; break; default: break; } return result; }
/** * Test the scenario when the master is in failover and trying to process a * region which is in Opening state on a dead RS. Master should immediately * assign the region and not wait for Timeout Monitor.(Hbase-5882). */ @Test(timeout = 5000) public void testRegionInOpeningStateOnDeadRSWhileMasterFailover() throws IOException, KeeperException, ServiceException, InterruptedException { AssignmentManagerWithExtrasForTesting am = setUpMockedAssignmentManager( this.server, this.serverManager); ZKAssign.createNodeOffline(this.watcher, REGIONINFO, SERVERNAME_A); int version = ZKAssign.getVersion(this.watcher, REGIONINFO); ZKAssign.transitionNode(this.watcher, REGIONINFO, SERVERNAME_A, EventType.M_ZK_REGION_OFFLINE, EventType.RS_ZK_REGION_OPENING, version); RegionTransition rt = RegionTransition.createRegionTransition(EventType.RS_ZK_REGION_OPENING, REGIONINFO.getRegionName(), SERVERNAME_A, HConstants.EMPTY_BYTE_ARRAY); version = ZKAssign.getVersion(this.watcher, REGIONINFO); Mockito.when(this.serverManager.isServerOnline(SERVERNAME_A)).thenReturn(false); am.getRegionStates().createRegionState(REGIONINFO); am.gate.set(false); am.processRegionsInTransition(rt, REGIONINFO, version); // Waiting for the assignment to get completed. while (!am.gate.get()) { Thread.sleep(10); } assertTrue("The region should be assigned immediately.", null != am.regionPlans.get(REGIONINFO .getEncodedName())); }
/** * Transition a region state to OPEN from OPENING/PENDING_OPEN */ public synchronized RegionState transitionOpenFromPendingOpenOrOpeningOnServer( final RegionTransition transition, final RegionState fromState, final ServerName sn) { if(fromState.isPendingOpenOrOpeningOnServer(sn)){ return updateRegionState(transition, State.OPEN); } return null; }
/** * Handle a ZK unassigned node transition triggered by HBCK repair tool. * <p> * This is handled in a separate code path because it breaks the normal rules. * @param rt */ @SuppressWarnings("deprecation") private void handleHBCK(RegionTransition rt) { String encodedName = HRegionInfo.encodeRegionName(rt.getRegionName()); LOG.info("Handling HBCK triggered transition=" + rt.getEventType() + ", server=" + rt.getServerName() + ", region=" + HRegionInfo.prettyPrint(encodedName)); RegionState regionState = regionStates.getRegionTransitionState(encodedName); switch (rt.getEventType()) { case M_ZK_REGION_OFFLINE: HRegionInfo regionInfo; if (regionState != null) { regionInfo = regionState.getRegion(); } else { try { byte [] name = rt.getRegionName(); Pair<HRegionInfo, ServerName> p = MetaTableAccessor.getRegion( this.server.getConnection(), name); regionInfo = p.getFirst(); } catch (IOException e) { LOG.info("Exception reading hbase:meta doing HBCK repair operation", e); return; } } LOG.info("HBCK repair is triggering assignment of region=" + regionInfo.getRegionNameAsString()); // trigger assign, node is already in OFFLINE so don't need to update ZK assign(regionInfo, false); break; default: LOG.warn("Received unexpected region state from HBCK: " + rt.toString()); break; } }
private void processAlreadyOpenedRegion(HRegionInfo region, ServerName sn) { // Remove region from in-memory transition and unassigned node from ZK // While trying to enable the table the regions of the table were // already enabled. LOG.debug("ALREADY_OPENED " + region.getRegionNameAsString() + " to " + sn); String encodedName = region.getEncodedName(); //If use ZkForAssignment, region already Opened event should not be handled, //leave it to zk event. See HBase-14407. if(useZKForAssignment){ String node = ZKAssign.getNodeName(watcher, encodedName); Stat stat = new Stat(); try { byte[] existingBytes = ZKUtil.getDataNoWatch(watcher, node, stat); if(existingBytes!=null){ RegionTransition rt= RegionTransition.parseFrom(existingBytes); EventType et = rt.getEventType(); if (et.equals(EventType.RS_ZK_REGION_OPENED)) { LOG.debug("ALREADY_OPENED " + region.getRegionNameAsString() + " and node in "+et+" state"); return; } } } catch (KeeperException ke) { LOG.warn("Unexpected ZK exception getData " + node + " node for the region " + encodedName, ke); } catch (DeserializationException e) { LOG.warn("Get RegionTransition from zk deserialization failed! ", e); } deleteNodeInStates(encodedName, "offline", sn, EventType.M_ZK_REGION_OFFLINE); } regionStates.regionOnline(region, sn); }
/** * @param path * @return True if znode is in SPLIT or SPLITTING or MERGED or MERGING state. * @throws KeeperException Can happen if the znode went away in meantime. * @throws DeserializationException */ private boolean isSplitOrSplittingOrMergedOrMerging(final String path) throws KeeperException, DeserializationException { boolean result = false; // This may fail if the SPLIT or SPLITTING or MERGED or MERGING znode gets // cleaned up before we can get data from it. byte [] data = ZKAssign.getData(watcher, path); if (data == null) { LOG.info("Node " + path + " is gone"); return false; } RegionTransition rt = RegionTransition.parseFrom(data); switch (rt.getEventType()) { case RS_ZK_REQUEST_REGION_SPLIT: case RS_ZK_REGION_SPLIT: case RS_ZK_REGION_SPLITTING: case RS_ZK_REQUEST_REGION_MERGE: case RS_ZK_REGION_MERGED: case RS_ZK_REGION_MERGING: result = true; break; default: LOG.info("Node " + path + " is in " + rt.getEventType()); break; } return result; }
/** * Test if close region can handle ZK closing node version mismatch * @throws IOException * @throws NodeExistsException * @throws KeeperException * @throws DeserializationException */ @Test public void testZKClosingNodeVersionMismatch() throws IOException, NodeExistsException, KeeperException, DeserializationException { final Server server = new MockServer(HTU); final RegionServerServices rss = HTU.createMockRegionServerService(); HTableDescriptor htd = TEST_HTD; final HRegionInfo hri = TEST_HRI; ZkCoordinatedStateManager coordinationProvider = new ZkCoordinatedStateManager(); coordinationProvider.initialize(server); coordinationProvider.start(); // open a region first so that it can be closed later OpenRegion(server, rss, htd, hri, coordinationProvider.getOpenRegionCoordination()); // close the region // Create it CLOSING, which is what Master set before sending CLOSE RPC int versionOfClosingNode = ZKAssign.createNodeClosing(server.getZooKeeper(), hri, server.getServerName()); // The CloseRegionHandler will validate the expected version // Given it is set to invalid versionOfClosingNode+1, // CloseRegionHandler should be M_ZK_REGION_CLOSING ZkCloseRegionCoordination.ZkCloseRegionDetails zkCrd = new ZkCloseRegionCoordination.ZkCloseRegionDetails(); zkCrd.setPublishStatusInZk(true); zkCrd.setExpectedVersion(versionOfClosingNode+1); CloseRegionHandler handler = new CloseRegionHandler(server, rss, hri, false, coordinationProvider.getCloseRegionCoordination(), zkCrd); handler.process(); // Handler should remain in M_ZK_REGION_CLOSING RegionTransition rt = RegionTransition.parseFrom(ZKAssign.getData(server.getZooKeeper(), hri.getEncodedName())); assertTrue(rt.getEventType().equals(EventType.M_ZK_REGION_CLOSING )); }
/** * Test if the region can be closed properly * @throws IOException * @throws NodeExistsException * @throws KeeperException * @throws org.apache.hadoop.hbase.exceptions.DeserializationException */ @Test public void testCloseRegion() throws IOException, NodeExistsException, KeeperException, DeserializationException { final Server server = new MockServer(HTU); final RegionServerServices rss = HTU.createMockRegionServerService(); HTableDescriptor htd = TEST_HTD; HRegionInfo hri = TEST_HRI; ZkCoordinatedStateManager coordinationProvider = new ZkCoordinatedStateManager(); coordinationProvider.initialize(server); coordinationProvider.start(); // open a region first so that it can be closed later OpenRegion(server, rss, htd, hri, coordinationProvider.getOpenRegionCoordination()); // close the region // Create it CLOSING, which is what Master set before sending CLOSE RPC int versionOfClosingNode = ZKAssign.createNodeClosing(server.getZooKeeper(), hri, server.getServerName()); // The CloseRegionHandler will validate the expected version // Given it is set to correct versionOfClosingNode, // CloseRegionHandlerit should be RS_ZK_REGION_CLOSED ZkCloseRegionCoordination.ZkCloseRegionDetails zkCrd = new ZkCloseRegionCoordination.ZkCloseRegionDetails(); zkCrd.setPublishStatusInZk(true); zkCrd.setExpectedVersion(versionOfClosingNode); CloseRegionHandler handler = new CloseRegionHandler(server, rss, hri, false, coordinationProvider.getCloseRegionCoordination(), zkCrd); handler.process(); // Handler should have transitioned it to RS_ZK_REGION_CLOSED RegionTransition rt = RegionTransition.parseFrom( ZKAssign.getData(server.getZooKeeper(), hri.getEncodedName())); assertTrue(rt.getEventType().equals(EventType.RS_ZK_REGION_CLOSED)); }
public static void createNodeOffline(ZooKeeperWatcher zkw, HRegionInfo region, ServerName serverName, final EventType event) throws KeeperException, KeeperException.NodeExistsException { LOG.debug(zkw.prefix("Creating unassigned node " + region.getEncodedName() + " in OFFLINE state")); RegionTransition rt = RegionTransition.createRegionTransition(event, region.getRegionName(), serverName); String node = getNodeName(zkw, region.getEncodedName()); ZKUtil.createAndWatch(zkw, node, rt.toByteArray()); }
/** * * @param zkw zk reference * @param region region to be closed * @param expectedVersion expected version of the znode * @return true if the znode exists, has the right version and the right state. False otherwise. * @throws KeeperException */ public static boolean checkClosingState(ZooKeeperWatcher zkw, HRegionInfo region, int expectedVersion) throws KeeperException { final String encoded = getNodeName(zkw, region.getEncodedName()); zkw.sync(encoded); // Read existing data of the node Stat stat = new Stat(); byte[] existingBytes = ZKUtil.getDataNoWatch(zkw, encoded, stat); if (existingBytes == null) { LOG.warn(zkw.prefix("Attempt to check the " + "closing node for " + encoded + ". The node does not exist")); return false; } if (expectedVersion != -1 && stat.getVersion() != expectedVersion) { LOG.warn(zkw.prefix("Attempt to check the " + "closing node for " + encoded + ". The node existed but was version " + stat.getVersion() + " not the expected version " + expectedVersion)); return false; } RegionTransition rt = getRegionTransition(existingBytes); if (!EventType.M_ZK_REGION_CLOSING.equals(rt.getEventType())) { LOG.warn(zkw.prefix("Attempt to check the " + "closing node for " + encoded + ". The node existed but was in an unexpected state: " + rt.getEventType())); return false; } return true; }
private static RegionTransition getRegionTransition(final byte [] bytes) throws KeeperException { try { return RegionTransition.parseFrom(bytes); } catch (DeserializationException e) { // Convert to a zk exception for now. Otherwise have to change API throw ZKUtil.convert(e); } }
/** * Presume bytes are serialized unassigned data structure * @param znodeBytes * @return String of the deserialized znode bytes. */ static String toString(final byte[] znodeBytes) { // This method should not exist. Used by ZKUtil stringifying RegionTransition. Have the // method in here so RegionTransition does not leak into ZKUtil. try { RegionTransition rt = RegionTransition.parseFrom(znodeBytes); return rt.toString(); } catch (DeserializationException e) { return ""; } }
/** * Test the scenario when the master is in failover and trying to process a * region which is in Opening state on a dead RS. Master will force offline the * region and put it in transition. AM relies on SSH to reassign it. */ @Test(timeout = 60000) public void testRegionInOpeningStateOnDeadRSWhileMasterFailover() throws IOException, KeeperException, ServiceException, CoordinatedStateException, InterruptedException { AssignmentManagerWithExtrasForTesting am = setUpMockedAssignmentManager( this.server, this.serverManager); ZKAssign.createNodeOffline(this.watcher, REGIONINFO, SERVERNAME_A); int version = ZKAssign.getVersion(this.watcher, REGIONINFO); ZKAssign.transitionNode(this.watcher, REGIONINFO, SERVERNAME_A, EventType.M_ZK_REGION_OFFLINE, EventType.RS_ZK_REGION_OPENING, version); RegionTransition rt = RegionTransition.createRegionTransition(EventType.RS_ZK_REGION_OPENING, REGIONINFO.getRegionName(), SERVERNAME_A, HConstants.EMPTY_BYTE_ARRAY); version = ZKAssign.getVersion(this.watcher, REGIONINFO); Mockito.when(this.serverManager.isServerOnline(SERVERNAME_A)).thenReturn(false); am.getRegionStates().logSplit(SERVERNAME_A); // Assume log splitting is done am.getRegionStates().createRegionState(REGIONINFO); am.gate.set(false); BaseCoordinatedStateManager cp = new ZkCoordinatedStateManager(); cp.initialize(server); cp.start(); OpenRegionCoordination orc = cp.getOpenRegionCoordination(); ZkOpenRegionCoordination.ZkOpenRegionDetails zkOrd = new ZkOpenRegionCoordination.ZkOpenRegionDetails(); zkOrd.setServerName(server.getServerName()); zkOrd.setVersion(version); assertFalse(am.processRegionsInTransition(rt, REGIONINFO, orc, zkOrd)); am.getTableStateManager().setTableState(REGIONINFO.getTable(), Table.State.ENABLED); processServerShutdownHandler(am, false); // Waiting for the assignment to get completed. while (!am.gate.get()) { Thread.sleep(10); } assertTrue("The region should be assigned immediately.", null != am.regionPlans.get(REGIONINFO .getEncodedName())); am.shutdown(); }