Skip to content

Commit 09e52d7

Browse files
committed
HBASE-29356 Incorrect split behavior when region information is missing
1 parent c4d8b00 commit 09e52d7

File tree

2 files changed

+75
-8
lines changed

2 files changed

+75
-8
lines changed

hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SimpleRegionNormalizer.java

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -322,14 +322,27 @@ private double getAverageRegionSizeMb(final List<RegionInfo> tableRegions,
322322
avgRegionSize = targetRegionSize;
323323
} else {
324324
final int regionCount = tableRegions.size();
325-
final long totalSizeMb = tableRegions.stream().mapToLong(this::getRegionSizeMB).sum();
325+
// Count of regions whose size is known
326+
int regionCountKnownSize = 0;
327+
long totalSizeMb = 0;
328+
for (RegionInfo regionInfo : tableRegions) {
329+
long regionSize = getRegionSizeMB(regionInfo);
330+
if (regionSize != -1) {
331+
totalSizeMb += regionSize;
332+
regionCountKnownSize++;
333+
}
334+
}
326335
if (targetRegionCount > 0) {
327-
avgRegionSize = totalSizeMb / (double) targetRegionCount;
336+
avgRegionSize =
337+
totalSizeMb / (double) targetRegionCount - (regionCount - regionCountKnownSize);
328338
} else {
329-
avgRegionSize = totalSizeMb / (double) regionCount;
339+
avgRegionSize = totalSizeMb / (double) regionCountKnownSize;
330340
}
331-
LOG.debug("Table {}, total aggregated regions size: {} MB and average region size {} MB",
332-
table, totalSizeMb, String.format("%.3f", avgRegionSize));
341+
LOG.debug(
342+
"Table {}, total aggregated regions size: {} MB and average region size {} MB, "
343+
+ "number of regions with unknown size {}",
344+
table, totalSizeMb, String.format("%.3f", avgRegionSize),
345+
regionCount - regionCountKnownSize);
333346
}
334347

335348
return avgRegionSize;
@@ -393,6 +406,13 @@ private List<NormalizationPlan> computeMergeNormalizationPlans(final NormalizeCo
393406
for (current = rangeStart; current < ctx.getTableRegions().size(); current++) {
394407
final RegionInfo regionInfo = ctx.getTableRegions().get(current);
395408
final long regionSizeMb = getRegionSizeMB(regionInfo);
409+
if (regionSizeMb == -1) {
410+
LOG.debug(
411+
"For region {} in table {} cannot determine size, skipping check merging region",
412+
regionInfo.getRegionNameAsString(), ctx.getTableName());
413+
rangeStart = Math.max(current, rangeStart + 1);
414+
continue;
415+
}
396416
if (skipForMerge(configuration, ctx, regionInfo)) {
397417
// this region cannot participate in a range. resume the outer loop.
398418
rangeStart = Math.max(current, rangeStart + 1);
@@ -457,6 +477,12 @@ private List<NormalizationPlan> computeSplitNormalizationPlans(final NormalizeCo
457477
continue;
458478
}
459479
final long regionSizeMb = getRegionSizeMB(hri);
480+
if (regionSizeMb == -1) {
481+
LOG.debug(
482+
"For region {} in table {} cannot determine size, skipping check splitting region",
483+
hri.getRegionNameAsString(), ctx.getTableName());
484+
continue;
485+
}
460486
if (regionSizeMb > 2 * avgRegionSize) {
461487
LOG.info(
462488
"Table {}, large region {} has size {} MB, more than twice avg size {} MB, "
@@ -490,7 +516,12 @@ private static boolean isOldEnoughForMerge(final NormalizerConfiguration normali
490516
*/
491517
private boolean isLargeEnoughForMerge(final NormalizerConfiguration normalizerConfiguration,
492518
final NormalizeContext ctx, final RegionInfo regionInfo) {
493-
return getRegionSizeMB(regionInfo) >= normalizerConfiguration.getMergeMinRegionSizeMb(ctx);
519+
long regionSizeMb = getRegionSizeMB(regionInfo);
520+
if (regionSizeMb == -1) {
521+
return false;
522+
} else {
523+
return regionSizeMb >= normalizerConfiguration.getMergeMinRegionSizeMb(ctx);
524+
}
494525
}
495526

496527
/**

hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizer.java

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
3535
import static org.hamcrest.Matchers.hasSize;
3636
import static org.hamcrest.Matchers.instanceOf;
37+
import static org.hamcrest.Matchers.is;
3738
import static org.hamcrest.Matchers.not;
3839
import static org.junit.Assert.assertEquals;
3940
import static org.junit.Assert.assertFalse;
@@ -676,13 +677,27 @@ private void setupMocksForNormalizer(Map<byte[], Integer> regionSizes,
676677
ServerName sn = ServerName.valueOf("localhost", 0, 0L);
677678
when(masterServices.getAssignmentManager().getRegionStates().getRegionsOfTable(any()))
678679
.thenReturn(regionInfoList);
679-
when(masterServices.getAssignmentManager().getRegionStates().getRegionServerOfRegion(any()))
680-
.thenReturn(sn);
680+
for (RegionInfo regionInfo : regionInfoList) {
681+
int regionSize = regionSizes.get(regionInfo.getRegionName());
682+
// ensures that the getRegionSizeMB method returns -1, simulating the condition when the
683+
// region size cannot be found
684+
if (regionSize == -1) {
685+
when(masterServices.getAssignmentManager().getRegionStates()
686+
.getRegionServerOfRegion(regionInfo)).thenReturn(null);
687+
} else {
688+
when(masterServices.getAssignmentManager().getRegionStates()
689+
.getRegionServerOfRegion(regionInfo)).thenReturn(sn);
690+
}
691+
}
681692
when(
682693
masterServices.getAssignmentManager().getRegionStates().getRegionState(any(RegionInfo.class)))
683694
.thenReturn(RegionState.createForTesting(null, RegionState.State.OPEN));
684695

685696
for (Map.Entry<byte[], Integer> region : regionSizes.entrySet()) {
697+
// skip regions where we don't know the size
698+
if (region.getValue() == -1) {
699+
continue;
700+
}
686701
RegionMetrics regionLoad = Mockito.mock(RegionMetrics.class);
687702
when(regionLoad.getRegionName()).thenReturn(region.getKey());
688703
when(regionLoad.getStoreFileSize())
@@ -757,4 +772,25 @@ private static Map<byte[], Integer> createRegionSizesMap(final List<RegionInfo>
757772
}
758773
return ret;
759774
}
775+
776+
@Test
777+
public void testSplitOfLargeRegionIfOneIsNotKnow() {
778+
final TableName tableName = name.getTableName();
779+
final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5);
780+
final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 8, 6, -1, 10, 30);
781+
782+
setupMocksForNormalizer(regionSizes, regionInfos);
783+
784+
assertThat(normalizer.computePlansForTable(tableDescriptor),
785+
contains(new SplitNormalizationPlan(regionInfos.get(4), 30)));
786+
}
787+
788+
@Test
789+
public void testSplitOfAllUnknownSize() {
790+
final TableName tableName = name.getTableName();
791+
final List<RegionInfo> regionInfos = createRegionInfos(tableName, 4);
792+
final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, -1, -1, -1, -1);
793+
setupMocksForNormalizer(regionSizes, regionInfos);
794+
assertThat(normalizer.computePlansForTable(tableDescriptor), is(empty()));
795+
}
760796
}

0 commit comments

Comments
 (0)