From 9ca6f806032d44e658fb81b0d4653d4d8ab57700 Mon Sep 17 00:00:00 2001 From: Pankaj Kumar Date: Tue, 19 Dec 2017 21:32:21 +0800 Subject: [PATCH] HBASE-19553, Old replica regions should be cleared from AM memory after primary region split or merge --- .../hadoop/hbase/master/AssignmentManager.java | 18 ++++ .../org/apache/hadoop/hbase/client/TestAdmin1.java | 102 +++++++++++++++++++-- 2 files changed, 112 insertions(+), 8 deletions(-) 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 b8c088a..e7d6108 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 @@ -4394,6 +4394,15 @@ public class AssignmentManager extends ZooKeeperListener { LOG.warn("Couldn't assign all replica(s) of region " + mergedHri+ " because of " + ie.getMessage()); } + + // Remove merged region's replica from AM's memory + for (List l : c) { + for (HRegionInfo h : l) { + if (!RegionReplicaUtil.isDefaultReplica(h)) { + regionStates.deleteRegion(h); + } + } + } } private void doSplittingOfReplicas(final HRegionInfo parentHri, final HRegionInfo hri_a, @@ -4437,6 +4446,15 @@ public class AssignmentManager extends ZooKeeperListener { } catch (InterruptedException e) { LOG.warn("Caught exception " + e + " while trying to assign replica(s) of daughter(s)"); } + + // Remove parent's replica regions from AM's memory + for (List l : c) { + for (HRegionInfo h : l) { + if (!RegionReplicaUtil.isDefaultReplica(h)) { + regionStates.deleteRegion(h); + } + } + } } private void prepareDaughterReplicaForAssignment(HRegionInfo daughterHri, HRegionInfo parentHri, diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAdmin1.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAdmin1.java index 279b304..cecd746 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAdmin1.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAdmin1.java @@ -50,6 +50,7 @@ import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TableNotDisabledException; import org.apache.hadoop.hbase.TableNotEnabledException; import org.apache.hadoop.hbase.TableNotFoundException; +import org.apache.hadoop.hbase.Waiter; import org.apache.hadoop.hbase.executor.EventHandler; import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos; import org.apache.hadoop.hbase.util.Bytes; @@ -57,7 +58,9 @@ import org.apache.hadoop.hbase.util.FSUtils; import org.apache.hadoop.hbase.zookeeper.ZKTableStateClientSideReader; import org.apache.hadoop.hbase.ZooKeeperConnectionException; import org.apache.hadoop.hbase.exceptions.MergeRegionException; +import org.apache.hadoop.hbase.master.AssignmentManager; import org.apache.hadoop.hbase.master.HMaster; +import org.apache.hadoop.hbase.master.RegionState; import org.apache.hadoop.hbase.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.protobuf.RequestConverter; import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.AdminService; @@ -1146,15 +1149,8 @@ public class TestAdmin1 { // regions. // Set up a table with 3 regions and replication set to 3 TableName tableName = TableName.valueOf("testSplitAndMergeWithReplicaTable"); - HTableDescriptor desc = new HTableDescriptor(tableName); - desc.setRegionReplication(3); byte[] cf = "f".getBytes(); - HColumnDescriptor hcd = new HColumnDescriptor(cf); - desc.addFamily(hcd); - byte[][] splitRows = new byte[2][]; - splitRows[0] = new byte[]{(byte)'4'}; - splitRows[1] = new byte[]{(byte)'7'}; - TEST_UTIL.getHBaseAdmin().createTable(desc, splitRows); + createReplicaTable(tableName, cf); List oldRegions; do { oldRegions = TEST_UTIL.getHBaseCluster().getRegions(tableName); @@ -1243,6 +1239,96 @@ public class TestAdmin1 { } /** + * Test case to validate whether parent's replica region are cleared from AM's memory after SPLIT. + * @throws Exception + */ + @Test + public void testRegionStateCleanupFromAMMemoryAfterRegionSplitAndMerge() throws Exception { + final TableName tableName = + TableName.valueOf("testRegionStateCleanupFromAMMemoryAfterRegionSplitAndMerge"); + createReplicaTable(tableName, "f".getBytes()); + final int regionReplication = admin.getTableDescriptor(tableName).getRegionReplication(); + + List> regions = MetaTableAccessor.getTableRegionsAndLocations( + TEST_UTIL.getZooKeeperWatcher(), TEST_UTIL.getConnection(), tableName); + assertEquals(9, regions.size()); + final int primaryRegionCount = regions.size() / regionReplication; + + final AssignmentManager am = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager(); + List offlineRegions = + am.getRegionStates().getRegionByStateOfTable(tableName).get(RegionState.State.OFFLINE); + assertEquals(0, offlineRegions.size()); + + // Validate region split + byte[] regionName = regions.get(0).getFirst().getRegionName(); + try { + TEST_UTIL.getHBaseAdmin().split(regionName, Bytes.toBytes('2')); + } catch (IllegalArgumentException ex) { + fail("Exception occured during region split" + ex); + } + + // Wait for replica region to become online + TEST_UTIL.waitFor(60000, 500, new Waiter.Predicate() { + @Override + public boolean evaluate() throws IOException { + return am.getRegionStates().getRegionByStateOfTable(tableName).get(RegionState.State.OPEN) + .size() == (primaryRegionCount + 1) * regionReplication; + } + }); + + regions = MetaTableAccessor.getTableRegionsAndLocations(TEST_UTIL.getZooKeeperWatcher(), + TEST_UTIL.getConnection(), tableName); + assertEquals(12, regions.size()); + final int primaryRegionCountAfterSplit = regions.size() / regionReplication; + + // Offline region after table split + offlineRegions = + am.getRegionStates().getRegionByStateOfTable(tableName).get(RegionState.State.OFFLINE); + // Parent's replica region should be removed from AM's memeory. + assertEquals(0, offlineRegions.size()); + + // Validate region merge + HRegionInfo regionA = regions.get(3).getFirst(); + HRegionInfo regionB = regions.get(6).getFirst(); + try { + TEST_UTIL.getHBaseAdmin().mergeRegions(regionA.getRegionName(), regionB.getRegionName(), + true); + } catch (IllegalArgumentException ex) { + fail("Exception occured during region merge" + ex); + } + + // Wait for replica region to become online + TEST_UTIL.waitFor(60000, 500, new Waiter.Predicate() { + @Override + public boolean evaluate() throws IOException { + return am.getRegionStates().getRegionByStateOfTable(tableName).get(RegionState.State.OPEN) + .size() == (primaryRegionCountAfterSplit - 1) * regionReplication; + } + }); + + regions = MetaTableAccessor.getTableRegionsAndLocations(TEST_UTIL.getZooKeeperWatcher(), + TEST_UTIL.getConnection(), tableName); + assertEquals(9, regions.size()); + // Offline region after table split + offlineRegions = + am.getRegionStates().getRegionByStateOfTable(tableName).get(RegionState.State.OFFLINE); + // Parent's replica region should be removed from AM's memeory. + assertEquals(0, offlineRegions.size()); + } + + private byte[] createReplicaTable(TableName tableName, byte[] cf) throws IOException { + HTableDescriptor desc = new HTableDescriptor(tableName); + desc.setRegionReplication(3); + HColumnDescriptor hcd = new HColumnDescriptor(cf); + desc.addFamily(hcd); + byte[][] splitRows = new byte[2][]; + splitRows[0] = new byte[] { (byte) '4' }; + splitRows[1] = new byte[] { (byte) '7' }; + TEST_UTIL.getHBaseAdmin().createTable(desc, splitRows); + return cf; + } + + /** * HADOOP-2156 * @throws IOException */ -- 2.7.2.windows.1