From 2e8120a63fd545e66e9e83cfde8ade80de3d3df0 Mon Sep 17 00:00:00 2001 From: Nick Dimiduk Date: Wed, 17 Jun 2020 15:47:37 -0700 Subject: [PATCH] HBASE-24583 Normalizer can't actually merge empty regions... when neighbor is larger than average size * add `testMergeEmptyRegions` to explicitly cover different interleaving of 0-sized regions. * fix bug where merging a 0-size region is skipped due to large neighbor. * remove unused `splitPoint` from `SplitNormalizationPlan`. * generate `toString`, `hashCode`, and `equals` methods from Apache Commons Lang3 template on `SplitNormalizationPlan` and `MergeNormalizationPlan`. * simplify test to use equality matching over `*NormalizationPlan` instances as plain pojos. * test make use of this handy `TableNameTestRule`. * fix line-length issues in `TestSimpleRegionNormalizer` Signed-off-by: Wellington Chevreuil Signed-off-by: Viraj Jasani Signed-off-by: huaxiangsun Signed-off-by: Aman Poonia --- .../hadoop/hbase/TableNameTestRule.java | 3 +- .../normalizer/MergeNormalizationPlan.java | 44 ++++-- .../normalizer/SimpleRegionNormalizer.java | 5 +- .../normalizer/SplitNormalizationPlan.java | 61 ++++---- .../TestSimpleRegionNormalizer.java | 145 +++++++++--------- 5 files changed, 144 insertions(+), 114 deletions(-) diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/TableNameTestRule.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/TableNameTestRule.java index 626c67ee242..ca7d446f31d 100644 --- a/hbase-common/src/test/java/org/apache/hadoop/hbase/TableNameTestRule.java +++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/TableNameTestRule.java @@ -21,7 +21,8 @@ import org.junit.rules.TestWatcher; import org.junit.runner.Description; /** - * Returns a {@code TableName} based on currently running test method name. + * Returns a {@code TableName} based on currently running test method name. Supports + * tests built on the {@link org.junit.runners.Parameterized} runner. */ public class TableNameTestRule extends TestWatcher { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/MergeNormalizationPlan.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/MergeNormalizationPlan.java index 8f8a43f7e21..17e313047d7 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/MergeNormalizationPlan.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/MergeNormalizationPlan.java @@ -1,4 +1,4 @@ -/** +/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -19,20 +19,20 @@ package org.apache.hadoop.hbase.master.normalizer; import java.io.IOException; - +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.client.RegionInfo; import org.apache.hadoop.hbase.master.MasterServices; import org.apache.yetus.audience.InterfaceAudience; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Normalization plan to merge regions (smallest region in the table with its smallest neighbor). */ @InterfaceAudience.Private public class MergeNormalizationPlan implements NormalizationPlan { - private static final Logger LOG = LoggerFactory.getLogger(MergeNormalizationPlan.class.getName()); private final RegionInfo firstRegion; private final RegionInfo secondRegion; @@ -47,7 +47,6 @@ public class MergeNormalizationPlan implements NormalizationPlan { */ @Override public long submit(MasterServices masterServices) throws IOException { - LOG.info("Executing merging normalization plan: " + this); // Do not use force=true as corner cases can happen, non adjacent regions, // merge with a merged child region with no GC done yet, it is going to // cause all different issues. @@ -71,10 +70,35 @@ public class MergeNormalizationPlan implements NormalizationPlan { @Override public String toString() { - return "MergeNormalizationPlan{" + - "firstRegion=" + firstRegion + - ", secondRegion=" + secondRegion + - '}'; + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append("firstRegion", firstRegion) + .append("secondRegion", secondRegion) + .toString(); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + MergeNormalizationPlan that = (MergeNormalizationPlan) o; + + return new EqualsBuilder() + .append(firstRegion, that.firstRegion) + .append(secondRegion, that.secondRegion) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(firstRegion) + .append(secondRegion) + .toHashCode(); + } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SimpleRegionNormalizer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SimpleRegionNormalizer.java index 525c404517c..a904e17f7b0 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SimpleRegionNormalizer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SimpleRegionNormalizer.java @@ -369,7 +369,8 @@ public class SimpleRegionNormalizer implements RegionNormalizer { } final long currentSizeMb = getRegionSizeMB(current); final long nextSizeMb = getRegionSizeMB(next); - if (currentSizeMb + nextSizeMb < avgRegionSizeMb) { + // always merge away empty regions when they present themselves. + if (currentSizeMb == 0 || nextSizeMb == 0 || currentSizeMb + nextSizeMb < avgRegionSizeMb) { plans.add(new MergeNormalizationPlan(current, next)); candidateIdx++; } @@ -411,7 +412,7 @@ public class SimpleRegionNormalizer implements RegionNormalizer { if (regionSize > 2 * avgRegionSize) { LOG.info("Table {}, large region {} has size {}, more than twice avg size {}, splitting", ctx.getTableName(), hri.getRegionNameAsString(), regionSize, avgRegionSize); - plans.add(new SplitNormalizationPlan(hri, null)); + plans.add(new SplitNormalizationPlan(hri)); } } return plans; diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SplitNormalizationPlan.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SplitNormalizationPlan.java index 67008b8fed3..7c634fbf248 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SplitNormalizationPlan.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SplitNormalizationPlan.java @@ -1,4 +1,4 @@ -/** +/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -19,35 +19,31 @@ package org.apache.hadoop.hbase.master.normalizer; import java.io.IOException; -import java.util.Arrays; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.client.RegionInfo; import org.apache.hadoop.hbase.master.MasterServices; import org.apache.yetus.audience.InterfaceAudience; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Normalization plan to split region. */ @InterfaceAudience.Private public class SplitNormalizationPlan implements NormalizationPlan { - private static final Logger LOG = LoggerFactory.getLogger(SplitNormalizationPlan.class.getName()); - private RegionInfo regionInfo; - private byte[] splitPoint; + private final RegionInfo regionInfo; - public SplitNormalizationPlan(RegionInfo regionInfo, byte[] splitPoint) { + public SplitNormalizationPlan(RegionInfo regionInfo) { this.regionInfo = regionInfo; - this.splitPoint = splitPoint; } - /** - * {@inheritDoc} - */ @Override public long submit(MasterServices masterServices) throws IOException { - return masterServices.splitRegion(regionInfo, null, HConstants.NO_NONCE, HConstants.NO_NONCE); + return masterServices.splitRegion(regionInfo, null, HConstants.NO_NONCE, + HConstants.NO_NONCE); } @Override @@ -59,24 +55,33 @@ public class SplitNormalizationPlan implements NormalizationPlan { return regionInfo; } - public void setRegionInfo(RegionInfo regionInfo) { - this.regionInfo = regionInfo; - } - - public byte[] getSplitPoint() { - return splitPoint; - } - - public void setSplitPoint(byte[] splitPoint) { - this.splitPoint = splitPoint; + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append("regionInfo", regionInfo) + .toString(); } @Override - public String toString() { - return "SplitNormalizationPlan{" + - "regionInfo=" + regionInfo + - ", splitPoint=" + Arrays.toString(splitPoint) + - '}'; + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + SplitNormalizationPlan that = (SplitNormalizationPlan) o; + + return new EqualsBuilder() + .append(regionInfo, that.regionInfo) + .isEquals(); } + @Override public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(regionInfo) + .toHashCode(); + } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizer.java index eeb9bef0c81..89da907eeb0 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizer.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizer.java @@ -30,11 +30,9 @@ import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.everyItem; import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.iterableWithSize; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.when; @@ -52,6 +50,7 @@ import org.apache.hadoop.hbase.RegionMetrics; import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.Size; import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.TableNameTestRule; import org.apache.hadoop.hbase.client.RegionInfo; import org.apache.hadoop.hbase.client.RegionInfoBuilder; import org.apache.hadoop.hbase.master.MasterServices; @@ -65,7 +64,6 @@ import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.rules.TestName; import org.mockito.Mockito; /** @@ -83,7 +81,7 @@ public class TestSimpleRegionNormalizer { private MasterServices masterServices; @Rule - public TestName name = new TestName(); + public TableNameTestRule name = new TableNameTestRule(); @Before public void before() { @@ -103,7 +101,7 @@ public class TestSimpleRegionNormalizer { @Test public void testNoNormalizationIfTooFewRegions() { - final TableName tableName = TableName.valueOf(name.getMethodName()); + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 2); final Map regionSizes = createRegionSizesMap(regionInfos, 10, 15); setupMocksForNormalizer(regionSizes, regionInfos); @@ -114,9 +112,10 @@ public class TestSimpleRegionNormalizer { @Test public void testNoNormalizationOnNormalizedCluster() { - final TableName tableName = TableName.valueOf(name.getMethodName()); + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 4); - final Map regionSizes = createRegionSizesMap(regionInfos, 10, 15, 8, 10); + final Map regionSizes = + createRegionSizesMap(regionInfos, 10, 15, 8, 10); setupMocksForNormalizer(regionSizes, regionInfos); List plans = normalizer.computePlansForTable(tableName); @@ -124,7 +123,7 @@ public class TestSimpleRegionNormalizer { } private void noNormalizationOnTransitioningRegions(final RegionState.State state) { - final TableName tableName = TableName.valueOf(name.getMethodName()); + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 3); final Map regionSizes = createRegionSizesMap(regionInfos, 10, 1, 100); @@ -170,38 +169,33 @@ public class TestSimpleRegionNormalizer { @Test public void testMergeOfSmallRegions() { - final TableName tableName = TableName.valueOf(name.getMethodName()); + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 5); final Map regionSizes = createRegionSizesMap(regionInfos, 15, 5, 5, 15, 16); setupMocksForNormalizer(regionSizes, regionInfos); - List plans = normalizer.computePlansForTable(tableName); - assertThat(plans.get(0), instanceOf(MergeNormalizationPlan.class)); - MergeNormalizationPlan plan = (MergeNormalizationPlan) plans.get(0); - assertEquals(regionInfos.get(1), plan.getFirstRegion()); - assertEquals(regionInfos.get(2), plan.getSecondRegion()); + assertThat(normalizer.computePlansForTable(tableName), contains( + new MergeNormalizationPlan(regionInfos.get(1), regionInfos.get(2)))); } // Test for situation illustrated in HBASE-14867 @Test public void testMergeOfSecondSmallestRegions() { - final TableName tableName = TableName.valueOf(name.getMethodName()); + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 6); final Map regionSizes = createRegionSizesMap(regionInfos, 1, 10000, 10000, 10000, 2700, 2700); setupMocksForNormalizer(regionSizes, regionInfos); - List plans = normalizer.computePlansForTable(tableName); - assertThat(plans.get(0), instanceOf(MergeNormalizationPlan.class)); - MergeNormalizationPlan plan = (MergeNormalizationPlan) plans.get(0); - assertEquals(regionInfos.get(4), plan.getFirstRegion()); - assertEquals(regionInfos.get(5), plan.getSecondRegion()); + assertThat(normalizer.computePlansForTable(tableName), contains( + new MergeNormalizationPlan(regionInfos.get(4), regionInfos.get(5)) + )); } @Test public void testMergeOfSmallNonAdjacentRegions() { - final TableName tableName = TableName.valueOf(name.getMethodName()); + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 5); final Map regionSizes = createRegionSizesMap(regionInfos, 15, 5, 16, 15, 5); @@ -213,21 +207,19 @@ public class TestSimpleRegionNormalizer { @Test public void testSplitOfLargeRegion() { - final TableName tableName = TableName.valueOf(name.getMethodName()); + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 4); final Map regionSizes = createRegionSizesMap(regionInfos, 8, 6, 10, 30); setupMocksForNormalizer(regionSizes, regionInfos); - List plans = normalizer.computePlansForTable(tableName); - assertThat(plans.get(0), instanceOf(SplitNormalizationPlan.class)); - SplitNormalizationPlan plan = (SplitNormalizationPlan) plans.get(0); - assertEquals(regionInfos.get(3), plan.getRegionInfo()); + assertThat(normalizer.computePlansForTable(tableName), contains( + new SplitNormalizationPlan(regionInfos.get(3)))); } @Test - public void testSplitWithTargetRegionCount() throws Exception { - final TableName tableName = TableName.valueOf(name.getMethodName()); + public void testSplitWithTargetRegionSize() throws Exception { + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 6); final Map regionSizes = createRegionSizesMap(regionInfos, 20, 40, 60, 80, 100, 120); @@ -236,49 +228,47 @@ public class TestSimpleRegionNormalizer { // test when target region size is 20 when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionSize()) .thenReturn(20L); - List plans = normalizer.computePlansForTable(tableName); - assertThat(plans, iterableWithSize(4)); - assertThat(plans, everyItem(instanceOf(SplitNormalizationPlan.class))); + assertThat(normalizer.computePlansForTable(tableName), contains( + new SplitNormalizationPlan(regionInfos.get(2)), + new SplitNormalizationPlan(regionInfos.get(3)), + new SplitNormalizationPlan(regionInfos.get(4)), + new SplitNormalizationPlan(regionInfos.get(5)) + )); // test when target region size is 200 when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionSize()) .thenReturn(200L); - plans = normalizer.computePlansForTable(tableName); - assertThat(plans, iterableWithSize(2)); - assertTrue(plans.get(0) instanceof MergeNormalizationPlan); - MergeNormalizationPlan plan = (MergeNormalizationPlan) plans.get(0); - assertEquals(regionInfos.get(0), plan.getFirstRegion()); - assertEquals(regionInfos.get(1), plan.getSecondRegion()); + assertThat(normalizer.computePlansForTable(tableName), contains( + new MergeNormalizationPlan(regionInfos.get(0), regionInfos.get(1)), + new MergeNormalizationPlan(regionInfos.get(2), regionInfos.get(3)))); } @Test - public void testSplitWithTargetRegionSize() throws Exception { - final TableName tableName = TableName.valueOf(name.getMethodName()); + public void testSplitWithTargetRegionCount() throws Exception { + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 4); - final Map regionSizes = createRegionSizesMap(regionInfos, 20, 40, 60, 80); + final Map regionSizes = + createRegionSizesMap(regionInfos, 20, 40, 60, 80); setupMocksForNormalizer(regionSizes, regionInfos); // test when target region count is 8 when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionCount()) .thenReturn(8); - List plans = normalizer.computePlansForTable(tableName); - assertThat(plans, iterableWithSize(2)); - assertThat(plans, everyItem(instanceOf(SplitNormalizationPlan.class))); + assertThat(normalizer.computePlansForTable(tableName), contains( + new SplitNormalizationPlan(regionInfos.get(2)), + new SplitNormalizationPlan(regionInfos.get(3)))); // test when target region count is 3 when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionCount()) .thenReturn(3); - plans = normalizer.computePlansForTable(tableName); - assertThat(plans, contains(instanceOf(MergeNormalizationPlan.class))); - MergeNormalizationPlan plan = (MergeNormalizationPlan) plans.get(0); - assertEquals(regionInfos.get(0), plan.getFirstRegion()); - assertEquals(regionInfos.get(1), plan.getSecondRegion()); + assertThat(normalizer.computePlansForTable(tableName), contains( + new MergeNormalizationPlan(regionInfos.get(0), regionInfos.get(1)))); } @Test public void testHonorsSplitEnabled() { conf.setBoolean(SPLIT_ENABLED_KEY, true); - final TableName tableName = TableName.valueOf(name.getMethodName()); + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 5); final Map regionSizes = createRegionSizesMap(regionInfos, 5, 5, 20, 5, 5); @@ -295,7 +285,7 @@ public class TestSimpleRegionNormalizer { @Test public void testHonorsMergeEnabled() { conf.setBoolean(MERGE_ENABLED_KEY, true); - final TableName tableName = TableName.valueOf(name.getMethodName()); + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 5); final Map regionSizes = createRegionSizesMap(regionInfos, 20, 5, 5, 20, 20); @@ -312,7 +302,7 @@ public class TestSimpleRegionNormalizer { @Test public void testHonorsMinimumRegionCount() { conf.setInt(MIN_REGION_COUNT_KEY, 1); - final TableName tableName = TableName.valueOf(name.getMethodName()); + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 3); // create a table topology that results in both a merge plan and a split plan. Assert that the // merge is only created when the when the number of table regions is above the region count @@ -322,27 +312,20 @@ public class TestSimpleRegionNormalizer { List plans = normalizer.computePlansForTable(tableName); assertThat(plans, contains( - instanceOf(SplitNormalizationPlan.class), - instanceOf(MergeNormalizationPlan.class))); - SplitNormalizationPlan splitPlan = (SplitNormalizationPlan) plans.get(0); - assertEquals(regionInfos.get(2), splitPlan.getRegionInfo()); - MergeNormalizationPlan mergePlan = (MergeNormalizationPlan) plans.get(1); - assertEquals(regionInfos.get(0), mergePlan.getFirstRegion()); - assertEquals(regionInfos.get(1), mergePlan.getSecondRegion()); + new SplitNormalizationPlan(regionInfos.get(2)), + new MergeNormalizationPlan(regionInfos.get(0), regionInfos.get(1)))); // have to call setupMocks again because we don't have dynamic config update on normalizer. conf.setInt(MIN_REGION_COUNT_KEY, 4); setupMocksForNormalizer(regionSizes, regionInfos); - plans = normalizer.computePlansForTable(tableName); - assertThat(plans, contains(instanceOf(SplitNormalizationPlan.class))); - splitPlan = (SplitNormalizationPlan) plans.get(0); - assertEquals(regionInfos.get(2), splitPlan.getRegionInfo()); + assertThat(normalizer.computePlansForTable(tableName), contains( + new SplitNormalizationPlan(regionInfos.get(2)))); } @Test public void testHonorsMergeMinRegionAge() { conf.setInt(MERGE_MIN_REGION_AGE_DAYS_KEY, 7); - final TableName tableName = TableName.valueOf(name.getMethodName()); + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 4); final Map regionSizes = createRegionSizesMap(regionInfos, 1, 1, 10, 10); @@ -365,19 +348,16 @@ public class TestSimpleRegionNormalizer { @Test public void testHonorsMergeMinRegionSize() { conf.setBoolean(SPLIT_ENABLED_KEY, false); - final TableName tableName = TableName.valueOf(name.getMethodName()); + final TableName tableName = name.getTableName(); final List regionInfos = createRegionInfos(tableName, 5); - final Map regionSizes = createRegionSizesMap(regionInfos, 1, 2, 0, 10, 10); + final Map regionSizes = + createRegionSizesMap(regionInfos, 1, 2, 0, 10, 10); setupMocksForNormalizer(regionSizes, regionInfos); assertFalse(normalizer.isSplitEnabled()); assertEquals(1, normalizer.getMergeMinRegionSizeMb()); - final List plans = normalizer.computePlansForTable(tableName); - assertThat(plans, everyItem(instanceOf(MergeNormalizationPlan.class))); - assertThat(plans, iterableWithSize(1)); - final MergeNormalizationPlan plan = (MergeNormalizationPlan) plans.get(0); - assertEquals(regionInfos.get(0), plan.getFirstRegion()); - assertEquals(regionInfos.get(1), plan.getSecondRegion()); + assertThat(normalizer.computePlansForTable(tableName), contains( + new MergeNormalizationPlan(regionInfos.get(0), regionInfos.get(1)))); conf.setInt(MERGE_MIN_REGION_SIZE_MB_KEY, 3); setupMocksForNormalizer(regionSizes, regionInfos); @@ -385,10 +365,28 @@ public class TestSimpleRegionNormalizer { assertThat(normalizer.computePlansForTable(tableName), empty()); } + @Test + public void testMergeEmptyRegions() { + conf.setBoolean(SPLIT_ENABLED_KEY, false); + conf.setInt(MERGE_MIN_REGION_SIZE_MB_KEY, 0); + final TableName tableName = name.getTableName(); + final List regionInfos = createRegionInfos(tableName, 7); + final Map regionSizes = + createRegionSizesMap(regionInfos, 0, 1, 10, 0, 9, 10, 0); + setupMocksForNormalizer(regionSizes, regionInfos); + + assertFalse(normalizer.isSplitEnabled()); + assertEquals(0, normalizer.getMergeMinRegionSizeMb()); + assertThat(normalizer.computePlansForTable(tableName), contains( + new MergeNormalizationPlan(regionInfos.get(0), regionInfos.get(1)), + new MergeNormalizationPlan(regionInfos.get(2), regionInfos.get(3)), + new MergeNormalizationPlan(regionInfos.get(5), regionInfos.get(6)))); + } + // This test is to make sure that normalizer is only going to merge adjacent regions. @Test public void testNormalizerCannotMergeNonAdjacentRegions() { - final TableName tableName = TableName.valueOf(name.getMethodName()); + final TableName tableName = name.getTableName(); // create 5 regions with sizes to trigger merge of small regions. region ranges are: // [, "aa"), ["aa", "aa1"), ["aa1", "aa1!"), ["aa1!", "aa2"), ["aa2", ) // Region ["aa", "aa1") and ["aa1!", "aa2") are not adjacent, they are not supposed to @@ -402,7 +400,8 @@ public class TestSimpleRegionNormalizer { null, }; final List regionInfos = createRegionInfos(tableName, keys); - final Map regionSizes = createRegionSizesMap(regionInfos, 3, 1, 1, 3, 5); + final Map regionSizes = + createRegionSizesMap(regionInfos, 3, 1, 1, 3, 5); setupMocksForNormalizer(regionSizes, regionInfos); // Compute the plan, no merge plan returned as they are not adjacent.