You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by la...@apache.org on 2012/11/12 20:46:01 UTC
svn commit: r1408421 - in /hbase/branches/0.94/src:
main/java/org/apache/hadoop/hbase/regionserver/SplitTransaction.java
test/java/org/apache/hadoop/hbase/regionserver/TestSplitTransactionOnCluster.java
Author: larsh
Date: Mon Nov 12 19:46:01 2012
New Revision: 1408421
URL: http://svn.apache.org/viewvc?rev=1408421&view=rev
Log:
HBASE-7103 Need to fail split if SPLIT znode is deleted even before the split is completed. (Ram)
Modified:
hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/SplitTransaction.java
hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestSplitTransactionOnCluster.java
Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/SplitTransaction.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/SplitTransaction.java?rev=1408421&r1=1408420&r2=1408421&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/SplitTransaction.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/regionserver/SplitTransaction.java Mon Nov 12 19:46:01 2012
@@ -108,10 +108,6 @@ public class SplitTransaction {
*/
enum JournalEntry {
/**
- * Before creating node in splitting state.
- */
- STARTED_SPLITTING,
- /**
* Set region as in transition, set it into SPLITTING state.
*/
SET_SPLITTING_IN_ZK,
@@ -236,20 +232,31 @@ public class SplitTransaction {
server.getConfiguration().getLong("hbase.regionserver.fileSplitTimeout",
this.fileSplitTimeout);
- this.journal.add(JournalEntry.STARTED_SPLITTING);
// Set ephemeral SPLITTING znode up in zk. Mocked servers sometimes don't
// have zookeeper so don't do zk stuff if server or zookeeper is null
if (server != null && server.getZooKeeper() != null) {
try {
- this.znodeVersion = createNodeSplitting(server.getZooKeeper(),
+ createNodeSplitting(server.getZooKeeper(),
this.parent.getRegionInfo(), server.getServerName());
} catch (KeeperException e) {
- throw new IOException("Failed setting SPLITTING znode on " +
+ throw new IOException("Failed creating SPLITTING znode on " +
this.parent.getRegionNameAsString(), e);
}
}
this.journal.add(JournalEntry.SET_SPLITTING_IN_ZK);
-
+ if (server != null && server.getZooKeeper() != null) {
+ try {
+ // Transition node from SPLITTING to SPLITTING after creating the split node.
+ // Master will get the callback for node change only if the transition is successful.
+ // Note that if the transition fails then the rollback will delete the created znode
+ // TODO : May be we can add some new state to znode and handle the new state incase of success/failure
+ this.znodeVersion = transitionNodeSplitting(server.getZooKeeper(),
+ this.parent.getRegionInfo(), server.getServerName(), -1);
+ } catch (KeeperException e) {
+ throw new IOException("Failed setting SPLITTING znode on "
+ + this.parent.getRegionNameAsString(), e);
+ }
+ }
createSplitDir(this.parent.getFilesystem(), this.splitdir);
this.journal.add(JournalEntry.CREATE_SPLIT_DIR);
@@ -740,15 +747,9 @@ public class SplitTransaction {
JournalEntry je = iterator.previous();
switch(je) {
- case STARTED_SPLITTING:
- if (server != null && server.getZooKeeper() != null) {
- cleanZK(server, this.parent.getRegionInfo(), false);
- }
- break;
-
case SET_SPLITTING_IN_ZK:
if (server != null && server.getZooKeeper() != null) {
- cleanZK(server, this.parent.getRegionInfo(), true);
+ cleanZK(server, this.parent.getRegionInfo());
}
break;
@@ -841,15 +842,11 @@ public class SplitTransaction {
LOG.info("Cleaned up old failed split transaction detritus: " + splitdir);
}
- private static void cleanZK(final Server server, final HRegionInfo hri, boolean abort) {
+ private static void cleanZK(final Server server, final HRegionInfo hri) {
try {
// Only delete if its in expected state; could have been hijacked.
ZKAssign.deleteNode(server.getZooKeeper(), hri.getEncodedName(),
EventType.RS_ZK_REGION_SPLITTING);
- } catch (KeeperException.NoNodeException nn) {
- if (abort) {
- server.abort("Failed cleanup of " + hri.getRegionNameAsString(), nn);
- }
} catch (KeeperException e) {
server.abort("Failed cleanup of " + hri.getRegionNameAsString(), e);
}
@@ -869,7 +866,7 @@ public class SplitTransaction {
* @throws KeeperException
* @throws IOException
*/
- int createNodeSplitting(final ZooKeeperWatcher zkw, final HRegionInfo region,
+ void 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"));
@@ -881,9 +878,6 @@ public class SplitTransaction {
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);
}
/**
Modified: hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestSplitTransactionOnCluster.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestSplitTransactionOnCluster.java?rev=1408421&r1=1408420&r2=1408421&view=diff
==============================================================================
--- hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestSplitTransactionOnCluster.java (original)
+++ hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestSplitTransactionOnCluster.java Mon Nov 12 19:46:01 2012
@@ -27,6 +27,8 @@ import static org.junit.Assert.assertFal
import java.io.IOException;
import java.util.List;
+import java.util.NavigableMap;
+import java.util.concurrent.CountDownLatch;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -37,6 +39,7 @@ import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
+import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.executor.EventHandler.EventType;
import org.apache.hadoop.hbase.executor.RegionTransitionData;
import org.apache.hadoop.hbase.master.AssignmentManager;
@@ -70,7 +73,11 @@ public class TestSplitTransactionOnClust
private HBaseAdmin admin = null;
private MiniHBaseCluster cluster = null;
private static final int NB_SERVERS = 2;
-
+ private static CountDownLatch latch = new CountDownLatch(1);
+ private static boolean secondSplit = false;
+ private static boolean callRollBack = false;
+ private static boolean firstSplitCompleted = false;
+
private static final HBaseTestingUtility TESTING_UTIL =
new HBaseTestingUtility();
@@ -564,7 +571,7 @@ public class TestSplitTransactionOnClust
} else {
st = new MockedSplitTransaction(regions.get(0), null) {
@Override
- int createNodeSplitting(ZooKeeperWatcher zkw, HRegionInfo region, ServerName serverName)
+ void createNodeSplitting(ZooKeeperWatcher zkw, HRegionInfo region, ServerName serverName)
throws KeeperException, IOException {
throw new IOException();
}
@@ -643,6 +650,100 @@ public class TestSplitTransactionOnClust
}
}
+ @Test(timeout = 2000000)
+ public void testShouldFailSplitIfZNodeDoesNotExistDueToPrevRollBack() throws Exception {
+ final byte[] tableName = Bytes
+ .toBytes("testShouldFailSplitIfZNodeDoesNotExistDueToPrevRollBack");
+ HBaseAdmin admin = new HBaseAdmin(TESTING_UTIL.getConfiguration());
+ try {
+ // Create table then get the single region for our new table.
+ HTableDescriptor htd = new HTableDescriptor(tableName);
+ htd.addFamily(new HColumnDescriptor("cf"));
+ admin.createTable(htd);
+ HTable t = new HTable(cluster.getConfiguration(), tableName);
+ while (!(cluster.getRegions(tableName).size() == 1)) {
+ Thread.sleep(100);
+ }
+ final List<HRegion> regions = cluster.getRegions(tableName);
+ HRegionInfo hri = getAndCheckSingleTableRegion(regions);
+ int regionServerIndex = cluster.getServerWith(regions.get(0).getRegionName());
+ final HRegionServer regionServer = cluster.getRegionServer(regionServerIndex);
+ insertData(tableName, admin, t);
+ // Turn off balancer so it doesn't cut in and mess up our placements.
+ this.admin.setBalancerRunning(false, false);
+ // Turn off the meta scanner so it don't remove parent on us.
+ cluster.getMaster().setCatalogJanitorEnabled(false);
+
+ new Thread() {
+ public void run() {
+ SplitTransaction st = null;
+ st = new MockedSplitTransaction(regions.get(0), Bytes.toBytes("row2"));
+ try {
+ st.prepare();
+ st.execute(regionServer, regionServer);
+ } catch (IOException e) {
+
+ }
+ }
+ }.start();
+ while (!callRollBack) {
+ Thread.sleep(100);
+ }
+ SplitTransaction st = null;
+ st = new MockedSplitTransaction(regions.get(0), Bytes.toBytes("row2"));
+ try {
+ secondSplit = true;
+ st.prepare();
+ st.execute(regionServer, regionServer);
+ } catch (IOException e) {
+ LOG.debug("Rollback started :"+ e.getMessage());
+ st.rollback(regionServer, regionServer);
+ }
+ while (!firstSplitCompleted) {
+ Thread.sleep(100);
+ }
+ NavigableMap<String, RegionState> rit = cluster.getMaster().getAssignmentManager()
+ .getRegionsInTransition();
+ while (rit.containsKey(hri.getTableNameAsString())) {
+ Thread.sleep(100);
+ }
+ List<HRegion> onlineRegions = regionServer.getOnlineRegions(tableName);
+ // Region server side split is successful.
+ assertEquals("The parent region should be splitted", 2, onlineRegions.size());
+ //Should be present in RIT
+ List<HRegionInfo> regionsOfTable = cluster.getMaster().getAssignmentManager().getRegionsOfTable(tableName);
+ // Master side should also reflect the same
+ assertEquals("No of regions in master", 2, regionsOfTable.size());
+ } finally {
+ admin.setBalancerRunning(true, false);
+ secondSplit = false;
+ firstSplitCompleted = false;
+ callRollBack = false;
+ cluster.getMaster().setCatalogJanitorEnabled(true);
+ if (admin.isTableAvailable(tableName) && admin.isTableEnabled(tableName)) {
+ admin.disableTable(tableName);
+ admin.deleteTable(tableName);
+ admin.close();
+ }
+ }
+ }
+
+ private void insertData(final byte[] tableName, HBaseAdmin admin, HTable t) throws IOException,
+ InterruptedException {
+ Put p = new Put(Bytes.toBytes("row1"));
+ p.add(Bytes.toBytes("cf"), Bytes.toBytes("q1"), Bytes.toBytes("1"));
+ t.put(p);
+ p = new Put(Bytes.toBytes("row2"));
+ p.add(Bytes.toBytes("cf"), Bytes.toBytes("q1"), Bytes.toBytes("2"));
+ t.put(p);
+ p = new Put(Bytes.toBytes("row3"));
+ p.add(Bytes.toBytes("cf"), Bytes.toBytes("q1"), Bytes.toBytes("3"));
+ t.put(p);
+ p = new Put(Bytes.toBytes("row4"));
+ p.add(Bytes.toBytes("cf"), Bytes.toBytes("q1"), Bytes.toBytes("4"));
+ t.put(p);
+ admin.flush(tableName);
+ }
@Test(timeout = 15000)
public void testShouldThrowIOExceptionIfStoreFileSizeIsEmptyAndSHouldSuccessfullyExecuteRollback()
throws Exception {
@@ -695,8 +796,43 @@ public class TestSplitTransactionOnClust
}
public static class MockedSplitTransaction extends SplitTransaction {
+ private HRegion currentRegion;
public MockedSplitTransaction(HRegion r, byte[] splitrow) {
super(r, splitrow);
+ this.currentRegion = r;
+ }
+
+ @Override
+ void transitionZKNode(Server server, RegionServerServices services, HRegion a, HRegion b)
+ throws IOException {
+ if (this.currentRegion.getRegionInfo().getTableNameAsString()
+ .equals("testShouldFailSplitIfZNodeDoesNotExistDueToPrevRollBack")) {
+ try {
+ if (!secondSplit){
+ callRollBack = true;
+ latch.await();
+ }
+ } catch (InterruptedException e) {
+ }
+
+ }
+ super.transitionZKNode(server, services, a, b);
+ if (this.currentRegion.getRegionInfo().getTableNameAsString()
+ .equals("testShouldFailSplitIfZNodeDoesNotExistDueToPrevRollBack")) {
+ firstSplitCompleted = true;
+ }
+ }
+ @Override
+ public boolean rollback(Server server, RegionServerServices services) throws IOException {
+ if (this.currentRegion.getRegionInfo().getTableNameAsString()
+ .equals("testShouldFailSplitIfZNodeDoesNotExistDueToPrevRollBack")) {
+ if(secondSplit){
+ super.rollback(server, services);
+ latch.countDown();
+ return true;
+ }
+ }
+ return super.rollback(server, services);
}
}