Skip to content

Commit 467bd83

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

File tree

2 files changed

+72
-8
lines changed

2 files changed

+72
-8
lines changed

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

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -322,14 +322,24 @@ 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 = totalSizeMb / (double) targetRegionCount - (regionCount - regionCountKnownSize);
328337
} else {
329-
avgRegionSize = totalSizeMb / (double) regionCount;
338+
avgRegionSize = totalSizeMb / (double) regionCountKnownSize;
330339
}
331-
LOG.debug("Table {}, total aggregated regions size: {} MB and average region size {} MB",
332-
table, totalSizeMb, String.format("%.3f", avgRegionSize));
340+
LOG.debug("Table {}, total aggregated regions size: {} MB and average region size {} MB, "
341+
+ "number of regions with unknown size {}",
342+
table, totalSizeMb, String.format("%.3f", avgRegionSize), regionCount - regionCountKnownSize);
333343
}
334344

335345
return avgRegionSize;
@@ -393,6 +403,12 @@ private List<NormalizationPlan> computeMergeNormalizationPlans(final NormalizeCo
393403
for (current = rangeStart; current < ctx.getTableRegions().size(); current++) {
394404
final RegionInfo regionInfo = ctx.getTableRegions().get(current);
395405
final long regionSizeMb = getRegionSizeMB(regionInfo);
406+
if(regionSizeMb == -1) {
407+
LOG.debug("For region {} in table {} cannot determine size, skipping check merging region",
408+
regionInfo.getRegionNameAsString(), ctx.getTableName());
409+
rangeStart = Math.max(current, rangeStart + 1);
410+
continue;
411+
}
396412
if (skipForMerge(configuration, ctx, regionInfo)) {
397413
// this region cannot participate in a range. resume the outer loop.
398414
rangeStart = Math.max(current, rangeStart + 1);
@@ -457,6 +473,11 @@ private List<NormalizationPlan> computeSplitNormalizationPlans(final NormalizeCo
457473
continue;
458474
}
459475
final long regionSizeMb = getRegionSizeMB(hri);
476+
if (regionSizeMb == -1) {
477+
LOG.debug("For region {} in table {} cannot determine size, skipping check splitting region",
478+
hri.getRegionNameAsString(), ctx.getTableName());
479+
continue;
480+
}
460481
if (regionSizeMb > 2 * avgRegionSize) {
461482
LOG.info(
462483
"Table {}, large region {} has size {} MB, more than twice avg size {} MB, "
@@ -490,7 +511,12 @@ private static boolean isOldEnoughForMerge(final NormalizerConfiguration normali
490511
*/
491512
private boolean isLargeEnoughForMerge(final NormalizerConfiguration normalizerConfiguration,
492513
final NormalizeContext ctx, final RegionInfo regionInfo) {
493-
return getRegionSizeMB(regionInfo) >= normalizerConfiguration.getMergeMinRegionSizeMb(ctx);
514+
long regionSizeMb = getRegionSizeMB(regionInfo);
515+
if( regionSizeMb==-1) {
516+
return false;
517+
} else {
518+
return regionSizeMb >= normalizerConfiguration.getMergeMinRegionSizeMb(ctx);
519+
}
494520
}
495521

496522
/**

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

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@
3232
import static org.hamcrest.Matchers.empty;
3333
import static org.hamcrest.Matchers.everyItem;
3434
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
35+
import static org.hamcrest.Matchers.hasItem;
3536
import static org.hamcrest.Matchers.hasSize;
3637
import static org.hamcrest.Matchers.instanceOf;
3738
import static org.hamcrest.Matchers.not;
39+
import static org.hamcrest.Matchers.is;
3840
import static org.junit.Assert.assertEquals;
3941
import static org.junit.Assert.assertFalse;
4042
import static org.junit.Assert.assertTrue;
@@ -676,13 +678,28 @@ private void setupMocksForNormalizer(Map<byte[], Integer> regionSizes,
676678
ServerName sn = ServerName.valueOf("localhost", 0, 0L);
677679
when(masterServices.getAssignmentManager().getRegionStates().getRegionsOfTable(any()))
678680
.thenReturn(regionInfoList);
679-
when(masterServices.getAssignmentManager().getRegionStates().getRegionServerOfRegion(any()))
680-
.thenReturn(sn);
681+
for(RegionInfo regionInfo : regionInfoList) {
682+
int regionSize = regionSizes.get(regionInfo.getRegionName());
683+
// ensures that the getRegionSizeMB method returns -1, simulating the condition when the region size cannot be found
684+
if(regionSize == -1) {
685+
when(masterServices.getAssignmentManager().getRegionStates()
686+
.getRegionServerOfRegion(regionInfo))
687+
.thenReturn(null);
688+
} else {
689+
when(masterServices.getAssignmentManager().getRegionStates()
690+
.getRegionServerOfRegion(regionInfo))
691+
.thenReturn(sn);
692+
}
693+
}
681694
when(
682695
masterServices.getAssignmentManager().getRegionStates().getRegionState(any(RegionInfo.class)))
683696
.thenReturn(RegionState.createForTesting(null, RegionState.State.OPEN));
684697

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

0 commit comments

Comments
 (0)