diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java index abd477c68cd..6761bfc719e 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java @@ -1374,12 +1374,16 @@ public class HMaster extends HRegionServer implements MasterServices, Server { continue; } } - NormalizationPlan plan = this.normalizer.computePlanForTable(table, types); - plan.execute(clusterConnection.getAdmin()); - if (plan.getType() == PlanType.SPLIT) { - splitPlanCount++; - } else if (plan.getType() == PlanType.MERGE) { - mergePlanCount++; + List plans = this.normalizer.computePlanForTable(table, types); + if (plans != null) { + for (NormalizationPlan plan : plans) { + plan.execute(clusterConnection.getAdmin()); + if (plan.getType() == PlanType.SPLIT) { + splitPlanCount++; + } else if (plan.getType() == PlanType.MERGE) { + mergePlanCount++; + } + } } } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/RegionNormalizer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/RegionNormalizer.java index 9de376af7c3..3c5de18d481 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/RegionNormalizer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/RegionNormalizer.java @@ -50,8 +50,8 @@ public interface RegionNormalizer { * Computes next optimal normalization plan. * @param table table to normalize * @param types desired types of NormalizationPlan - * @return Next (perhaps most urgent) normalization action to perform + * @return normalization actions to perform. Null if no action to take */ - NormalizationPlan computePlanForTable(TableName table, List types) + List computePlanForTable(TableName table, List types) throws HBaseIOException; } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/RegionNormalizerChore.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/RegionNormalizerChore.java index 1506892fec7..9f47cdcc826 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/RegionNormalizerChore.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/RegionNormalizerChore.java @@ -39,7 +39,7 @@ public class RegionNormalizerChore extends ScheduledChore { public RegionNormalizerChore(HMaster master) { super(master.getServerName() + "-RegionNormalizerChore", master, - master.getConfiguration().getInt("hbase.normalizer.period", 1800000)); + master.getConfiguration().getInt("hbase.normalizer.period", 300000)); this.master = master; } 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 9f76f26d4ae..3b6981e95df 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 @@ -71,19 +71,14 @@ public class SimpleRegionNormalizer implements RegionNormalizer { this.masterServices = masterServices; } - /* - * This comparator compares the region size. - * The second element in the triple is region size while the 3rd element - * is the index of the region in the underlying List - */ - private Comparator> regionSizeComparator = - new Comparator>() { + // Comparator that gives higher priority to region Split plan + private Comparator planComparator = + new Comparator() { @Override - public int compare(Triple pair, - Triple pair2) { - long sz = pair.getSecond(); - long sz2 = pair2.getSecond(); - return (sz < sz2) ? -1 : ((sz == sz2) ? 0 : 1); + public int compare(NormalizationPlan plan, NormalizationPlan plan2) { + if (plan instanceof SplitNormalizationPlan) return -1; + if (plan2 instanceof SplitNormalizationPlan) return 1; + return 0; } }; @@ -96,13 +91,14 @@ public class SimpleRegionNormalizer implements RegionNormalizer { * @return normalization plan to execute */ @Override - public NormalizationPlan computePlanForTable(TableName table, List types) + public List computePlanForTable(TableName table, List types) throws HBaseIOException { if (table == null || table.isSystemTable()) { LOG.debug("Normalization of system table " + table + " isn't allowed"); - return EmptyNormalizationPlan.getInstance(); + return null; } + List plans = new ArrayList(); List tableRegions = masterServices.getAssignmentManager().getRegionStates(). getRegionsOfTable(table); @@ -111,7 +107,7 @@ public class SimpleRegionNormalizer implements RegionNormalizer { int nrRegions = tableRegions == null ? 0 : tableRegions.size(); LOG.debug("Table " + table + " has " + nrRegions + " regions, required min number" + " of regions for normalizer to run is " + MIN_REGION_COUNT + ", not running normalizer"); - return EmptyNormalizationPlan.getInstance(); + return null; } LOG.debug("Computing normalization plan for table: " + table + @@ -119,56 +115,49 @@ public class SimpleRegionNormalizer implements RegionNormalizer { long totalSizeMb = 0; - ArrayList> regionsWithSize = - new ArrayList>(tableRegions.size()); for (int i = 0; i < tableRegions.size(); i++) { HRegionInfo hri = tableRegions.get(i); long regionSize = getRegionSize(hri); - regionsWithSize.add(new Triple(hri, regionSize, i)); totalSizeMb += regionSize; } - Collections.sort(regionsWithSize, regionSizeComparator); - - Triple largestRegion = regionsWithSize.get(tableRegions.size()-1); double avgRegionSize = totalSizeMb / (double) tableRegions.size(); LOG.debug("Table " + table + ", total aggregated regions size: " + totalSizeMb); LOG.debug("Table " + table + ", average region size: " + avgRegionSize); - // now; if the largest region is >2 times large than average, we split it, split - // is more high priority normalization action than merge. - if (types.contains(PlanType.SPLIT) && largestRegion.getSecond() > 2 * avgRegionSize) { - LOG.debug("Table " + table + ", largest region " - + largestRegion.getFirst().getRegionNameAsString() + " has size " - + largestRegion.getSecond() + ", more than 2 times than avg size, splitting"); - return new SplitNormalizationPlan(largestRegion.getFirst(), null); - } int candidateIdx = 0; - // look for two successive entries whose indices are adjacent - while (candidateIdx < tableRegions.size()-1) { - if (Math.abs(regionsWithSize.get(candidateIdx).getThird() - - regionsWithSize.get(candidateIdx + 1).getThird()) == 1) { - break; + while (candidateIdx < tableRegions.size()) { + HRegionInfo hri = tableRegions.get(candidateIdx); + long regionSize = getRegionSize(hri); + // if the region is > 2 times larger than average, we split it, split + // is more high priority normalization action than merge. + if (types.contains(PlanType.SPLIT) && regionSize > 2 * avgRegionSize) { + LOG.debug("Table " + table + ", large region " + hri.getRegionNameAsString() + " has size " + + regionSize + ", more than twice avg size, splitting"); + plans.add(new SplitNormalizationPlan(hri, null)); + } else { + if (candidateIdx == tableRegions.size()-1) { + break; + } + HRegionInfo hri2 = tableRegions.get(candidateIdx+1); + long regionSize2 = getRegionSize(hri2); + if (types.contains(PlanType.MERGE) && regionSize + regionSize2 < avgRegionSize) { + LOG.debug("Table " + table + ", small region size: " + regionSize + + " plus its neighbor size: " + regionSize2 + + ", less than the avg size " + avgRegionSize + ", merging them"); + plans.add(new MergeNormalizationPlan(hri, hri2)); + candidateIdx++; + } } candidateIdx++; } - if (candidateIdx == tableRegions.size()-1) { - LOG.debug("No neighboring regions found for table: " + table); - return EmptyNormalizationPlan.getInstance(); + if (plans.isEmpty()) { + LOG.debug("No normalization needed, regions look good for table: " + table); + return null; } - Triple candidateRegion = regionsWithSize.get(candidateIdx); - Triple candidateRegion2 = regionsWithSize.get(candidateIdx+1); - if (types.contains(PlanType.MERGE) && - candidateRegion.getSecond() + candidateRegion2.getSecond() < avgRegionSize) { - LOG.debug("Table " + table + ", smallest region size: " + candidateRegion.getSecond() - + " and its smallest neighbor size: " + candidateRegion2.getSecond() - + ", less than the avg size, merging them"); - return new MergeNormalizationPlan(candidateRegion.getFirst(), - candidateRegion2.getFirst()); - } - LOG.debug("No normalization needed, regions look good for table: " + table); - return EmptyNormalizationPlan.getInstance(); + Collections.sort(plans, planComparator); + return plans; } private long getRegionSize(HRegionInfo hri) { 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 2c302d5134a..9733d33b4b3 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 @@ -82,8 +82,8 @@ public class TestSimpleRegionNormalizer { Map regionSizes = new HashMap<>(); setupMocksForNormalizer(regionSizes, hris); - NormalizationPlan plan = normalizer.computePlanForTable(testTable, bothTypes); - assertTrue(plan instanceof EmptyNormalizationPlan); + List plans = normalizer.computePlanForTable(testTable, bothTypes); + assertTrue(plans == null); } @Test @@ -101,8 +101,8 @@ public class TestSimpleRegionNormalizer { regionSizes.put(hri2.getRegionName(), 15); setupMocksForNormalizer(regionSizes, hris); - NormalizationPlan plan = normalizer.computePlanForTable(testTable, bothTypes); - assertTrue((plan instanceof EmptyNormalizationPlan)); + List plans = normalizer.computePlanForTable(testTable, bothTypes); + assertTrue(plans == null); } @Test @@ -128,8 +128,8 @@ public class TestSimpleRegionNormalizer { regionSizes.put(hri4.getRegionName(), 10); setupMocksForNormalizer(regionSizes, hris); - NormalizationPlan plan = normalizer.computePlanForTable(testTable, bothTypes); - assertTrue(plan instanceof EmptyNormalizationPlan); + List plans = normalizer.computePlanForTable(testTable, bothTypes); + assertTrue(plans == null); } @Test @@ -164,15 +164,16 @@ public class TestSimpleRegionNormalizer { regionSizes.put(hri5.getRegionName(), 16); setupMocksForNormalizer(regionSizes, hris); - NormalizationPlan plan = normalizer.computePlanForTable(testTable, + List plans = normalizer.computePlanForTable(testTable, mergeDesired ? bothTypes : splitType); if (mergeDesired) { + NormalizationPlan plan = plans.get(0); assertTrue(plan instanceof MergeNormalizationPlan); assertEquals(hri2, ((MergeNormalizationPlan) plan).getFirstRegion()); assertEquals(hri3, ((MergeNormalizationPlan) plan).getSecondRegion()); } else { - assertTrue(plan instanceof EmptyNormalizationPlan); + assertTrue(plans == null); } } @@ -208,7 +209,8 @@ public class TestSimpleRegionNormalizer { regionSizes.put(hri6.getRegionName(), 2700); setupMocksForNormalizer(regionSizes, hris); - NormalizationPlan plan = normalizer.computePlanForTable(testTable, bothTypes); + List plans = normalizer.computePlanForTable(testTable, bothTypes); + NormalizationPlan plan = plans.get(0); assertTrue(plan instanceof MergeNormalizationPlan); assertEquals(hri5, ((MergeNormalizationPlan) plan).getFirstRegion()); @@ -242,9 +244,9 @@ public class TestSimpleRegionNormalizer { regionSizes.put(hri5.getRegionName(), 5); setupMocksForNormalizer(regionSizes, hris); - NormalizationPlan plan = normalizer.computePlanForTable(testTable, bothTypes); + List plans = normalizer.computePlanForTable(testTable, bothTypes); - assertTrue(plan instanceof EmptyNormalizationPlan); + assertTrue(plans == null); } @Test @@ -270,7 +272,8 @@ public class TestSimpleRegionNormalizer { regionSizes.put(hri4.getRegionName(), 30); setupMocksForNormalizer(regionSizes, hris); - NormalizationPlan plan = normalizer.computePlanForTable(testTable, bothTypes); + List plans = normalizer.computePlanForTable(testTable, bothTypes); + NormalizationPlan plan = plans.get(0); assertTrue(plan instanceof SplitNormalizationPlan); assertEquals(hri4, ((SplitNormalizationPlan) plan).getRegionInfo()); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizerOnCluster.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizerOnCluster.java index b821b8a7e11..dc96dc7e216 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizerOnCluster.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizerOnCluster.java @@ -126,13 +126,19 @@ public class TestSimpleRegionNormalizerOnCluster { Thread.sleep(5000); // to let region load to update m.normalizeRegions(); - while (MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), TABLENAME) < 6) { - LOG.info("Waiting for normalization split to complete"); - Thread.sleep(100); + while (true) { + List regions = TEST_UTIL.getHBaseCluster().getRegions(TABLENAME); + int cnt = 0; + for (HRegion region : regions) { + String regionName = region.getRegionInfo().getRegionNameAsString(); + if (regionName.startsWith("testRegionNormalizationSplitOnCluster,zzzzz")) { + cnt++; + } + } + if (cnt >= 2) { + break; + } } - - assertEquals(6, MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), TABLENAME)); - admin.disableTable(TABLENAME); admin.deleteTable(TABLENAME); }