diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java index 3d40c70..cc9453c 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java @@ -1655,7 +1655,8 @@ public class MetaTableAccessor { */ public static void splitRegion(final Connection connection, HRegionInfo parent, HRegionInfo splitA, HRegionInfo splitB, - ServerName sn, int regionReplication) throws IOException { + ServerName snp, ServerName sna, ServerName snb, + int regionReplication) throws IOException { Table meta = getMetaHTable(connection); try { HRegionInfo copyOfParent = new HRegionInfo(parent); @@ -1670,8 +1671,12 @@ public class MetaTableAccessor { Put putA = makePutFromRegionInfo(splitA); Put putB = makePutFromRegionInfo(splitB); - addLocation(putA, sn, 1, -1, splitA.getReplicaId()); //new regions, openSeqNum = 1 is fine. - addLocation(putB, sn, 1, -1, splitB.getReplicaId()); + if (sna != null) { + addLocation(putA, sna, 1, -1, splitA.getReplicaId()); //new regions, openSeqNum = 1 is fine. + } + if (snb != null) { + addLocation(putB, snb, 1, -1, splitB.getReplicaId()); + } // Add empty locations for region replicas of daughters so that number of replicas can be // cached whenever the primary region is looked up from meta diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java index a02d89a..eaaa28a 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java @@ -1260,6 +1260,9 @@ public final class HConstants { public static final String DEFAULT_TEMPORARY_HDFS_DIRECTORY = "/user/" + System.getProperty("user.name") + "/hbase-staging"; + public static final String ASSIGN_DAUGHTERS_AFTER_SPLIT = + "hbase.split.assign"; + private HConstants() { // Can't be instantiated with this ctor. } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java index 7639004..7920da9 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java @@ -202,6 +202,8 @@ public class AssignmentManager { private RegionStateListener regionStateListener; + private boolean shouldAssignAfterSplit; + /** * Constructs a new assignment manager. * @@ -254,6 +256,8 @@ public class AssignmentManager { this.metricsAssignmentManager = new MetricsAssignmentManager(); this.tableLockManager = tableLockManager; + this.shouldAssignAfterSplit = + conf.getBoolean(HConstants.ASSIGN_DAUGHTERS_AFTER_SPLIT, false); } /** @@ -2369,64 +2373,51 @@ public class AssignmentManager { } try { - regionStates.splitRegion(hri, a, b, serverName); + regionStates.splitRegion(hri, a, b, serverName, null, null); } catch (IOException ioe) { LOG.info("Failed to record split region " + hri.getShortNameToLog()); return "Failed to record the splitting in meta"; } - return null; - } - - private String onRegionSplit(final RegionState current, final HRegionInfo hri, - final ServerName serverName, final RegionStateTransition transition) { - // The region must be splitting on this server, and the daughters must be in - // splitting_new state. - // If current state is already split on the same server, - // it could be a reportRegionTransition RPC retry. - if (current == null || !current.isSplittingOrSplitOnServer(serverName)) { - return hri.getShortNameToLog() + " is not splitting on " + serverName; - } - // Just return in case of retrying - if (current.isSplit()) { - return null; + //Offline the parent region + regionOffline(hri, State.SPLIT); + try { + regionStates.prepareAssignDaughters(a, b); + } catch (IOException ex) { + LOG.info("Failed to prepare daughters for assignment: " + + "a=" + rs_a + ", b=" + rs_b, ex); + return "Failed to prepare daughters for assignment"; } - final HRegionInfo a = HRegionInfo.convert(transition.getRegionInfo(1)); - final HRegionInfo b = HRegionInfo.convert(transition.getRegionInfo(2)); - RegionState rs_a = regionStates.getRegionState(a); - RegionState rs_b = regionStates.getRegionState(b); - if (rs_a == null || !rs_a.isSplittingNewOnServer(serverName) - || rs_b == null || !rs_b.isSplittingNewOnServer(serverName)) { - return "Some daughter is not known to be splitting on " + serverName - + ", a=" + rs_a + ", b=" + rs_b; + if (!shouldAssignAfterSplit) { + synchronized (this.regionPlans) { + RegionPlan planA = new RegionPlan(a, null, serverName); + RegionPlan planB = new RegionPlan(b, null, serverName); + regionPlans.put(a.getEncodedName(), planA); + regionPlans.put(b.getEncodedName(), planB); + } } - if (TEST_SKIP_SPLIT_HANDLING) { - return "Skipping split message, TEST_SKIP_SPLIT_HANDLING is set"; - } - regionOffline(hri, State.SPLIT); - regionOnline(a, serverName, 1); - regionOnline(b, serverName, 1); + invokeAssign(a); + invokeAssign(b); - // User could disable the table before master knows the new region. - if (getTableStateManager().isTableState(hri.getTable(), - TableState.State.DISABLED, TableState.State.DISABLING)) { - invokeUnAssign(a); - invokeUnAssign(b); - } else { - Callable splitReplicasCallable = new Callable() { - @Override - public Object call() { - doSplittingOfReplicas(hri, a, b); - return null; - } - }; - threadPoolExecutorService.submit(splitReplicasCallable); - } + Callable splitReplicasCallable = new Callable() { + @Override + public Object call() { + doSplittingOfReplicas(hri, a, b); + return null; + } + }; + threadPoolExecutorService.submit(splitReplicasCallable); return null; } + private String onRegionSplit(final RegionState current, final HRegionInfo hri, + final ServerName serverName, final RegionStateTransition transition) { + LOG.error("SPLIT called", new Exception()); + throw new IllegalStateException("SPLIT called!"); + } + private String onRegionSplitReverted(final RegionState current, final HRegionInfo hri, final ServerName serverName, final RegionStateTransition transition) { // The region must be splitting on this server, and the daughters must be in diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStateStore.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStateStore.java index bc5173a..2ec85c5 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStateStore.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStateStore.java @@ -239,9 +239,11 @@ public class RegionStateStore { } } - void splitRegion(HRegionInfo p, - HRegionInfo a, HRegionInfo b, ServerName sn, int regionReplication) throws IOException { - MetaTableAccessor.splitRegion(server.getConnection(), p, a, b, sn, regionReplication); + void splitRegion(HRegionInfo p, HRegionInfo a, HRegionInfo b, + ServerName snp, ServerName sna, ServerName snb, + int regionReplication) throws IOException { + MetaTableAccessor.splitRegion(server.getConnection(), + p, a, b, snp, sna, snb, regionReplication); } void mergeRegions(HRegionInfo p, diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStates.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStates.java index 3743616..e458abb 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStates.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStates.java @@ -20,6 +20,7 @@ package org.apache.hadoop.hbase.master; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -27,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; @@ -43,6 +45,7 @@ import org.apache.hadoop.hbase.ServerLoad; import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.RegionReplicaUtil; +import org.apache.hadoop.hbase.constraint.ConstraintException; import org.apache.hadoop.hbase.master.RegionState.State; import org.apache.hadoop.hbase.client.TableState; import org.apache.hadoop.hbase.util.Bytes; @@ -845,20 +848,44 @@ public class RegionStates { return regions == null ? false : regions.contains(hri); } - void splitRegion(HRegionInfo p, - HRegionInfo a, HRegionInfo b, ServerName sn) throws IOException { + public void prepareAssignDaughters(HRegionInfo a, HRegionInfo b) throws IOException { + synchronized (this) { + if (!(isRegionInState(a, State.SPLITTING_NEW) || isRegionInState(b, State.SPLITTING_NEW))) { + throw new ConstraintException("Neither regions are in SPLITTING_NEW state"); + } + updateRegionState(a, State.OFFLINE, null); + updateRegionState(b, State.OFFLINE, null); + } + } + + void splitRegion(HRegionInfo p, HRegionInfo a, HRegionInfo b, + ServerName snp, ServerName sna, ServerName snb) throws IOException { - regionStateStore.splitRegion(p, a, b, sn, getRegionReplication(p)); + regionStateStore.splitRegion(p, a, b, snp, sna, snb, getRegionReplication(p)); synchronized (this) { // After PONR, split is considered to be done. // Update server holdings to be aligned with the meta. - Set regions = serverHoldings.get(sn); + Set regions = serverHoldings.get(snp); if (regions == null) { - throw new IllegalStateException(sn + " should host some regions"); + throw new IllegalStateException(snp + " should host some regions"); } regions.remove(p); - regions.add(a); - regions.add(b); + + if (sna != null) { + regions = serverHoldings.get(sna); + if (regions == null) { + regions = Collections.newSetFromMap(new ConcurrentHashMap()); + } + regions.add(a); + } + + if (snb != null) { + regions = serverHoldings.get(snb); + if (regions == null) { + regions = Collections.newSetFromMap(new ConcurrentHashMap()); + } + regions.add(b); + } } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/SplitTransactionImpl.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/SplitTransactionImpl.java index 70d040e..5f72969 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/SplitTransactionImpl.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/SplitTransactionImpl.java @@ -529,8 +529,6 @@ public class SplitTransactionImpl implements SplitTransaction { } } - openDaughters(server, services, regions.getFirst(), regions.getSecond()); - transition(SplitTransactionPhase.BEFORE_POST_SPLIT_HOOK); // Coprocessor callback diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/MiniHBaseCluster.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/MiniHBaseCluster.java index 3bd3c3f..ff0c793 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/MiniHBaseCluster.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/MiniHBaseCluster.java @@ -663,7 +663,7 @@ public class MiniHBaseCluster extends HBaseCluster { public List getRegions(TableName tableName) { List ret = new ArrayList(); - for (JVMClusterUtil.RegionServerThread rst : getRegionServerThreads()) { + for (JVMClusterUtil.RegionServerThread rst : getLiveRegionServerThreads()) { HRegionServer hrs = rst.getRegionServer(); for (Region region : hrs.getOnlineRegionsLocalContext()) { if (region.getTableDesc().getTableName().equals(tableName)) { diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestMetaTableAccessor.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestMetaTableAccessor.java index 7e934c0..3bcffb1 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestMetaTableAccessor.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestMetaTableAccessor.java @@ -445,7 +445,8 @@ public class TestMetaTableAccessor { List regionInfos = Lists.newArrayList(parent); MetaTableAccessor.addRegionsToMeta(connection, regionInfos, 3); - MetaTableAccessor.splitRegion(connection, parent, splitA, splitB, serverName0, 3); + MetaTableAccessor.splitRegion(connection, parent, splitA, splitB, + serverName0, serverName0, serverName0, 3); assertEmptyMetaLocation(meta, splitA.getRegionName(), 1); assertEmptyMetaLocation(meta, splitA.getRegionName(), 2); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestSplitTransactionOnCluster.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestSplitTransactionOnCluster.java index fe620e7..446a097 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestSplitTransactionOnCluster.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestSplitTransactionOnCluster.java @@ -28,12 +28,14 @@ import static org.junit.Assert.fail; import java.io.IOException; import java.io.InterruptedIOException; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; +import com.google.common.collect.Lists; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; @@ -47,6 +49,7 @@ import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HRegionLocation; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.MasterNotRunningException; import org.apache.hadoop.hbase.MetaTableAccessor; @@ -65,6 +68,7 @@ import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.Mutation; import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.RegionLocator; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; @@ -129,6 +133,10 @@ public class TestSplitTransactionOnCluster { new HBaseTestingUtility(); @BeforeClass public static void before() throws Exception { + setupOnce(); + } + + public static void setupOnce() throws Exception { TESTING_UTIL.getConfiguration().setInt("hbase.balancer.period", 60000); TESTING_UTIL.startMiniCluster(1, NB_SERVERS, null, MyMaster.class, null); } @@ -266,6 +274,9 @@ public class TestSplitTransactionOnCluster { SplitTransactionImpl st = new SplitTransactionImpl(region, Bytes.toBytes("row3")); assertTrue(st.prepare()); st.execute(regionServer, regionServer); + //verify regions are online + for (Result r : t.getScanner(new Scan())) { + } assertEquals(2, cluster.getRegions(tableName).size()); } @@ -283,58 +294,6 @@ public class TestSplitTransactionOnCluster { } } - /** - * A test that intentionally has master fail the processing of the split message. - * Tests that after we process server shutdown, the daughters are up on line. - * @throws IOException - * @throws InterruptedException - * @throws ServiceException - */ - @Test (timeout = 300000) public void testRSSplitDaughtersAreOnlinedAfterShutdownHandling() - throws IOException, InterruptedException, ServiceException { - final TableName tableName = - TableName.valueOf("testRSSplitDaughtersAreOnlinedAfterShutdownHandling"); - - // Create table then get the single region for our new table. - Table t = createTableAndWait(tableName, HConstants.CATALOG_FAMILY); - List regions = cluster.getRegions(tableName); - HRegionInfo hri = getAndCheckSingleTableRegion(regions); - - int tableRegionIndex = ensureTableRegionNotOnSameServerAsMeta(admin, hri); - - // Turn off balancer so it doesn't cut in and mess up our placements. - this.admin.setBalancerRunning(false, true); - // Turn off the meta scanner so it don't remove parent on us. - cluster.getMaster().setCatalogJanitorEnabled(false); - try { - // Add a bit of load up into the table so splittable. - TESTING_UTIL.loadTable(t, HConstants.CATALOG_FAMILY, false); - // Get region pre-split. - HRegionServer server = cluster.getRegionServer(tableRegionIndex); - printOutRegions(server, "Initial regions: "); - int regionCount = ProtobufUtil.getOnlineRegions(server.getRSRpcServices()).size(); - // Now, before we split, set special flag in master, a flag that has - // it FAIL the processing of split. - AssignmentManager.TEST_SKIP_SPLIT_HANDLING = true; - try { - // Now try splitting and it should work. - split(hri, server, regionCount); - } catch (RegionServerStoppedException rsse) { - // Expected. The regionserver should crash - } - - waitUntilRegionServerDead(); - awaitDaughters(tableName, 2); - } finally { - // Set this flag back. - AssignmentManager.TEST_SKIP_SPLIT_HANDLING = false; - admin.setBalancerRunning(true, false); - cluster.getMaster().setCatalogJanitorEnabled(true); - cluster.startRegionServer(); - t.close(); - } - } - @Test (timeout = 300000) public void testExistingZnodeBlocksSplitAndWeRollback() throws IOException, InterruptedException, NodeExistsException, KeeperException, ServiceException { final TableName tableName = @@ -529,6 +488,7 @@ public class TestSplitTransactionOnCluster { Assert.assertEquals(3, mainTableCount); } finally { table.close(); + TESTING_UTIL.deleteTable(userTableName); } } @@ -659,12 +619,14 @@ public class TestSplitTransactionOnCluster { assertEquals("The specified table should present.", true, tableExists); Map rit = cluster.getMaster().getAssignmentManager().getRegionStates() .getRegionsInTransition(); - assertTrue(rit.size() == 3); + for (Result r : t.getScanner(new Scan())) { + } + assertEquals(rit.toString(), 2, rit.size()); cluster.getMaster().getAssignmentManager().regionOffline(st.getFirstDaughter()); cluster.getMaster().getAssignmentManager().regionOffline(st.getSecondDaughter()); cluster.getMaster().getAssignmentManager().regionOffline(region.getRegionInfo()); rit = cluster.getMaster().getAssignmentManager().getRegionStates().getRegionsInTransition(); - assertTrue(rit.size() == 0); + assertEquals(0, rit.size()); } finally { admin.setBalancerRunning(true, false); cluster.getMaster().setCatalogJanitorEnabled(true); @@ -776,7 +738,7 @@ public class TestSplitTransactionOnCluster { final TableName tableName = TableName.valueOf("testSplitRegionWithNoStoreFiles"); // Create table then get the single region for our new table. - createTableAndWait(tableName, HConstants.CATALOG_FAMILY); + Table table = createTableAndWait(tableName, HConstants.CATALOG_FAMILY); List regions = cluster.getRegions(tableName); HRegionInfo hri = getAndCheckSingleTableRegion(regions); ensureTableRegionNotOnSameServerAsMeta(admin, hri); @@ -812,10 +774,13 @@ public class TestSplitTransactionOnCluster { fail("Split execution should have succeeded with no exceptions thrown"); } + //verify regions are online + for (Result r : table.getScanner(new Scan())) { + } // Postcondition: split the table with no store files into two regions, but still have not // store files List daughters = cluster.getRegions(tableName); - assertTrue(daughters.size() == 2); + assertEquals(2, daughters.size()); // check dirs HBaseFsck.debugLsr(conf, new Path("/")); @@ -860,7 +825,7 @@ public class TestSplitTransactionOnCluster { LOG.info("Starting testSplitAndRestartingMaster"); final TableName tableName = TableName.valueOf("testSplitAndRestartingMaster"); // Create table then get the single region for our new table. - createTableAndWait(tableName, HConstants.CATALOG_FAMILY); + Table table = createTableAndWait(tableName, HConstants.CATALOG_FAMILY); List regions = cluster.getRegions(tableName); HRegionInfo hri = getAndCheckSingleTableRegion(regions); ensureTableRegionNotOnSameServerAsMeta(admin, hri); @@ -888,9 +853,11 @@ public class TestSplitTransactionOnCluster { } // Postcondition + for (Result r : table.getScanner(new Scan())) { + } List daughters = cluster.getRegions(tableName); LOG.info("xxx " + regions.size() + AssignmentManager.TEST_SKIP_SPLIT_HANDLING); - assertTrue(daughters.size() == 2); + assertEquals(2, daughters.size()); } finally { MyMasterRpcServices.enabled.set(false); admin.setBalancerRunning(true, false); @@ -930,7 +897,7 @@ public class TestSplitTransactionOnCluster { Table table2 = null; try { table1 = TESTING_UTIL.getConnection().getTable(firstTable); - table2 = TESTING_UTIL.getConnection().getTable(firstTable); + table2 = TESTING_UTIL.getConnection().getTable(secondTable); insertData(firstTable, admin, table1); insertData(secondTable, admin, table2); admin.split(firstTable, "row2".getBytes()); @@ -940,8 +907,14 @@ public class TestSplitTransactionOnCluster { firstTableRegions = cluster.getRegions(firstTable); } assertEquals("Number of regions after split should be 2.", 2, firstTableRegions.size()); + for(Result r: table1.getScanner(new Scan())) { + //just make sure regions are accessible + } secondTableRegions = cluster.getRegions(secondTable); assertEquals("Number of regions after split should be 2.", 2, secondTableRegions.size()); + for(Result r: table2.getScanner(new Scan())) { + //just make sure regions are accessible + } } finally { if (table1 != null) { table1.close(); @@ -1143,14 +1116,34 @@ public class TestSplitTransactionOnCluster { private void split(final HRegionInfo hri, final HRegionServer server, final int regionCount) throws IOException, InterruptedException { this.admin.splitRegion(hri.getRegionName()); - for (int i = 0; ProtobufUtil.getOnlineRegions( - server.getRSRpcServices()).size() <= regionCount && i < 300; i++) { - LOG.debug("Waiting on region to split"); - Thread.sleep(100); - } - assertFalse("Waited too long for split", - ProtobufUtil.getOnlineRegions(server.getRSRpcServices()).size() <= regionCount); + if (!TESTING_UTIL.getConfiguration().getBoolean( + HConstants.ASSIGN_DAUGHTERS_AFTER_SPLIT, false)) { + for (int i = 0; ProtobufUtil.getOnlineRegions( + server.getRSRpcServices()).size() <= regionCount && i < 300; i++) { + LOG.debug("Waiting on region to split"); + Thread.sleep(100); + } + assertFalse("Waited too long for split", + ProtobufUtil.getOnlineRegions(server.getRSRpcServices()).size() <= regionCount); + } else { + RegionLocator locator = admin.getConnection().getRegionLocator(hri.getTable()); + boolean found = false; + for (int i = 0; i < 300; i++) { + HRegionLocation location = locator.getRegionLocation(hri.getStartKey(), true); + if (location.getRegionInfo().getEncodedName().equals(hri.getEncodedName())) { + found = true; + break; + } + LOG.debug("Waiting on region to split"); + Thread.sleep(100); + } + assertTrue(found); + } + Table t1 = TESTING_UTIL.getConnection().getTable(hri.getTable()); + //Verify split region key space is accessible + for(Result r : t1.getScanner(new Scan(hri.getStartKey(), hri.getEndKey()))) { + } } /** @@ -1325,6 +1318,10 @@ public class TestSplitTransactionOnCluster { public static class MockedRegionObserver extends BaseRegionObserver { private SplitTransactionImpl st = null; private PairOfSameType daughterRegions = null; + private Region parentRegion = null; + private TableName tableName = TableName.valueOf("testSplitHooksBeforeAndAfterPONR_2"); + private AssignmentManager am = + TESTING_UTIL.getHBaseCluster().getMaster().getAssignmentManager(); @Override public void preSplitBeforePONR(ObserverContext ctx, @@ -1332,7 +1329,7 @@ public class TestSplitTransactionOnCluster { RegionCoprocessorEnvironment environment = ctx.getEnvironment(); HRegionServer rs = (HRegionServer) environment.getRegionServerServices(); List onlineRegions = - rs.getOnlineRegions(TableName.valueOf("testSplitHooksBeforeAndAfterPONR_2")); + rs.getOnlineRegions(tableName); Region region = onlineRegions.get(0); for (Region r : onlineRegions) { if (r.getRegionInfo().containsRow(splitKey)) { @@ -1340,6 +1337,7 @@ public class TestSplitTransactionOnCluster { break; } } + parentRegion = region; st = new SplitTransactionImpl((HRegion) region, splitKey); if (!st.prepare()) { LOG.error("Prepare for the table " + region.getTableDesc().getNameAsString() @@ -1347,6 +1345,7 @@ public class TestSplitTransactionOnCluster { ctx.bypass(); return; } + ((HRegion)region).forceSplit(splitKey); daughterRegions = st.stepsBeforePONR(rs, rs, false); HRegionInfo copyOfParent = new HRegionInfo(region.getRegionInfo()); @@ -1362,10 +1361,18 @@ public class TestSplitTransactionOnCluster { daughterRegions.getFirst().getRegionInfo()); Put putB = MetaTableAccessor.makePutFromRegionInfo( daughterRegions.getSecond().getRegionInfo()); - st.addLocation(putA, rs.getServerName(), 1); - st.addLocation(putB, rs.getServerName(), 1); metaEntries.add(putA); metaEntries.add(putB); + MetaTableAccessor.putsToMetaTable(TESTING_UTIL.getConnection(), + //Ugly forced cast, but it's localized in this test + (List)metaEntries); + + am.getRegionStates().regionOffline(parentRegion.getRegionInfo(), RegionState.State.SPLIT); + am.getRegionStates().prepareAssignDaughters( + daughterRegions.getFirst().getRegionInfo(), + daughterRegions.getSecond().getRegionInfo()); + am.assign(daughterRegions.getFirst().getRegionInfo()); + am.assign(daughterRegions.getSecond().getRegionInfo()); } @Override @@ -1373,7 +1380,16 @@ public class TestSplitTransactionOnCluster { throws IOException { RegionCoprocessorEnvironment environment = ctx.getEnvironment(); HRegionServer rs = (HRegionServer) environment.getRegionServerServices(); + st.stepsAfterPONR(rs, rs, daughterRegions, null); + try { + //We wait until daughter regions of manually split table + //is online. This will also end up waiting for the daughters that + //the current split transaction is processing to be assigned as well + TESTING_UTIL.waitUntilNoRegionsInTransition(60000); + } catch (Exception e) { + throw new IllegalStateException("", e); + } } }