-ROOT- and
@@ -63,6 +60,12 @@
private final RootRegionTracker rootRegionTracker;
private final MetaNodeTracker metaNodeTracker;
private final AtomicBoolean metaAvailable = new AtomicBoolean(false);
+ /**
+ * Do not clear this address once set. Let it be cleared by
+ * {@link #setMetaLocation(HServerAddress)} only. Its needed when we do
+ * server shutdown processing -- we need to know who had .META. last. If you
+ * want to know if the address is good, rely on {@link #metaAvailable} value.
+ */
private HServerAddress metaLocation;
private final int defaultTimeout;
private boolean stopped = false;
@@ -365,7 +368,6 @@
private void resetMetaLocation() {
LOG.info("Current cached META location is not valid, resetting");
this.metaAvailable.set(false);
- this.metaLocation = null;
}
private void setMetaLocation(HServerAddress metaLocation) {
@@ -471,37 +473,6 @@
return getMetaServerConnection(true) != null;
}
- /**
- * Check if hsi was carrying -ROOT- or
- * .META. and if so, clear out old locations.
- * @param hsi Server that has crashed/shutdown.
- * @throws InterruptedException
- * @throws KeeperException
- * @return Pair of booleans; if this server was carrying root, then first
- * boolean is set, if server was carrying meta, then second boolean set.
- */
- public Pair-ROOT-,
+ * .META., or both.
+ */
+public class MetaServerShutdownHandler extends ServerShutdownHandler {
+ private final boolean carryingRoot;
+ private final boolean carryingMeta;
+
+ public MetaServerShutdownHandler(final Server server,
+ final MasterServices services,
+ final DeadServer deadServers, final HServerInfo hsi,
+ final boolean carryingRoot, final boolean carryingMeta) {
+ super(server, services, deadServers, hsi, EventType.M_META_SERVER_SHUTDOWN);
+ this.carryingRoot = carryingRoot;
+ this.carryingMeta = carryingMeta;
+ }
+
+ @Override
+ boolean isCarryingRoot() {
+ return this.carryingRoot;
+ }
+
+ @Override
+ boolean isCarryingMeta() {
+ return this.carryingMeta;
+ }
+}
\ No newline at end of file
Index: src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java (revision 1027351)
+++ src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java (working copy)
@@ -57,7 +57,12 @@
public ServerShutdownHandler(final Server server, final MasterServices services,
final DeadServer deadServers, final HServerInfo hsi) {
- super(server, EventType.M_SERVER_SHUTDOWN);
+ this(server, services, deadServers, hsi, EventType.M_SERVER_SHUTDOWN);
+ }
+
+ ServerShutdownHandler(final Server server, final MasterServices services,
+ final DeadServer deadServers, final HServerInfo hsi, EventType type) {
+ super(server, type);
this.hsi = hsi;
this.server = server;
this.services = services;
@@ -67,19 +72,22 @@
}
}
+ /**
+ * @return True if the server we are processing was carrying -ROOT-
+ */
+ boolean isCarryingRoot() {
+ return false;
+ }
+
+ /**
+ * @return True if the server we are processing was carrying .META.
+ */
+ boolean isCarryingMeta() {
+ return false;
+ }
+
@Override
public void process() throws IOException {
- Pair+ * 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. + *
+ * Method synchronizes() with ZK so will yield an up-to-date result but is
+ * a slow read.
+ * @param watcher
+ * @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;
+ }
}
Index: src/test/java/org/apache/hadoop/hbase/catalog/TestCatalogTracker.java
===================================================================
--- src/test/java/org/apache/hadoop/hbase/catalog/TestCatalogTracker.java (revision 1027351)
+++ src/test/java/org/apache/hadoop/hbase/catalog/TestCatalogTracker.java (working copy)
@@ -35,7 +35,6 @@
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo;
-import org.apache.hadoop.hbase.HRegionLocation;
import org.apache.hadoop.hbase.HServerAddress;
import org.apache.hadoop.hbase.HServerInfo;
import org.apache.hadoop.hbase.KeyValue;
@@ -105,6 +104,26 @@
}
/**
+ * Test that we get notification if .META. moves.
+ * @throws IOException
+ * @throws InterruptedException
+ * @throws KeeperException
+ */
+ @Test public void testThatIfMETAMovesWeAreNotified()
+ throws IOException, InterruptedException, KeeperException {
+ HConnection connection = Mockito.mock(HConnection.class);
+ final CatalogTracker ct = constructAndStartCatalogTracker(connection);
+ try {
+ RootLocationEditor.setRootLocation(this.watcher,
+ new HServerAddress("example.com:1234"));
+ } finally {
+ // Clean out root location or later tests will be confused... they presume
+ // start fresh in zk.
+ RootLocationEditor.deleteRootLocation(this.watcher);
+ }
+ }
+
+ /**
* Test interruptable while blocking wait on root and meta.
* @throws IOException
* @throws InterruptedException
Index: src/test/java/org/apache/hadoop/hbase/master/TestMasterFailover.java
===================================================================
--- src/test/java/org/apache/hadoop/hbase/master/TestMasterFailover.java (revision 1027351)
+++ src/test/java/org/apache/hadoop/hbase/master/TestMasterFailover.java (working copy)
@@ -41,6 +41,7 @@
import org.apache.hadoop.hbase.MiniHBaseCluster;
import org.apache.hadoop.hbase.executor.RegionTransitionData;
import org.apache.hadoop.hbase.executor.EventHandler.EventType;
+import org.apache.hadoop.hbase.master.AssignmentManager.RegionState;
import org.apache.hadoop.hbase.master.LoadBalancer.RegionPlan;
import org.apache.hadoop.hbase.regionserver.HRegionServer;
import org.apache.hadoop.hbase.util.Bytes;
@@ -794,10 +795,35 @@
cluster.waitForActiveAndReadyMaster();
log("Master is ready");
+ // Let's add some weird states to master in-memory state
+
+ // PENDING_OPEN and enabled
+ region = enabledRegions.remove(0);
+ regionsThatShouldBeOnline.add(region);
+ master.assignmentManager.regionsInTransition.put(region.getEncodedName(),
+ new RegionState(region, RegionState.State.PENDING_OPEN));
+ // PENDING_OPEN and disabled
+ region = disabledRegions.remove(0);
+ regionsThatShouldBeOffline.add(region);
+ master.assignmentManager.regionsInTransition.put(region.getEncodedName(),
+ new RegionState(region, RegionState.State.PENDING_OPEN));
+ // PENDING_CLOSE and enabled
+ region = enabledRegions.remove(0);
+ regionsThatShouldBeOnline.add(region);
+ master.assignmentManager.regionsInTransition.put(region.getEncodedName(),
+ new RegionState(region, RegionState.State.PENDING_CLOSE));
+ // PENDING_CLOSE and disabled
+ region = disabledRegions.remove(0);
+ regionsThatShouldBeOffline.add(region);
+ master.assignmentManager.regionsInTransition.put(region.getEncodedName(),
+ new RegionState(region, RegionState.State.PENDING_CLOSE));
+
// Failover should be completed, now wait for no RIT
log("Waiting for no more RIT");
ZKAssign.blockUntilNoRIT(zkw);
- log("No more RIT in ZK, now doing final test verification");
+ log("No more RIT in ZK");
+ master.assignmentManager.waitUntilNoRegionsInTransition(120000);
+ log("No more RIT in RIT map, doing final test verification");
// Grab all the regions that are online across RSs
Set