HBASE-7790 Refactor OpenRegionHandler so that the cleanup happens in one place - the finally block(Ram)

git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1450269 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
ramkrishna 2013-02-26 16:41:07 +00:00
parent eeefa84e3f
commit 4224209d28
3 changed files with 114 additions and 25 deletions

View File

@ -32,6 +32,7 @@ import org.apache.hadoop.hbase.executor.EventType;
import org.apache.hadoop.hbase.regionserver.HRegion; import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.regionserver.RegionServerAccounting; import org.apache.hadoop.hbase.regionserver.RegionServerAccounting;
import org.apache.hadoop.hbase.regionserver.RegionServerServices; import org.apache.hadoop.hbase.regionserver.RegionServerServices;
import org.apache.hadoop.hbase.regionserver.wal.HLog;
import org.apache.hadoop.hbase.util.CancelableProgressable; import org.apache.hadoop.hbase.util.CancelableProgressable;
import org.apache.hadoop.hbase.zookeeper.ZKAssign; import org.apache.hadoop.hbase.zookeeper.ZKAssign;
import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException;
@ -87,8 +88,9 @@ public class OpenRegionHandler extends EventHandler {
@Override @Override
public void process() throws IOException { public void process() throws IOException {
boolean openSuccessful = false; boolean openSuccessful = false;
boolean transitionToFailedOpen = false; boolean transitionedToOpening = false;
final String regionName = regionInfo.getRegionNameAsString(); final String regionName = regionInfo.getRegionNameAsString();
HRegion region = null;
try { try {
if (this.server.isStopped() || this.rsServices.isStopping()) { if (this.server.isStopped() || this.rsServices.isStopping()) {
@ -106,7 +108,6 @@ public class OpenRegionHandler extends EventHandler {
LOG.error("Region " + encodedName + LOG.error("Region " + encodedName +
" was already online when we started processing the opening. " + " was already online when we started processing the opening. " +
"Marking this new attempt as failed"); "Marking this new attempt as failed");
tryTransitionFromOfflineToFailedOpen(this.rsServices, regionInfo, this.version);
return; return;
} }
@ -115,23 +116,19 @@ public class OpenRegionHandler extends EventHandler {
// Calling transitionZookeeperOfflineToOpening initializes this.version. // Calling transitionZookeeperOfflineToOpening initializes this.version.
if (!isRegionStillOpening()){ if (!isRegionStillOpening()){
LOG.error("Region " + encodedName + " opening cancelled"); LOG.error("Region " + encodedName + " opening cancelled");
tryTransitionFromOfflineToFailedOpen(this.rsServices, regionInfo, this.version);
return; return;
} }
if (!transitionZookeeperOfflineToOpening(encodedName, versionOfOfflineNode)) { if (!transitionZookeeperOfflineToOpening(encodedName, versionOfOfflineNode)) {
LOG.warn("Region was hijacked? Opening cancelled for encodedName=" + encodedName); LOG.warn("Region was hijacked? Opening cancelled for encodedName=" + encodedName);
// This is a desperate attempt: the znode is unlikely to be ours. But we can't do more. // This is a desperate attempt: the znode is unlikely to be ours. But we can't do more.
tryTransitionFromOfflineToFailedOpen(this.rsServices, regionInfo, this.version);
return; return;
} }
transitionedToOpening = true;
// Open region. After a successful open, failures in subsequent // Open region. After a successful open, failures in subsequent
// processing needs to do a close as part of cleanup. // processing needs to do a close as part of cleanup.
HRegion region = openRegion(); region = openRegion();
if (region == null) { if (region == null) {
tryTransitionFromOpeningToFailedOpen(regionInfo);
transitionToFailedOpen = true;
return; return;
} }
boolean failed = true; boolean failed = true;
@ -142,9 +139,6 @@ public class OpenRegionHandler extends EventHandler {
} }
if (failed || this.server.isStopped() || if (failed || this.server.isStopped() ||
this.rsServices.isStopping()) { this.rsServices.isStopping()) {
cleanupFailedOpen(region);
tryTransitionFromOpeningToFailedOpen(regionInfo);
transitionToFailedOpen = true;
return; return;
} }
@ -155,9 +149,6 @@ public class OpenRegionHandler extends EventHandler {
// OR (b) someone else opened the region before us // OR (b) someone else opened the region before us
// OR (c) someone cancelled the open // OR (c) someone cancelled the open
// In all cases, we try to transition to failed_open to be safe. // In all cases, we try to transition to failed_open to be safe.
cleanupFailedOpen(region);
tryTransitionFromOpeningToFailedOpen(regionInfo);
transitionToFailedOpen = true;
return; return;
} }
@ -180,6 +171,10 @@ public class OpenRegionHandler extends EventHandler {
} finally { } finally {
// Do all clean up here
if (!openSuccessful) {
doCleanUpOnFailedOpen(region, transitionedToOpening);
}
final Boolean current = this.rsServices.getRegionsInTransitionInRS(). final Boolean current = this.rsServices.getRegionsInTransitionInRS().
remove(this.regionInfo.getEncodedNameAsBytes()); remove(this.regionInfo.getEncodedNameAsBytes());
@ -191,19 +186,35 @@ public class OpenRegionHandler extends EventHandler {
// 1) this.rsServices.addToOnlineRegions(region); // 1) this.rsServices.addToOnlineRegions(region);
// 2) the ZK state. // 2) the ZK state.
if (openSuccessful) { if (openSuccessful) {
if (current == null) { // Should NEVER happen, but let's be paranoid. if (current == null) { // Should NEVER happen, but let's be paranoid.
LOG.error("Bad state: we've just opened a region that was NOT in transition. Region=" + LOG.error("Bad state: we've just opened a region that was NOT in transition. Region="
regionName + regionName);
); } else if (Boolean.FALSE.equals(current)) { // Can happen, if we're
} else if (Boolean.FALSE.equals(current)) { // Can happen, if we're really unlucky. // really unlucky.
LOG.error("Race condition: we've finished to open a region, while a close was requested " LOG.error("Race condition: we've finished to open a region, while a close was requested "
+ " on region=" + regionName + ". It can be a critical error, as a region that" + + " on region=" + regionName + ". It can be a critical error, as a region that"
" should be closed is now opened." + " should be closed is now opened.");
);
} }
} else if (transitionToFailedOpen == false) { }
}
}
private void doCleanUpOnFailedOpen(HRegion region, boolean transitionedToOpening)
throws IOException {
if (transitionedToOpening) {
try {
if (region != null) {
cleanupFailedOpen(region);
}
} finally {
// Even if cleanupFailed open fails we need to do this transition
// See HBASE-7698
tryTransitionFromOpeningToFailedOpen(regionInfo); tryTransitionFromOpeningToFailedOpen(regionInfo);
} }
} else {
// If still transition to OPENING is not done, we need to transition znode
// to FAILED_OPEN
tryTransitionFromOfflineToFailedOpen(this.rsServices, regionInfo, versionOfOfflineNode);
} }
} }

View File

@ -212,5 +212,77 @@ public class TestOpenRegionHandler {
TEST_HRI.getEncodedName())); TEST_HRI.getEncodedName()));
assertEquals(EventType.RS_ZK_REGION_FAILED_OPEN, rt.getEventType()); assertEquals(EventType.RS_ZK_REGION_FAILED_OPEN, rt.getEventType());
} }
@Test
public void testTransitionToFailedOpenFromOffline() throws Exception {
Server server = new MockServer(HTU);
RegionServerServices rsServices = new MockRegionServerServices(server.getZooKeeper(),
server.getServerName());
// Create it OFFLINE, which is what it expects
ZKAssign.createNodeOffline(server.getZooKeeper(), TEST_HRI, server.getServerName());
// Create the handler
OpenRegionHandler handler = new OpenRegionHandler(server, rsServices, TEST_HRI, TEST_HTD) {
@Override
boolean transitionZookeeperOfflineToOpening(String encodedName, int versionOfOfflineNode) {
return false;
}
};
rsServices.getRegionsInTransitionInRS().put(TEST_HRI.getEncodedNameAsBytes(), Boolean.TRUE);
handler.process();
RegionTransition rt = RegionTransition.parseFrom(ZKAssign.getData(server.getZooKeeper(),
TEST_HRI.getEncodedName()));
assertEquals(EventType.RS_ZK_REGION_FAILED_OPEN, rt.getEventType());
}
@Test
public void testTransitionToFailedOpenFromOffline() throws Exception {
Server server = new MockServer(HTU);
RegionServerServices rsServices = new MockRegionServerServices(server.getZooKeeper(),
server.getServerName());
// Create it OFFLINE, which is what it expects
ZKAssign.createNodeOffline(server.getZooKeeper(), TEST_HRI, server.getServerName());
// Create the handler
OpenRegionHandler handler = new OpenRegionHandler(server, rsServices, TEST_HRI, TEST_HTD) {
@Override
boolean transitionZookeeperOfflineToOpening(String encodedName, int versionOfOfflineNode) {
return false;
}
};
rsServices.getRegionsInTransitionInRS().put(TEST_HRI.getEncodedNameAsBytes(), Boolean.TRUE);
handler.process();
RegionTransition rt = RegionTransition.parseFrom(ZKAssign.getData(server.getZooKeeper(),
TEST_HRI.getEncodedName()));
assertEquals(EventType.RS_ZK_REGION_FAILED_OPEN, rt.getEventType());
}
@Test
public void testTransitionToFailedOpenFromOffline() throws Exception {
Server server = new MockServer(HTU);
RegionServerServices rsServices = new MockRegionServerServices(server.getZooKeeper(),
server.getServerName());
// Create it OFFLINE, which is what it expects
ZKAssign.createNodeOffline(server.getZooKeeper(), TEST_HRI, server.getServerName());
// Create the handler
OpenRegionHandler handler = new OpenRegionHandler(server, rsServices, TEST_HRI, TEST_HTD) {
@Override
boolean transitionZookeeperOfflineToOpening(String encodedName, int versionOfOfflineNode) {
return false;
}
};
rsServices.getRegionsInTransitionInRS().put(TEST_HRI.getEncodedNameAsBytes(), Boolean.TRUE);
handler.process();
RegionTransition rt = RegionTransition.parseFrom(ZKAssign.getData(server.getZooKeeper(),
TEST_HRI.getEncodedName()));
assertEquals(EventType.RS_ZK_REGION_FAILED_OPEN, rt.getEventType());
}
} }

View File

@ -51,11 +51,17 @@ public class MockRegionServerServices implements RegionServerServices {
new ConcurrentSkipListMap<byte[], Boolean>(Bytes.BYTES_COMPARATOR); new ConcurrentSkipListMap<byte[], Boolean>(Bytes.BYTES_COMPARATOR);
private HFileSystem hfs = null; private HFileSystem hfs = null;
private ZooKeeperWatcher zkw = null; private ZooKeeperWatcher zkw = null;
private ServerName serverName = null;
public MockRegionServerServices(ZooKeeperWatcher zkw){ public MockRegionServerServices(ZooKeeperWatcher zkw) {
this.zkw = zkw; this.zkw = zkw;
} }
public MockRegionServerServices(ZooKeeperWatcher zkw, ServerName serverName) {
this.zkw = zkw;
this.serverName = serverName;
}
public MockRegionServerServices(){ public MockRegionServerServices(){
this(null); this(null);
} }
@ -126,7 +132,7 @@ public class MockRegionServerServices implements RegionServerServices {
@Override @Override
public ServerName getServerName() { public ServerName getServerName() {
return null; return this.serverName;
} }
@Override @Override