You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by st...@apache.org on 2020/09/08 19:02:28 UTC

[hbase] branch branch-2 updated: HBASE-24995: MetaFixer fails to fix overlaps when multiple tables have overlaps (#2361)

This is an automated email from the ASF dual-hosted git repository.

stack pushed a commit to branch branch-2
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-2 by this push:
     new 672bd1b  HBASE-24995: MetaFixer fails to fix overlaps when multiple tables have overlaps (#2361)
672bd1b is described below

commit 672bd1b3a84bfe0c3c4fd9ff984dffadd3e8f2d6
Author: Mohammad Arshad <ar...@apache.org>
AuthorDate: Wed Sep 9 00:30:44 2020 +0530

    HBASE-24995: MetaFixer fails to fix overlaps when multiple tables have overlaps (#2361)
    
    Signed-off-by: stack <st...@apache.org>
---
 .../org/apache/hadoop/hbase/master/MetaFixer.java  | 28 +++++++++++++---
 .../apache/hadoop/hbase/master/TestMetaFixer.java  | 39 +++++++++++++++++++++-
 2 files changed, 62 insertions(+), 5 deletions(-)

diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MetaFixer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MetaFixer.java
index 9f10791..68501da 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MetaFixer.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MetaFixer.java
@@ -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;
   }
 
   /**
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMetaFixer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMetaFixer.java
index fe329f3..d5d8cd7 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMetaFixer.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMetaFixer.java
@@ -44,6 +44,7 @@ import org.apache.hadoop.hbase.master.assignment.GCMultipleMergedRegionsProcedur
 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;
@@ -169,7 +170,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;
   }
 
@@ -243,6 +245,41 @@ public class TestMetaFixer {
   }
 
   @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());
     try {