From ce58832621e9963a16f92693e6cedfa0cab82bf1 Mon Sep 17 00:00:00 2001 From: zjushch Date: Thu, 19 Dec 2013 06:25:20 +0000 Subject: [PATCH] HBASE-10196 Enhance HBCK to understand the case after online region merge git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1552238 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/hadoop/hbase/HRegionInfo.java | 14 ++++++ .../apache/hadoop/hbase/util/HBaseFsck.java | 27 ++++++++++ .../hadoop/hbase/util/TestHBaseFsck.java | 49 +++++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java index 6525befe7af..9d0a1d40e92 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java @@ -1012,6 +1012,20 @@ public class HRegionInfo implements Comparable { return new PairOfSameType(splitA, splitB); } + + /** + * Returns the merge regions by reading the corresponding columns of the catalog table + * Result. + * @param data a Result object from the catalog table scan + * @return a pair of HRegionInfo or PairOfSameType(null, null) if the region is not a split + * parent + */ + public static PairOfSameType getMergeRegions(Result data) throws IOException { + HRegionInfo mergeA = getHRegionInfo(data, HConstants.MERGEA_QUALIFIER); + HRegionInfo mergeB = getHRegionInfo(data, HConstants.MERGEB_QUALIFIER); + + return new PairOfSameType(mergeA, mergeB); + } /** * Returns the HRegionInfo object from the column {@link HConstants#CATALOG_FAMILY} and diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java index e90415253f2..9ab1d1167b6 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java @@ -1668,6 +1668,14 @@ public class HBaseFsck extends Configured { } } else if (!inMeta && inHdfs && !isDeployed) { + if (hbi.isMerged()) { + // This region has already been merged, the remaining hdfs file will be + // cleaned by CatalogJanitor later + hbi.setSkipChecks(true); + LOG.info("Region " + descriptiveName + + " got merge recently, its file will be cleaned by CatalogJanitor later"); + return; + } errors.reportError(ERROR_CODE.NOT_IN_META_OR_DEPLOYED, "Region " + descriptiveName + " on HDFS, but not listed in hbase:meta " + "or deployed on any region server"); @@ -2646,6 +2654,16 @@ public class HBaseFsck extends Configured { } else { throw new IOException("Two entries in hbase:meta are same " + previous); } + + PairOfSameType mergeRegions = HRegionInfo.getMergeRegions(result); + for (HRegionInfo mergeRegion : new HRegionInfo[] { + mergeRegions.getFirst(), mergeRegions.getSecond() }) { + if (mergeRegion != null) { + // This region is already been merged + HbckInfo hbInfo = getOrCreateInfo(mergeRegion.getEncodedName()); + hbInfo.setMerged(true); + } + } // show proof of progress to the user, once for every 100 records. if (countRecord % 100 == 0) { @@ -2753,6 +2771,7 @@ public class HBaseFsck extends Configured { private List deployedEntries = Lists.newArrayList(); // on Region Server private List deployedOn = Lists.newArrayList(); // info on RS's private boolean skipChecks = false; // whether to skip further checks to this region info. + private boolean isMerged = false;// whether this region has already been merged into another one HbckInfo(MetaEntry metaEntry) { this.metaEntry = metaEntry; @@ -2879,6 +2898,14 @@ public class HBaseFsck extends Configured { public boolean isSkipChecks() { return skipChecks; } + + public void setMerged(boolean isMerged) { + this.isMerged = isMerged; + } + + public boolean isMerged() { + return this.isMerged; + } } final static Comparator cmp = new Comparator() { diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java index f8ff7afb48c..153777efc5b 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java @@ -23,6 +23,7 @@ import static org.apache.hadoop.hbase.util.hbck.HbckTestingUtil.assertNoErrors; import static org.apache.hadoop.hbase.util.hbck.HbckTestingUtil.doFsck; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -2177,6 +2178,54 @@ public class TestHBaseFsck { } + @Test + public void testHbckAfterRegionMerge() throws Exception { + TableName table = TableName.valueOf("testMergeRegionFilesInHdfs"); + HTable meta = null; + try { + // disable CatalogJanitor + TEST_UTIL.getHBaseCluster().getMaster().setCatalogJanitorEnabled(false); + setupTable(table); + assertEquals(ROWKEYS.length, countRows()); + + // make sure data in regions, if in hlog only there is no data loss + TEST_UTIL.getHBaseAdmin().flush(table.getName()); + HRegionInfo region1 = tbl.getRegionLocation("A").getRegionInfo(); + HRegionInfo region2 = tbl.getRegionLocation("B").getRegionInfo(); + + int regionCountBeforeMerge = tbl.getRegionLocations().size(); + + assertNotEquals(region1, region2); + + // do a region merge + HBaseAdmin admin = TEST_UTIL.getHBaseAdmin(); + admin.mergeRegions(region1.getEncodedNameAsBytes(), + region2.getEncodedNameAsBytes(), false); + + // wait until region merged + long timeout = System.currentTimeMillis() + 30 * 1000; + while (true) { + if (tbl.getRegionLocations().size() < regionCountBeforeMerge) { + break; + } else if (System.currentTimeMillis() > timeout) { + fail("Time out waiting on region " + region1.getEncodedName() + + " and " + region2.getEncodedName() + " be merged"); + } + Thread.sleep(10); + } + + assertEquals(ROWKEYS.length, countRows()); + + HBaseFsck hbck = doFsck(conf, false); + assertNoErrors(hbck); // no errors + + } finally { + TEST_UTIL.getHBaseCluster().getMaster().setCatalogJanitorEnabled(true); + deleteTable(table); + IOUtils.closeQuietly(meta); + } + } + @org.junit.Rule public TestName name = new TestName(); }