/** * 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; }
/** * Process failover of new master for region <code>encodedRegionName</code> * up in zookeeper. * @param encodedRegionName Region to process failover for. * @param regionInfo If null we'll go get it from meta table. * @param deadServers Can be null * @return True if we processed <code>regionInfo</code> as a RIT. * @throws KeeperException * @throws IOException */ boolean processRegionInTransition(final String encodedRegionName, final HRegionInfo regionInfo, final Map<ServerName,List<Pair<HRegionInfo,Result>>> deadServers) throws KeeperException, IOException { Stat stat = new Stat(); RegionTransitionData data = ZKAssign.getDataAndWatch(watcher, encodedRegionName, stat); if (data == null) return false; HRegionInfo hri = regionInfo; if (hri == null) { if ((hri = getHRegionInfo(data)) == null) return false; } processRegionsInTransition(data, hri, deadServers, stat.getVersion()); return true; }
/** * New unassigned node has been created. * * <p>This happens when an RS begins the OPENING or CLOSING of a region by * creating an unassigned node. * * <p>When this happens we must: * <ol> * <li>Watch the node for further events</li> * <li>Read and handle the state in the node</li> * </ol> */ @Override public void nodeCreated(String path) { if(path.startsWith(watcher.assignmentZNode)) { try { Stat stat = new Stat(); RegionTransitionData data = ZKAssign.getDataAndWatch(watcher, path, stat); if (data == null) { return; } handleRegion(data, stat.getVersion()); } catch (KeeperException e) { master.abort("Unexpected ZK exception reading unassigned node data", e); } } }
/** * Existing unassigned node has had data changed. * * <p>This happens when an RS transitions from OFFLINE to OPENING, or between * OPENING/OPENED and CLOSING/CLOSED. * * <p>When this happens we must: * <ol> * <li>Watch the node for further events</li> * <li>Read and handle the state in the node</li> * </ol> */ @Override public void nodeDataChanged(String path) { if(path.startsWith(watcher.assignmentZNode)) { try { Stat stat = new Stat(); RegionTransitionData data = ZKAssign.getDataAndWatch(watcher, path, stat); if (data == null) { return; } handleRegion(data, stat.getVersion()); } catch (KeeperException e) { master.abort("Unexpected ZK exception reading unassigned node data", e); } } }
/** * New unassigned node has been created. * * <p>This happens when an RS begins the OPENING, SPLITTING or CLOSING of a * region by creating a znode. * * <p>When this happens we must: * <ol> * <li>Watch the node for further children changed events</li> * <li>Watch all new children for changed events</li> * </ol> */ @Override public void nodeChildrenChanged(String path) { if(path.equals(watcher.assignmentZNode)) { try { List<String> children = ZKUtil.listChildrenAndWatchForNewChildren(watcher, watcher.assignmentZNode); if (children != null) { Stat stat = new Stat(); for (String child : children) { stat.setVersion(0); RegionTransitionData data = ZKAssign.getDataAndWatch(watcher, ZKUtil.joinZNode(watcher.assignmentZNode, child), stat); // See HBASE-7551, handle splitting here as well, in case we miss the node change event if (stat.getVersion() > 0 && data.getEventType() == EventType.RS_ZK_REGION_SPLITTING) { handleRegion(data, stat.getVersion()); } } } } catch(KeeperException e) { master.abort("Unexpected ZK exception reading unassigned children", e); } } }
/** * @param path * @return True if znode is in SPLIT or SPLITTING state. * @throws KeeperException Can happen if the znode went away in meantime. */ private boolean isSplitOrSplitting(final String path) throws KeeperException { boolean result = false; // This may fail if the SPLIT or SPLITTING znode gets cleaned up before we // can get data from it. RegionTransitionData data = ZKAssign.getData(master.getZooKeeper(), path); EventType evt = data.getEventType(); switch (evt) { case RS_ZK_REGION_SPLIT: case RS_ZK_REGION_SPLITTING: result = true; break; default: break; } return result; }
/** * 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 { RegionTransitionData data = new RegionTransitionData(EventType.RS_ZK_REGION_SPLITTING, region.getRegionName(), serverName); String node = ZKAssign.getNodeName(zkw, region.getEncodedName()); if (!ZKUtil.createEphemeralNodeAndWatch(zkw, node, data.getBytes())) { 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) throws IOException, NodeExistsException, KeeperException { // Create it OFFLINE node, which is what Master set before sending OPEN RPC ZKAssign.createNodeOffline(server.getZooKeeper(), hri, server.getServerName()); int version = ZKAssign.transitionNodeOpening(server.getZooKeeper(), hri, server.getServerName()); OpenRegionHandler openHandler = new OpenRegionHandler(server, rss, hri, htd, version); openHandler.process(); RegionTransitionData data = 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); }
@Test public void testFailedOpenRegion() throws Exception { Server server = new MockServer(HTU); RegionServerServices rsServices = new MockRegionServerServices(); // Create it OFFLINE, which is what it expects ZKAssign.createNodeOffline(server.getZooKeeper(), TEST_HRI, server.getServerName()); ZKAssign.transitionNodeOpening(server.getZooKeeper(), TEST_HRI, server.getServerName()); // Create the handler OpenRegionHandler handler = new OpenRegionHandler(server, rsServices, TEST_HRI, TEST_HTD) { @Override HRegion openRegion() { // Fake failure of opening a region due to an IOE, which is caught return null; } }; handler.process(); // Handler should have transitioned it to FAILED_OPEN RegionTransitionData data = ZKAssign.getData(server.getZooKeeper(), TEST_HRI.getEncodedName()); assertEquals(EventType.RS_ZK_REGION_FAILED_OPEN, data.getEventType()); }
@Test public void testFailedUpdateMeta() throws Exception { Server server = new MockServer(HTU); RegionServerServices rsServices = new MockRegionServerServices(); // Create it OFFLINE, which is what it expects ZKAssign.createNodeOffline(server.getZooKeeper(), TEST_HRI, server.getServerName()); ZKAssign.transitionNodeOpening(server.getZooKeeper(), TEST_HRI, server.getServerName()); // Create the handler OpenRegionHandler handler = new OpenRegionHandler(server, rsServices, TEST_HRI, TEST_HTD) { @Override boolean updateMeta(final HRegion r) { // Fake failure of updating META return false; } }; handler.process(); // Handler should have transitioned it to FAILED_OPEN RegionTransitionData data = ZKAssign.getData(server.getZooKeeper(), TEST_HRI.getEncodedName()); assertEquals(EventType.RS_ZK_REGION_FAILED_OPEN, data.getEventType()); }
/** * 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 */ private static int createNodeSplitting(final ZooKeeperWatcher zkw, final HRegionInfo region, final ServerName serverName) throws KeeperException, IOException { LOG.debug(zkw.prefix("Creating ephemeral node for " + region.getEncodedName() + " in SPLITTING state")); RegionTransitionData data = new RegionTransitionData(EventType.RS_ZK_REGION_SPLITTING, region.getRegionName(), serverName); String node = ZKAssign.getNodeName(zkw, region.getEncodedName()); if (!ZKUtil.createEphemeralNodeAndWatch(zkw, node, data.getBytes())) { 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); }