ndimiduk commented on a change in pull request #1786: URL: https://github.com/apache/hbase/pull/1786#discussion_r431442449
########## File path: hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizer.java ########## @@ -69,517 +78,347 @@ public static final HBaseClassTestRule CLASS_RULE = HBaseClassTestRule.forClass(TestSimpleRegionNormalizer.class); - private static final Logger LOG = LoggerFactory.getLogger(TestSimpleRegionNormalizer.class); - - private RegionNormalizer normalizer; + private Configuration conf; + private SimpleRegionNormalizer normalizer; private MasterServices masterServices; @Rule public TestName name = new TestName(); - @Test - public void testPlanComparator() { - Comparator<NormalizationPlan> comparator = new SimpleRegionNormalizer.PlanComparator(); - NormalizationPlan splitPlan1 = new SplitNormalizationPlan(null, null); - NormalizationPlan splitPlan2 = new SplitNormalizationPlan(null, null); - NormalizationPlan mergePlan1 = new MergeNormalizationPlan(null, null); - NormalizationPlan mergePlan2 = new MergeNormalizationPlan(null, null); - - assertEquals(0, comparator.compare(splitPlan1, splitPlan2)); - assertEquals(0, comparator.compare(splitPlan2, splitPlan1)); - assertEquals(0, comparator.compare(mergePlan1, mergePlan2)); - assertEquals(0, comparator.compare(mergePlan2, mergePlan1)); - assertTrue(comparator.compare(splitPlan1, mergePlan1) < 0); - assertTrue(comparator.compare(mergePlan1, splitPlan1) > 0); + @Before + public void before() { + conf = HBaseConfiguration.create(); } @Test - public void testNoNormalizationForMetaTable() throws HBaseIOException { + public void testNoNormalizationForMetaTable() { TableName testTable = TableName.META_TABLE_NAME; List<RegionInfo> RegionInfo = new ArrayList<>(); Map<byte[], Integer> regionSizes = new HashMap<>(); setupMocksForNormalizer(regionSizes, RegionInfo); - List<NormalizationPlan> plans = normalizer.computePlanForTable(testTable); - assertNull(plans); + List<NormalizationPlan> plans = normalizer.computePlansForTable(testTable); + assertThat(plans, empty()); } @Test - public void testNoNormalizationIfTooFewRegions() throws HBaseIOException { + public void testNoNormalizationIfTooFewRegions() { final TableName tableName = TableName.valueOf(name.getMethodName()); - List<RegionInfo> RegionInfo = new ArrayList<>(); - Map<byte[], Integer> regionSizes = new HashMap<>(); - RegionInfo hri1 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("aaa")) - .setEndKey(Bytes.toBytes("bbb")) - .build(); - RegionInfo.add(hri1); - regionSizes.put(hri1.getRegionName(), 10); - - RegionInfo hri2 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("bbb")) - .setEndKey(Bytes.toBytes("ccc")) - .build(); - RegionInfo.add(hri2); - regionSizes.put(hri2.getRegionName(), 15); + final List<RegionInfo> regionInfos = createRegionInfos(tableName, 2); + final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 10, 15); + setupMocksForNormalizer(regionSizes, regionInfos); - setupMocksForNormalizer(regionSizes, RegionInfo); - List<NormalizationPlan> plans = normalizer.computePlanForTable(tableName); - assertNull(plans); + List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); + assertThat(plans, empty()); } @Test - public void testNoNormalizationOnNormalizedCluster() throws HBaseIOException { + public void testNoNormalizationOnNormalizedCluster() { final TableName tableName = TableName.valueOf(name.getMethodName()); - List<RegionInfo> RegionInfo = new ArrayList<>(); - Map<byte[], Integer> regionSizes = new HashMap<>(); - - RegionInfo hri1 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("aaa")) - .setEndKey(Bytes.toBytes("bbb")) - .build(); - RegionInfo.add(hri1); - regionSizes.put(hri1.getRegionName(), 10); - - RegionInfo hri2 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("bbb")) - .setEndKey(Bytes.toBytes("ccc")) - .build(); - RegionInfo.add(hri2); - regionSizes.put(hri2.getRegionName(), 15); - - RegionInfo hri3 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("ccc")) - .setEndKey(Bytes.toBytes("ddd")) - .build(); - RegionInfo.add(hri3); - regionSizes.put(hri3.getRegionName(), 8); - - RegionInfo hri4 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("ddd")) - .setEndKey(Bytes.toBytes("eee")) - .build(); - regionSizes.put(hri4.getRegionName(), 10); + final List<RegionInfo> regionInfos = createRegionInfos(tableName, 4); + final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 10, 15, 8, 10); + setupMocksForNormalizer(regionSizes, regionInfos); - setupMocksForNormalizer(regionSizes, RegionInfo); - List<NormalizationPlan> plans = normalizer.computePlanForTable(tableName); - assertNull(plans); + List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); + assertThat(plans, empty()); } - private void noNormalizationOnTransitioningRegions(final RegionState.State state) - throws Exception { + private void noNormalizationOnTransitioningRegions(final RegionState.State state) { final TableName tableName = TableName.valueOf(name.getMethodName()); - final List<RegionInfo> regionInfos = new LinkedList<>(); - final Map<byte[], Integer> regionSizes = new HashMap<>(); - - final RegionInfo ri1 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("aaa")) - .setEndKey(Bytes.toBytes("bbb")) - .build(); - regionInfos.add(ri1); - regionSizes.put(ri1.getRegionName(), 10); - - final RegionInfo ri2 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("bbb")) - .setEndKey(Bytes.toBytes("ccc")) - .build(); - regionInfos.add(ri2); - regionSizes.put(ri2.getRegionName(), 1); + final List<RegionInfo> regionInfos = createRegionInfos(tableName, 3); + final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 10, 1, 100); setupMocksForNormalizer(regionSizes, regionInfos); when(masterServices.getAssignmentManager().getRegionStates() - .getRegionState(any(RegionInfo.class))).thenReturn( - RegionState.createForTesting(null, state)); - assertNull( - format("Unexpected plans for RegionState %s", state), - normalizer.computePlanForTable(tableName)); + .getRegionState(any(RegionInfo.class))) + .thenReturn(RegionState.createForTesting(null, state)); + assertThat(normalizer.getMinRegionCount(), greaterThanOrEqualTo(regionInfos.size())); + + List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); + assertThat(format("Unexpected plans for RegionState %s", state), plans, empty()); } @Test - public void testNoNormalizationOnMergingNewRegions() throws Exception { + public void testNoNormalizationOnMergingNewRegions() { noNormalizationOnTransitioningRegions(RegionState.State.MERGING_NEW); } @Test - public void testNoNormalizationOnMergingRegions() throws Exception { + public void testNoNormalizationOnMergingRegions() { noNormalizationOnTransitioningRegions(RegionState.State.MERGING); } @Test - public void testNoNormalizationOnMergedRegions() throws Exception { + public void testNoNormalizationOnMergedRegions() { noNormalizationOnTransitioningRegions(RegionState.State.MERGED); } @Test - public void testNoNormalizationOnSplittingNewRegions() throws Exception { + public void testNoNormalizationOnSplittingNewRegions() { noNormalizationOnTransitioningRegions(RegionState.State.SPLITTING_NEW); } @Test - public void testNoNormalizationOnSplittingRegions() throws Exception { + public void testNoNormalizationOnSplittingRegions() { noNormalizationOnTransitioningRegions(RegionState.State.SPLITTING); } @Test - public void testNoNormalizationOnSplitRegions() throws Exception { + public void testNoNormalizationOnSplitRegions() { noNormalizationOnTransitioningRegions(RegionState.State.SPLIT); } @Test - public void testMergeOfSmallRegions() throws HBaseIOException { + public void testMergeOfSmallRegions() { final TableName tableName = TableName.valueOf(name.getMethodName()); - List<RegionInfo> RegionInfo = new ArrayList<>(); - Map<byte[], Integer> regionSizes = new HashMap<>(); - - RegionInfo hri1 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("aaa")) - .setEndKey(Bytes.toBytes("bbb")) - .build(); - RegionInfo.add(hri1); - regionSizes.put(hri1.getRegionName(), 15); - - RegionInfo hri2 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("bbb")) - .setEndKey(Bytes.toBytes("ccc")) - .build(); - RegionInfo.add(hri2); - regionSizes.put(hri2.getRegionName(), 5); - - RegionInfo hri3 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("ccc")) - .setEndKey(Bytes.toBytes("ddd")) - .build(); - RegionInfo.add(hri3); - regionSizes.put(hri3.getRegionName(), 5); - - RegionInfo hri4 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("ddd")) - .setEndKey(Bytes.toBytes("eee")) - .build(); - RegionInfo.add(hri4); - regionSizes.put(hri4.getRegionName(), 15); - - RegionInfo hri5 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("eee")) - .setEndKey(Bytes.toBytes("fff")) - .build(); - RegionInfo.add(hri5); - regionSizes.put(hri5.getRegionName(), 16); - - setupMocksForNormalizer(regionSizes, RegionInfo); - List<NormalizationPlan> plans = normalizer.computePlanForTable(tableName); + final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5); + final Map<byte[], Integer> regionSizes = + createRegionSizesMap(regionInfos, 15, 5, 5, 15, 16); + setupMocksForNormalizer(regionSizes, regionInfos); - NormalizationPlan plan = plans.get(0); - assertTrue(plan instanceof MergeNormalizationPlan); - assertEquals(hri2, ((MergeNormalizationPlan) plan).getFirstRegion()); - assertEquals(hri3, ((MergeNormalizationPlan) plan).getSecondRegion()); + List<NormalizationPlan> 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()); } // Test for situation illustrated in HBASE-14867 @Test - public void testMergeOfSecondSmallestRegions() throws HBaseIOException { + public void testMergeOfSecondSmallestRegions() { final TableName tableName = TableName.valueOf(name.getMethodName()); - List<RegionInfo> RegionInfo = new ArrayList<>(); - Map<byte[], Integer> regionSizes = new HashMap<>(); - - RegionInfo hri1 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("aaa")) - .setEndKey(Bytes.toBytes("bbb")) - .build(); - RegionInfo.add(hri1); - regionSizes.put(hri1.getRegionName(), 1); - - RegionInfo hri2 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("bbb")) - .setEndKey(Bytes.toBytes("ccc")) - .build(); - RegionInfo.add(hri2); - regionSizes.put(hri2.getRegionName(), 10000); - - RegionInfo hri3 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("ccc")) - .setEndKey(Bytes.toBytes("ddd")) - .build(); - RegionInfo.add(hri3); - regionSizes.put(hri3.getRegionName(), 10000); - - RegionInfo hri4 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("ddd")) - .setEndKey(Bytes.toBytes("eee")) - .build(); - RegionInfo.add(hri4); - regionSizes.put(hri4.getRegionName(), 10000); - - RegionInfo hri5 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("eee")) - .setEndKey(Bytes.toBytes("fff")) - .build(); - RegionInfo.add(hri5); - regionSizes.put(hri5.getRegionName(), 2700); - - RegionInfo hri6 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("fff")) - .setEndKey(Bytes.toBytes("ggg")) - .build(); - RegionInfo.add(hri6); - regionSizes.put(hri6.getRegionName(), 2700); - - setupMocksForNormalizer(regionSizes, RegionInfo); - List<NormalizationPlan> plans = normalizer.computePlanForTable(tableName); - NormalizationPlan plan = plans.get(0); + final List<RegionInfo> regionInfos = createRegionInfos(tableName, 6); + final Map<byte[], Integer> regionSizes = + createRegionSizesMap(regionInfos, 1, 10000, 10000, 10000, 2700, 2700); + setupMocksForNormalizer(regionSizes, regionInfos); - assertTrue(plan instanceof MergeNormalizationPlan); - assertEquals(hri5, ((MergeNormalizationPlan) plan).getFirstRegion()); - assertEquals(hri6, ((MergeNormalizationPlan) plan).getSecondRegion()); + List<NormalizationPlan> 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()); } @Test - public void testMergeOfSmallNonAdjacentRegions() throws HBaseIOException { + public void testMergeOfSmallNonAdjacentRegions() { final TableName tableName = TableName.valueOf(name.getMethodName()); - List<RegionInfo> RegionInfo = new ArrayList<>(); - Map<byte[], Integer> regionSizes = new HashMap<>(); - - RegionInfo hri1 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("aaa")) - .setEndKey(Bytes.toBytes("bbb")) - .build(); - RegionInfo.add(hri1); - regionSizes.put(hri1.getRegionName(), 15); - - RegionInfo hri2 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("bbb")) - .setEndKey(Bytes.toBytes("ccc")) - .build(); - RegionInfo.add(hri2); - regionSizes.put(hri2.getRegionName(), 5); - - RegionInfo hri3 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("ccc")) - .setEndKey(Bytes.toBytes("ddd")) - .build(); - RegionInfo.add(hri3); - regionSizes.put(hri3.getRegionName(), 16); - - RegionInfo hri4 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("ddd")) - .setEndKey(Bytes.toBytes("eee")) - .build(); - RegionInfo.add(hri4); - regionSizes.put(hri4.getRegionName(), 15); - - RegionInfo hri5 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("ddd")) - .setEndKey(Bytes.toBytes("eee")) - .build(); - RegionInfo.add(hri4); - regionSizes.put(hri5.getRegionName(), 5); - - setupMocksForNormalizer(regionSizes, RegionInfo); - List<NormalizationPlan> plans = normalizer.computePlanForTable(tableName); + final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5); + final Map<byte[], Integer> regionSizes = + createRegionSizesMap(regionInfos, 15, 5, 16, 15, 5); + setupMocksForNormalizer(regionSizes, regionInfos); - assertNull(plans); + List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); + assertThat(plans, empty()); } @Test - public void testSplitOfLargeRegion() throws HBaseIOException { + public void testSplitOfLargeRegion() { final TableName tableName = TableName.valueOf(name.getMethodName()); - List<RegionInfo> RegionInfo = new ArrayList<>(); - Map<byte[], Integer> regionSizes = new HashMap<>(); - - RegionInfo hri1 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("aaa")) - .setEndKey(Bytes.toBytes("bbb")) - .build(); - RegionInfo.add(hri1); - regionSizes.put(hri1.getRegionName(), 8); - - RegionInfo hri2 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("bbb")) - .setEndKey(Bytes.toBytes("ccc")) - .build(); - RegionInfo.add(hri2); - regionSizes.put(hri2.getRegionName(), 6); - - RegionInfo hri3 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("ccc")) - .setEndKey(Bytes.toBytes("ddd")) - .build(); - RegionInfo.add(hri3); - regionSizes.put(hri3.getRegionName(), 10); - - RegionInfo hri4 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("ddd")) - .setEndKey(Bytes.toBytes("eee")) - .build(); - RegionInfo.add(hri4); - regionSizes.put(hri4.getRegionName(), 30); - - setupMocksForNormalizer(regionSizes, RegionInfo); - List<NormalizationPlan> plans = normalizer.computePlanForTable(tableName); - NormalizationPlan plan = plans.get(0); + final List<RegionInfo> regionInfos = createRegionInfos(tableName, 4); + final Map<byte[], Integer> regionSizes = + createRegionSizesMap(regionInfos, 8, 6, 10, 30); + setupMocksForNormalizer(regionSizes, regionInfos); - assertTrue(plan instanceof SplitNormalizationPlan); - assertEquals(hri4, ((SplitNormalizationPlan) plan).getRegionInfo()); + List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); + assertThat(plans.get(0), instanceOf(SplitNormalizationPlan.class)); + SplitNormalizationPlan plan = (SplitNormalizationPlan) plans.get(0); + assertEquals(regionInfos.get(3), plan.getRegionInfo()); } @Test public void testSplitWithTargetRegionCount() throws Exception { final TableName tableName = TableName.valueOf(name.getMethodName()); - List<RegionInfo> RegionInfo = new ArrayList<>(); - Map<byte[], Integer> regionSizes = new HashMap<>(); - - RegionInfo hri1 = RegionInfoBuilder.newBuilder(tableName).setStartKey(Bytes.toBytes("aaa")) - .setEndKey(Bytes.toBytes("bbb")).build(); - RegionInfo.add(hri1); - regionSizes.put(hri1.getRegionName(), 20); - - RegionInfo hri2 = RegionInfoBuilder.newBuilder(tableName).setStartKey(Bytes.toBytes("bbb")) - .setEndKey(Bytes.toBytes("ccc")).build(); - RegionInfo.add(hri2); - regionSizes.put(hri2.getRegionName(), 40); - - RegionInfo hri3 = RegionInfoBuilder.newBuilder(tableName).setStartKey(Bytes.toBytes("ccc")) - .setEndKey(Bytes.toBytes("ddd")).build(); - RegionInfo.add(hri3); - regionSizes.put(hri3.getRegionName(), 60); - - RegionInfo hri4 = RegionInfoBuilder.newBuilder(tableName).setStartKey(Bytes.toBytes("ddd")) - .setEndKey(Bytes.toBytes("eee")).build(); - RegionInfo.add(hri4); - regionSizes.put(hri4.getRegionName(), 80); - - RegionInfo hri5 = RegionInfoBuilder.newBuilder(tableName).setStartKey(Bytes.toBytes("eee")) - .setEndKey(Bytes.toBytes("fff")).build(); - RegionInfo.add(hri5); - regionSizes.put(hri5.getRegionName(), 100); - - RegionInfo hri6 = RegionInfoBuilder.newBuilder(tableName).setStartKey(Bytes.toBytes("fff")) - .setEndKey(Bytes.toBytes("ggg")).build(); - RegionInfo.add(hri6); - regionSizes.put(hri6.getRegionName(), 120); - - setupMocksForNormalizer(regionSizes, RegionInfo); + final List<RegionInfo> regionInfos = createRegionInfos(tableName, 6); + final Map<byte[], Integer> regionSizes = + createRegionSizesMap(regionInfos, 20, 40, 60, 80, 100, 120); + setupMocksForNormalizer(regionSizes, regionInfos); // test when target region size is 20 when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionSize()) .thenReturn(20L); - List<NormalizationPlan> plans = normalizer.computePlanForTable(tableName); - assertEquals(4, plans.size()); - - for (NormalizationPlan plan : plans) { - assertTrue(plan instanceof SplitNormalizationPlan); - } + List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); + assertThat(plans, iterableWithSize(4)); + assertThat(plans, everyItem(instanceOf(SplitNormalizationPlan.class))); // test when target region size is 200 when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionSize()) .thenReturn(200L); - plans = normalizer.computePlanForTable(tableName); - assertEquals(2, plans.size()); - NormalizationPlan plan = plans.get(0); - assertTrue(plan instanceof MergeNormalizationPlan); - assertEquals(hri1, ((MergeNormalizationPlan) plan).getFirstRegion()); - assertEquals(hri2, ((MergeNormalizationPlan) plan).getSecondRegion()); + 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()); } @Test public void testSplitWithTargetRegionSize() throws Exception { final TableName tableName = TableName.valueOf(name.getMethodName()); - List<RegionInfo> RegionInfo = new ArrayList<>(); - Map<byte[], Integer> regionSizes = new HashMap<>(); - - RegionInfo hri1 = RegionInfoBuilder.newBuilder(tableName).setStartKey(Bytes.toBytes("aaa")) - .setEndKey(Bytes.toBytes("bbb")).build(); - RegionInfo.add(hri1); - regionSizes.put(hri1.getRegionName(), 20); - - RegionInfo hri2 = RegionInfoBuilder.newBuilder(tableName).setStartKey(Bytes.toBytes("bbb")) - .setEndKey(Bytes.toBytes("ccc")).build(); - RegionInfo.add(hri2); - regionSizes.put(hri2.getRegionName(), 40); - - RegionInfo hri3 = RegionInfoBuilder.newBuilder(tableName).setStartKey(Bytes.toBytes("ccc")) - .setEndKey(Bytes.toBytes("ddd")).build(); - RegionInfo.add(hri3); - regionSizes.put(hri3.getRegionName(), 60); - - RegionInfo hri4 = RegionInfoBuilder.newBuilder(tableName).setStartKey(Bytes.toBytes("ddd")) - .setEndKey(Bytes.toBytes("eee")).build(); - RegionInfo.add(hri4); - regionSizes.put(hri4.getRegionName(), 80); - - setupMocksForNormalizer(regionSizes, RegionInfo); + final List<RegionInfo> regionInfos = createRegionInfos(tableName, 4); + final Map<byte[], Integer> 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<NormalizationPlan> plans = normalizer.computePlanForTable(tableName); - assertEquals(2, plans.size()); - - for (NormalizationPlan plan : plans) { - assertTrue(plan instanceof SplitNormalizationPlan); - } + List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); + assertThat(plans, iterableWithSize(2)); + assertThat(plans, everyItem(instanceOf(SplitNormalizationPlan.class))); // test when target region count is 3 when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionCount()) .thenReturn(3); - plans = normalizer.computePlanForTable(tableName); - assertEquals(1, plans.size()); - NormalizationPlan plan = plans.get(0); - assertTrue(plan instanceof MergeNormalizationPlan); - assertEquals(hri1, ((MergeNormalizationPlan) plan).getFirstRegion()); - assertEquals(hri2, ((MergeNormalizationPlan) plan).getSecondRegion()); + 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()); } @Test - public void testSplitIfTooFewRegions() throws HBaseIOException { + public void testHonorsSplitEnabled() { + conf.setBoolean(SPLIT_ENABLED_KEY, true); final TableName tableName = TableName.valueOf(name.getMethodName()); - List<RegionInfo> RegionInfo = new ArrayList<>(); - Map<byte[], Integer> regionSizes = new HashMap<>(); + final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5); + final Map<byte[], Integer> regionSizes = + createRegionSizesMap(regionInfos, 5, 5, 20, 5, 5); + setupMocksForNormalizer(regionSizes, regionInfos); + assertThat( + normalizer.computePlansForTable(tableName), + contains(instanceOf(SplitNormalizationPlan.class))); + + conf.setBoolean(SPLIT_ENABLED_KEY, false); + setupMocksForNormalizer(regionSizes, regionInfos); + assertThat(normalizer.computePlansForTable(tableName), empty()); + } + + @Test + public void testHonorsMergeEnabled() { + conf.setBoolean(MERGE_ENABLED_KEY, true); + final TableName tableName = TableName.valueOf(name.getMethodName()); + final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5); + final Map<byte[], Integer> regionSizes = + createRegionSizesMap(regionInfos, 20, 5, 5, 20, 20); + setupMocksForNormalizer(regionSizes, regionInfos); + assertThat( + normalizer.computePlansForTable(tableName), + contains(instanceOf(MergeNormalizationPlan.class))); - RegionInfo hri1 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("aaa")) - .setEndKey(Bytes.toBytes("bbb")) - .build(); - RegionInfo.add(hri1); - regionSizes.put(hri1.getRegionName(), 1); - - RegionInfo hri2 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("bbb")) - .setEndKey(Bytes.toBytes("ccc")) - .build(); - RegionInfo.add(hri2); - regionSizes.put(hri2.getRegionName(), 1); - // the third region is huge one - RegionInfo hri3 = RegionInfoBuilder.newBuilder(tableName) - .setStartKey(Bytes.toBytes("ccc")) - .setEndKey(Bytes.toBytes("ddd")) - .build(); - RegionInfo.add(hri3); - regionSizes.put(hri3.getRegionName(), 10); + conf.setBoolean(MERGE_ENABLED_KEY, false); + setupMocksForNormalizer(regionSizes, regionInfos); + assertThat(normalizer.computePlansForTable(tableName), empty()); + } - setupMocksForNormalizer(regionSizes, RegionInfo); + @Test + public void testHonorsMinimumRegionCount() { + conf.setInt(MIN_REGION_COUNT_KEY, 1); + final TableName tableName = TableName.valueOf(name.getMethodName()); + final List<RegionInfo> 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 + // threshold, and that the split plan is create in both cases. + final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 1, 1, 10); + setupMocksForNormalizer(regionSizes, regionInfos); + + List<NormalizationPlan> 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()); + + // 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()); + } + + @Test + public void testHonorsMergeMinRegionAge() { + conf.setInt(MERGE_MIN_REGION_AGE_DAYS_KEY, 7); + final TableName tableName = TableName.valueOf(name.getMethodName()); + final List<RegionInfo> regionInfos = createRegionInfos(tableName, 4); + final Map<byte[], Integer> regionSizes = + createRegionSizesMap(regionInfos, 1, 1, 10, 10); + setupMocksForNormalizer(regionSizes, regionInfos); + assertEquals(Period.ofDays(7), normalizer.getMergeMinRegionAge()); + assertThat( + normalizer.computePlansForTable(tableName), + everyItem(not(instanceOf(MergeNormalizationPlan.class)))); + + // have to call setupMocks again because we don't have dynamic config update on normalizer. + conf.unset(MERGE_MIN_REGION_AGE_DAYS_KEY); + setupMocksForNormalizer(regionSizes, regionInfos); + assertEquals( + Period.ofDays(DEFAULT_MERGE_MIN_REGION_AGE_DAYS), normalizer.getMergeMinRegionAge()); + final List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName); + assertThat(plans, not(empty())); + assertThat(plans, everyItem(instanceOf(MergeNormalizationPlan.class))); + } + + @Test + public void testHonorsMergeMinRegionSize() { + conf.setBoolean(SPLIT_ENABLED_KEY, false); + final TableName tableName = TableName.valueOf(name.getMethodName()); + final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5); + final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 1, 2, 0, 10, 10); + setupMocksForNormalizer(regionSizes, regionInfos); + + assertFalse(normalizer.isSplitEnabled()); + assertEquals(1, normalizer.getMergeMinRegionSizeMb()); + final List<NormalizationPlan> 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()); + + conf.setInt(MERGE_MIN_REGION_SIZE_MB_KEY, 3); + setupMocksForNormalizer(regionSizes, regionInfos); + assertEquals(3, normalizer.getMergeMinRegionSizeMb()); + assertThat(normalizer.computePlansForTable(tableName), empty()); + } - Configuration configuration = HBaseConfiguration.create(); - configuration.setInt(AbstractRegionNormalizer.HBASE_REGION_NORMALIZER_MIN_REGION_COUNT_KEY, 4); - when(masterServices.getConfiguration()).thenReturn(configuration); + // 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()); + // 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 + // merged. + final byte[][] keys = { Review comment: Oh, got it. Makes sense, thanks. ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org