HBASE-24995: MetaFixer fails to fix overlaps when multiple tables have overlaps (#2361)

Signed-off-by: stack <stack@apache.org>
This commit is contained in:
Mohammad Arshad 2020-09-09 00:30:44 +05:30 committed by GitHub
parent 0d95a8f91b
commit 2250b51fe7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 5 deletions

View File

@ -19,9 +19,11 @@ package org.apache.hadoop.hbase.master;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
@ -39,6 +41,8 @@ import org.apache.hadoop.hbase.master.assignment.TransitRegionStateProcedure;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil;
import org.apache.hbase.thirdparty.com.google.common.collect.ArrayListMultimap;
import org.apache.hbase.thirdparty.com.google.common.collect.ListMultimap;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -231,16 +235,18 @@ class MetaFixer {
/**
* Fix overlaps noted in CJ consistency report.
*/
void fixOverlaps(CatalogJanitor.Report report) throws IOException {
List<Long> fixOverlaps(CatalogJanitor.Report report) throws IOException {
List<Long> pidList = new ArrayList<>();
for (Set<RegionInfo> regions: calculateMerges(maxMergeCount, report.getOverlaps())) {
RegionInfo [] regionsArray = regions.toArray(new RegionInfo [] {});
try {
this.masterServices.mergeRegions(regionsArray,
true, HConstants.NO_NONCE, HConstants.NO_NONCE);
pidList.add(this.masterServices
.mergeRegions(regionsArray, true, HConstants.NO_NONCE, HConstants.NO_NONCE));
} catch (MergeRegionException mre) {
LOG.warn("Failed overlap fix of {}", regionsArray, mre);
}
}
return pidList;
}
/**
@ -258,6 +264,21 @@ class MetaFixer {
return Collections.emptyList();
}
List<SortedSet<RegionInfo>> merges = new ArrayList<>();
// First group overlaps by table then calculate merge table by table.
ListMultimap<TableName, Pair<RegionInfo, RegionInfo>> overlapGroups =
ArrayListMultimap.create();
for (Pair<RegionInfo, RegionInfo> pair : overlaps) {
overlapGroups.put(pair.getFirst().getTable(), pair);
}
for (Map.Entry<TableName, Collection<Pair<RegionInfo, RegionInfo>>> entry : overlapGroups
.asMap().entrySet()) {
calculateTableMerges(maxMergeCount, merges, entry.getValue());
}
return merges;
}
private static void calculateTableMerges(int maxMergeCount, List<SortedSet<RegionInfo>> merges,
Collection<Pair<RegionInfo, RegionInfo>> overlaps) {
SortedSet<RegionInfo> currentMergeSet = new TreeSet<>();
HashSet<RegionInfo> regionsInMergeSet = new HashSet<>();
RegionInfo regionInfoWithlargestEndKey = null;
@ -301,7 +322,6 @@ class MetaFixer {
regionInfoWithlargestEndKey);
}
merges.add(currentMergeSet);
return merges;
}
/**

View File

@ -46,6 +46,7 @@ import org.apache.hadoop.hbase.master.assignment.RegionStateStore;
import org.apache.hadoop.hbase.master.assignment.RegionStates;
import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility;
import org.apache.hadoop.hbase.testclassification.LargeTests;
import org.apache.hadoop.hbase.testclassification.MasterTests;
import org.apache.hadoop.hbase.util.Bytes;
@ -171,7 +172,8 @@ public class TestMetaFixer {
Collections.singletonList(MetaTableAccessor.makePutFromRegionInfo(overlapRegion,
System.currentTimeMillis())));
// TODO: Add checks at assign time to PREVENT being able to assign over existing assign.
services.getAssignmentManager().assign(overlapRegion);
long assign = services.getAssignmentManager().assign(overlapRegion);
ProcedureTestingUtility.waitProcedures(services.getMasterProcedureExecutor(), assign);
return overlapRegion;
}
@ -244,6 +246,41 @@ public class TestMetaFixer {
assertTrue(postReport.isEmpty());
}
@Test
public void testMultipleTableOverlaps() throws Exception {
TableName t1 = TableName.valueOf("t1");
TableName t2 = TableName.valueOf("t2");
TEST_UTIL.createMultiRegionTable(t1, new byte[][] { HConstants.CATALOG_FAMILY });
TEST_UTIL.createMultiRegionTable(t2, new byte[][] { HConstants.CATALOG_FAMILY });
TEST_UTIL.waitTableAvailable(t2);
HMaster services = TEST_UTIL.getHBaseCluster().getMaster();
services.getCatalogJanitor().scan();
CatalogJanitor.Report report = services.getCatalogJanitor().getLastReport();
assertTrue(report.isEmpty());
// Make a simple overlap for t1
List<RegionInfo> ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), t1);
makeOverlap(services, ris.get(1), ris.get(2));
// Make a simple overlap for t2
ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), t2);
makeOverlap(services, ris.get(1), ris.get(2));
services.getCatalogJanitor().scan();
report = services.getCatalogJanitor().getLastReport();
assertEquals("Region overlaps count does not match.", 4, report.getOverlaps().size());
MetaFixer fixer = new MetaFixer(services);
List<Long> longs = fixer.fixOverlaps(report);
long[] procIds = longs.stream().mapToLong(l -> l).toArray();
ProcedureTestingUtility.waitProcedures(services.getMasterProcedureExecutor(), procIds);
// After fix, verify no overlaps are left.
services.getCatalogJanitor().scan();
report = services.getCatalogJanitor().getLastReport();
assertTrue("After fix there should not have been any overlaps.", report.isEmpty());
}
@Test
public void testOverlapWithSmallMergeCount() throws Exception {
TableName tn = TableName.valueOf(this.name.getMethodName());