Return-Path: X-Original-To: apmail-hbase-commits-archive@www.apache.org Delivered-To: apmail-hbase-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 6297AED54 for ; Wed, 27 Feb 2013 23:20:11 +0000 (UTC) Received: (qmail 50926 invoked by uid 500); 27 Feb 2013 23:20:11 -0000 Delivered-To: apmail-hbase-commits-archive@hbase.apache.org Received: (qmail 50894 invoked by uid 500); 27 Feb 2013 23:20:11 -0000 Mailing-List: contact commits-help@hbase.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@hbase.apache.org Delivered-To: mailing list commits@hbase.apache.org Received: (qmail 50884 invoked by uid 99); 27 Feb 2013 23:20:11 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 27 Feb 2013 23:20:11 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 27 Feb 2013 23:20:08 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 97E262388980; Wed, 27 Feb 2013 23:19:49 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1451028 - in /hbase/branches/0.94/src: main/java/org/apache/hadoop/hbase/catalog/ main/java/org/apache/hadoop/hbase/util/ test/java/org/apache/hadoop/hbase/regionserver/ test/java/org/apache/hadoop/hbase/util/ Date: Wed, 27 Feb 2013 23:19:49 -0000 To: commits@hbase.apache.org From: enis@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130227231949.97E262388980@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: enis Date: Wed Feb 27 23:19:48 2013 New Revision: 1451028 URL: http://svn.apache.org/r1451028 Log: HBASE-7777 HBCK check for lingering split parents should check for child regions Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestEndToEndSplitTransaction.java hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java?rev=1451028&r1=1451027&r2=1451028&view=diff ============================================================================== --- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java (original) +++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java Wed Feb 27 23:19:48 2013 @@ -40,6 +40,7 @@ import org.apache.hadoop.hbase.client.Sc import org.apache.hadoop.hbase.ipc.HRegionInterface; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; +import org.apache.hadoop.hbase.util.PairOfSameType; import org.apache.hadoop.hbase.util.Writables; import org.apache.hadoop.ipc.RemoteException; @@ -402,6 +403,8 @@ public class MetaReader { return Writables.getHRegionInfoOrNull(bytes); } + + /** * Checks if the specified table exists. Looks at the META table hosted on * the specified server. @@ -450,6 +453,21 @@ public class MetaReader { } /** + * Returns the daughter 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 getDaughterRegions(Result data) throws IOException { + HRegionInfo splitA = Writables.getHRegionInfoOrNull(data.getValue(HConstants.CATALOG_FAMILY, + HConstants.SPLITA_QUALIFIER)); + HRegionInfo splitB = Writables.getHRegionInfoOrNull(data.getValue(HConstants.CATALOG_FAMILY, + HConstants.SPLITB_QUALIFIER)); + return new PairOfSameType(splitA, splitB); + } + + /** * Gets all of the regions of the specified table. * @param catalogTracker * @param tableName Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java?rev=1451028&r1=1451027&r2=1451028&view=diff ============================================================================== --- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java (original) +++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java Wed Feb 27 23:19:48 2013 @@ -236,7 +236,7 @@ public class HBaseFsck extends Configure * When initially looking at HDFS, we attempt to find any orphaned data. */ private List orphanHdfsDirs = Collections.synchronizedList(new ArrayList()); - + private Map> orphanTableDirs = new HashMap>(); /** @@ -395,7 +395,7 @@ public class HBaseFsck extends Configure if (!checkMetaOnly) { reportTablesInFlux(); } - + // get regions according to what is online on each RegionServer loadDeployedRegions(); @@ -800,19 +800,21 @@ public class HBaseFsck extends Configure if (!orphanTableDirs.containsKey(tableName)) { LOG.warn("Unable to read .tableinfo from " + hbaseRoot, ioe); //should only report once for each table - errors.reportError(ERROR_CODE.NO_TABLEINFO_FILE, + errors.reportError(ERROR_CODE.NO_TABLEINFO_FILE, "Unable to read .tableinfo from " + hbaseRoot + "/" + tableName); Set columns = new HashSet(); orphanTableDirs.put(tableName, getColumnFamilyList(columns, hbi)); } } } - modTInfo.addRegionInfo(hbi); + if (!hbi.isSkipChecks()) { + modTInfo.addRegionInfo(hbi); + } } return tablesInfo; } - + /** * To get the column family list according to the column family dirs * @param columns @@ -830,7 +832,7 @@ public class HBaseFsck extends Configure } return columns; } - + /** * To fabricate a .tableinfo file with following contents
* 1. the correct tablename
@@ -848,7 +850,7 @@ public class HBaseFsck extends Configure FSTableDescriptors.createTableDescriptor(htd, getConf(), true); return true; } - + /** * To fix orphan table by creating a .tableinfo file under tableDir
* 1. if TableInfo is cached, to recover the .tableinfo accordingly
@@ -1661,6 +1663,18 @@ public class HBaseFsck extends Configure // ========== Cases where the region is in META ============= } else if (inMeta && inHdfs && !isDeployed && splitParent) { + // check whether this is an actual error, or just transient state where parent + // is not cleaned + if (hbi.metaEntry.splitA != null && hbi.metaEntry.splitB != null) { + // check that split daughters are there + HbckInfo infoA = this.regionInfoMap.get(hbi.metaEntry.splitA.getEncodedName()); + HbckInfo infoB = this.regionInfoMap.get(hbi.metaEntry.splitB.getEncodedName()); + if (infoA != null && infoB != null) { + // we already processed or will process daughters. Move on, nothing to see here. + hbi.setSkipChecks(true); + return; + } + } errors.reportError(ERROR_CODE.LINGERING_SPLIT_PARENT, "Region " + descriptiveName + " is a split parent in META, in HDFS, " + "and not deployed on any region server. This could be transient."); @@ -1791,7 +1805,9 @@ public class HBaseFsck extends Configure modTInfo.addServer(server); } - modTInfo.addRegionInfo(hbi); + if (!hbi.isSkipChecks()) { + modTInfo.addRegionInfo(hbi); + } tablesInfo.put(tableName, modTInfo); } @@ -2555,7 +2571,8 @@ public class HBaseFsck extends Configure || hri.isMetaRegion() || hri.isRootRegion())) { return true; } - MetaEntry m = new MetaEntry(hri, sn, ts); + PairOfSameType daughters = MetaReader.getDaughterRegions(result); + MetaEntry m = new MetaEntry(hri, sn, ts, daughters.getFirst(), daughters.getSecond()); HbckInfo hbInfo = new HbckInfo(m); HbckInfo previous = regionInfoMap.put(hri.getEncodedName(), hbInfo); if (previous != null) { @@ -2594,11 +2611,19 @@ public class HBaseFsck extends Configure static class MetaEntry extends HRegionInfo { ServerName regionServer; // server hosting this region long modTime; // timestamp of most recent modification metadata + HRegionInfo splitA, splitB; //split daughters public MetaEntry(HRegionInfo rinfo, ServerName regionServer, long modTime) { + this(rinfo, regionServer, modTime, null, null); + } + + public MetaEntry(HRegionInfo rinfo, ServerName regionServer, long modTime, + HRegionInfo splitA, HRegionInfo splitB) { super(rinfo); this.regionServer = regionServer; this.modTime = modTime; + this.splitA = splitA; + this.splitB = splitB; } public boolean equals(Object o) { @@ -2647,6 +2672,7 @@ public class HBaseFsck extends Configure private HdfsEntry hdfsEntry = null; // info in HDFS 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. HbckInfo(MetaEntry metaEntry) { this.metaEntry = metaEntry; @@ -2764,6 +2790,14 @@ public class HBaseFsck extends Configure } return hdfsEntry.hri; } + + public void setSkipChecks(boolean skipChecks) { + this.skipChecks = skipChecks; + } + + public boolean isSkipChecks() { + return skipChecks; + } } final static Comparator cmp = new Comparator() { @@ -3239,15 +3273,15 @@ public class HBaseFsck extends Configure boolean shouldFixHdfsHoles() { return fixHdfsHoles; } - + public void setFixTableOrphans(boolean shouldFix) { fixTableOrphans = shouldFix; } - + boolean shouldFixTableOrphans() { return fixTableOrphans; } - + public void setFixHdfsOverlaps(boolean shouldFix) { fixHdfsOverlaps = shouldFix; } Modified: hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestEndToEndSplitTransaction.java URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestEndToEndSplitTransaction.java?rev=1451028&r1=1451027&r2=1451028&view=diff ============================================================================== --- hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestEndToEndSplitTransaction.java (original) +++ hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/regionserver/TestEndToEndSplitTransaction.java Wed Feb 27 23:19:48 2013 @@ -43,6 +43,7 @@ import org.apache.hadoop.hbase.NotServin import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.Stoppable; import org.apache.hadoop.hbase.catalog.MetaEditor; +import org.apache.hadoop.hbase.catalog.MetaReader; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.client.HConnection; @@ -199,7 +200,6 @@ public class TestEndToEndSplitTransactio HTable table; byte[] tableName, family; HBaseAdmin admin; - HTable metaTable; HRegionServer rs; RegionSplitter(HTable table) throws IOException { @@ -208,7 +208,6 @@ public class TestEndToEndSplitTransactio this.family = table.getTableDescriptor().getFamiliesKeys().iterator().next(); admin = TEST_UTIL.getHBaseAdmin(); rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0); - metaTable = new HTable(conf, HConstants.META_TABLE_NAME); } public void run() { @@ -239,14 +238,14 @@ public class TestEndToEndSplitTransactio addData(start); addData(mid); - flushAndBlockUntilDone(region.getRegionName()); - compactAndBlockUntilDone(region.getRegionName()); + flushAndBlockUntilDone(admin, rs, region.getRegionName()); + compactAndBlockUntilDone(admin, rs, region.getRegionName()); log("Initiating region split for:" + region.getRegionNameAsString()); try { admin.split(region.getRegionName(), splitPoint); //wait until the split is complete - blockUntilRegionSplit(50000, region.getRegionName(), true); + blockUntilRegionSplit(conf, 50000, region.getRegionName(), true); } catch (NotServingRegionException ex) { //ignore @@ -254,10 +253,6 @@ public class TestEndToEndSplitTransactio } } catch (Throwable ex) { this.ex = ex; - } finally { - if (metaTable != null) { - IOUtils.closeQuietly(metaTable); - } } } @@ -270,106 +265,6 @@ public class TestEndToEndSplitTransactio } table.flushCommits(); } - - void flushAndBlockUntilDone(byte[] regionName) throws IOException, InterruptedException { - log("flushing region: " + Bytes.toStringBinary(regionName)); - admin.flush(regionName); - log("blocking until flush is complete: " + Bytes.toStringBinary(regionName)); - Threads.sleepWithoutInterrupt(500); - while (rs.cacheFlusher.getFlushQueueSize() > 0) { - Threads.sleep(50); - } - } - - void compactAndBlockUntilDone(byte[] regionName) throws IOException, - InterruptedException { - log("Compacting region: " + Bytes.toStringBinary(regionName)); - admin.majorCompact(regionName); - log("blocking until compaction is complete: " + Bytes.toStringBinary(regionName)); - Threads.sleepWithoutInterrupt(500); - while (rs.compactSplitThread.getCompactionQueueSize() > 0) { - Threads.sleep(50); - } - } - - /** bloks until the region split is complete in META and region server opens the daughters */ - void blockUntilRegionSplit(long timeout, final byte[] regionName, boolean waitForDaughters) - throws IOException, InterruptedException { - long start = System.currentTimeMillis(); - log("blocking until region is split:" + Bytes.toStringBinary(regionName)); - HRegionInfo daughterA = null, daughterB = null; - - while (System.currentTimeMillis() - start < timeout) { - Result result = getRegionRow(regionName); - if (result == null) { - break; - } - - HRegionInfo region = MetaEditor.getHRegionInfo(result); - if(region.isSplitParent()) { - log("found parent region: " + region.toString()); - PairOfSameType pair = MetaEditor.getDaughterRegions(result); - daughterA = pair.getFirst(); - daughterB = pair.getSecond(); - break; - } - sleep(100); - } - - //if we are here, this means the region split is complete or timed out - if (waitForDaughters) { - long rem = timeout - (System.currentTimeMillis() - start); - blockUntilRegionIsInMeta(rem, daughterA.getRegionName()); - - rem = timeout - (System.currentTimeMillis() - start); - blockUntilRegionIsInMeta(rem, daughterB.getRegionName()); - - rem = timeout - (System.currentTimeMillis() - start); - blockUntilRegionIsOpenedByRS(rem, daughterA.getRegionName()); - - rem = timeout - (System.currentTimeMillis() - start); - blockUntilRegionIsOpenedByRS(rem, daughterB.getRegionName()); - } - } - - Result getRegionRow(byte[] regionName) throws IOException { - Get get = new Get(regionName); - return metaTable.get(get); - } - - void blockUntilRegionIsInMeta(long timeout, byte[] regionName) - throws IOException, InterruptedException { - log("blocking until region is in META: " + Bytes.toStringBinary(regionName)); - long start = System.currentTimeMillis(); - while (System.currentTimeMillis() - start < timeout) { - Result result = getRegionRow(regionName); - if (result != null) { - HRegionInfo info = MetaEditor.getHRegionInfo(result); - if (info != null && !info.isOffline()) { - log("found region in META: " + Bytes.toStringBinary(regionName)); - break; - } - } - sleep(10); - } - } - - void blockUntilRegionIsOpenedByRS(long timeout, byte[] regionName) - throws IOException, InterruptedException { - log("blocking until region is opened by region server: " + Bytes.toStringBinary(regionName)); - long start = System.currentTimeMillis(); - while (System.currentTimeMillis() - start < timeout) { - List regions = rs.getOnlineRegions(tableName); - for (HRegion region : regions) { - if (Bytes.compareTo(region.getRegionName(), regionName) == 0) { - log("found region open in RS: " + Bytes.toStringBinary(regionName)); - return; - } - } - sleep(10); - } - } - } /** @@ -476,6 +371,120 @@ public class TestEndToEndSplitTransactio LOG.info(msg); } + /* some utility methods for split tests */ + + public static void flushAndBlockUntilDone(HBaseAdmin admin, HRegionServer rs, byte[] regionName) + throws IOException, InterruptedException { + log("flushing region: " + Bytes.toStringBinary(regionName)); + admin.flush(regionName); + log("blocking until flush is complete: " + Bytes.toStringBinary(regionName)); + Threads.sleepWithoutInterrupt(500); + while (rs.cacheFlusher.getFlushQueueSize() > 0) { + Threads.sleep(50); + } + } + + public static void compactAndBlockUntilDone(HBaseAdmin admin, HRegionServer rs, byte[] regionName) + throws IOException, InterruptedException { + log("Compacting region: " + Bytes.toStringBinary(regionName)); + admin.majorCompact(regionName); + log("blocking until compaction is complete: " + Bytes.toStringBinary(regionName)); + Threads.sleepWithoutInterrupt(500); + while (rs.compactSplitThread.getCompactionQueueSize() > 0) { + Threads.sleep(50); + } + } + + /** Blocks until the region split is complete in META and region server opens the daughters */ + public static void blockUntilRegionSplit(Configuration conf, long timeout, + final byte[] regionName, boolean waitForDaughters) + throws IOException, InterruptedException { + long start = System.currentTimeMillis(); + log("blocking until region is split:" + Bytes.toStringBinary(regionName)); + HRegionInfo daughterA = null, daughterB = null; + HTable metaTable = new HTable(conf, HConstants.META_TABLE_NAME); + + try { + while (System.currentTimeMillis() - start < timeout) { + Result result = getRegionRow(metaTable, regionName); + if (result == null) { + break; + } + + HRegionInfo region = MetaReader.parseCatalogResult(result).getFirst(); + if(region.isSplitParent()) { + log("found parent region: " + region.toString()); + PairOfSameType pair = MetaReader.getDaughterRegions(result); + daughterA = pair.getFirst(); + daughterB = pair.getSecond(); + break; + } + Threads.sleep(100); + } + + //if we are here, this means the region split is complete or timed out + if (waitForDaughters) { + long rem = timeout - (System.currentTimeMillis() - start); + blockUntilRegionIsInMeta(metaTable, rem, daughterA); + + rem = timeout - (System.currentTimeMillis() - start); + blockUntilRegionIsInMeta(metaTable, rem, daughterB); + + rem = timeout - (System.currentTimeMillis() - start); + blockUntilRegionIsOpened(conf, rem, daughterA); + + rem = timeout - (System.currentTimeMillis() - start); + blockUntilRegionIsOpened(conf, rem, daughterB); + } + } finally { + IOUtils.closeQuietly(metaTable); + } + } + + public static Result getRegionRow(HTable metaTable, byte[] regionName) throws IOException { + Get get = new Get(regionName); + return metaTable.get(get); + } + + public static void blockUntilRegionIsInMeta(HTable metaTable, long timeout, HRegionInfo hri) + throws IOException, InterruptedException { + log("blocking until region is in META: " + hri.getRegionNameAsString()); + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() - start < timeout) { + Result result = getRegionRow(metaTable, hri.getRegionName()); + if (result != null) { + HRegionInfo info = MetaReader.parseCatalogResult(result).getFirst(); + if (info != null && !info.isOffline()) { + log("found region in META: " + hri.getRegionNameAsString()); + break; + } + } + Threads.sleep(10); + } + } + + public static void blockUntilRegionIsOpened(Configuration conf, long timeout, HRegionInfo hri) + throws IOException, InterruptedException { + log("blocking until region is opened for reading:" + hri.getRegionNameAsString()); + long start = System.currentTimeMillis(); + HTable table = new HTable(conf, hri.getTableName()); + + try { + Get get = new Get(hri.getStartKey()); + while (System.currentTimeMillis() - start < timeout) { + try { + table.get(get); + break; + } catch(IOException ex) { + //wait some more + } + Threads.sleep(10); + } + } finally { + IOUtils.closeQuietly(table); + } + } + @org.junit.Rule public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu = new org.apache.hadoop.hbase.ResourceCheckerJUnitRule(); Modified: hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java?rev=1451028&r1=1451027&r2=1451028&view=diff ============================================================================== --- hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java (original) +++ hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/util/TestHBaseFsck.java Wed Feb 27 23:19:48 2013 @@ -38,6 +38,7 @@ import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; +import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; @@ -54,6 +55,7 @@ import org.apache.hadoop.hbase.HTableDes import org.apache.hadoop.hbase.LargeTests; import org.apache.hadoop.hbase.MiniHBaseCluster; import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.catalog.MetaReader; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.HBaseAdmin; @@ -70,11 +72,12 @@ import org.apache.hadoop.hbase.ipc.HRegi import org.apache.hadoop.hbase.master.HMaster; import org.apache.hadoop.hbase.regionserver.HRegion; import org.apache.hadoop.hbase.regionserver.HRegionServer; +import org.apache.hadoop.hbase.regionserver.TestEndToEndSplitTransaction; import org.apache.hadoop.hbase.util.HBaseFsck.ErrorReporter; -import org.apache.hadoop.hbase.util.HBaseFsck.PrintingErrorReporter; -import org.apache.hadoop.hbase.util.HBaseFsck.TableInfo; import org.apache.hadoop.hbase.util.HBaseFsck.ErrorReporter.ERROR_CODE; import org.apache.hadoop.hbase.util.HBaseFsck.HbckInfo; +import org.apache.hadoop.hbase.util.HBaseFsck.PrintingErrorReporter; +import org.apache.hadoop.hbase.util.HBaseFsck.TableInfo; import org.apache.hadoop.hbase.util.hbck.HFileCorruptionChecker; import org.apache.hadoop.hbase.util.hbck.HbckTestingUtil; import org.apache.hadoop.hbase.zookeeper.ZKAssign; @@ -409,7 +412,7 @@ public class TestHBaseFsck { deleteTable(table); } } - + @Test public void testHbckFixOrphanTable() throws Exception { String table = "tableInfo"; @@ -418,31 +421,31 @@ public class TestHBaseFsck { try { setupTable(table); HBaseAdmin admin = TEST_UTIL.getHBaseAdmin(); - + Path hbaseTableDir = new Path(conf.get(HConstants.HBASE_DIR) + "/" + table ); fs = hbaseTableDir.getFileSystem(conf); FileStatus status = FSTableDescriptors.getTableInfoPath(fs, hbaseTableDir); tableinfo = status.getPath(); fs.rename(tableinfo, new Path("/.tableinfo")); - + //to report error if .tableinfo is missing. - HBaseFsck hbck = doFsck(conf, false); + HBaseFsck hbck = doFsck(conf, false); assertErrors(hbck, new ERROR_CODE[] { ERROR_CODE.NO_TABLEINFO_FILE }); - + // fix OrphanTable with default .tableinfo (htd not yet cached on master) hbck = doFsck(conf, true); assertNoErrors(hbck); status = null; status = FSTableDescriptors.getTableInfoPath(fs, hbaseTableDir); assertNotNull(status); - + HTableDescriptor htd = admin.getTableDescriptor(table.getBytes()); htd.setValue("NOT_DEFAULT", "true"); admin.disableTable(table); admin.modifyTable(table.getBytes(), htd); admin.enableTable(table); fs.delete(status.getPath(), true); - + // fix OrphanTable with cache htd = admin.getTableDescriptor(table.getBytes()); // warms up cached htd on master hbck = doFsck(conf, true); @@ -1185,6 +1188,7 @@ public class TestHBaseFsck { @Test public void testLingeringSplitParent() throws Exception { String table = "testLingeringSplitParent"; + HTable meta = null; try { setupTable(table); assertEquals(ROWKEYS.length, countRows()); @@ -1198,7 +1202,7 @@ public class TestHBaseFsck { Bytes.toBytes("C"), true, true, false); // Create a new meta entry to fake it as a split parent. - HTable meta = new HTable(conf, HTableDescriptor.META_TABLEDESC.getName()); + meta = new HTable(conf, HTableDescriptor.META_TABLEDESC.getName()); HRegionInfo hri = location.getRegionInfo(); HRegionInfo a = new HRegionInfo(tbl.getTableName(), @@ -1256,6 +1260,119 @@ public class TestHBaseFsck { assertEquals(ROWKEYS.length, countRows()); } finally { deleteTable(table); + IOUtils.closeQuietly(meta); + } + } + + /** + * Tests that LINGERING_SPLIT_PARENT is not erroneously reported for + * valid cases where the daughters are there. + */ + @Test + public void testValidLingeringSplitParent() throws Exception { + String table = "testLingeringSplitParent"; + HTable meta = null; + try { + 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); + HRegionLocation location = tbl.getRegionLocation("B"); + + meta = new HTable(conf, HTableDescriptor.META_TABLEDESC.getName()); + HRegionInfo hri = location.getRegionInfo(); + + // do a regular split + HBaseAdmin admin = TEST_UTIL.getHBaseAdmin(); + byte[] regionName = location.getRegionInfo().getRegionName(); + admin.split(location.getRegionInfo().getRegionName(), Bytes.toBytes("BM")); + TestEndToEndSplitTransaction.blockUntilRegionSplit( + TEST_UTIL.getConfiguration(), 60000, regionName, true); + + // TODO: fixHdfsHoles does not work against splits, since the parent dir lingers on + // for some time until children references are deleted. HBCK erroneously sees this as + // overlapping regions + HBaseFsck hbck = doFsck(conf, true, true, false, false, false, true, true, true, null); + assertErrors(hbck, new ERROR_CODE[] {}); //no LINGERING_SPLIT_PARENT reported + + // assert that the split META entry is still there. + Get get = new Get(hri.getRegionName()); + Result result = meta.get(get); + assertNotNull(result); + assertNotNull(MetaReader.parseCatalogResult(result).getFirst()); + + assertEquals(ROWKEYS.length, countRows()); + + // assert that we still have the split regions + assertEquals(tbl.getStartKeys().length, SPLITS.length + 1 + 1); //SPLITS + 1 is # regions pre-split. + assertNoErrors(doFsck(conf, false)); + } finally { + deleteTable(table); + IOUtils.closeQuietly(meta); + } + } + + /** + * Split crashed after write to META finished for the parent region, but + * failed to write daughters (pre HBASE-7721 codebase) + */ + @Test + public void testSplitDaughtersNotInMeta() throws Exception { + String table = "testSplitdaughtersNotInMeta"; + HTable meta = null; + try { + 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); + HRegionLocation location = tbl.getRegionLocation("B"); + + meta = new HTable(conf, HTableDescriptor.META_TABLEDESC.getName()); + HRegionInfo hri = location.getRegionInfo(); + + // do a regular split + HBaseAdmin admin = TEST_UTIL.getHBaseAdmin(); + byte[] regionName = location.getRegionInfo().getRegionName(); + admin.split(location.getRegionInfo().getRegionName(), Bytes.toBytes("BM")); + TestEndToEndSplitTransaction.blockUntilRegionSplit( + TEST_UTIL.getConfiguration(), 60000, regionName, true); + + PairOfSameType daughters = MetaReader.getDaughterRegions(meta.get(new Get(regionName))); + + // Delete daughter regions from meta, but not hdfs, unassign it. + Map hris = tbl.getRegionLocations(); + undeployRegion(admin, hris.get(daughters.getFirst()), daughters.getFirst()); + undeployRegion(admin, hris.get(daughters.getSecond()), daughters.getSecond()); + + meta.delete(new Delete(daughters.getFirst().getRegionName())); + meta.delete(new Delete(daughters.getSecond().getRegionName())); + meta.flushCommits(); + + HBaseFsck hbck = doFsck(conf, false); + assertErrors(hbck, new ERROR_CODE[] {ERROR_CODE.NOT_IN_META_OR_DEPLOYED, + ERROR_CODE.NOT_IN_META_OR_DEPLOYED, ERROR_CODE.HOLE_IN_REGION_CHAIN}); //no LINGERING_SPLIT_PARENT + + // now fix it. The fix should not revert the region split, but add daughters to META + hbck = doFsck(conf, true, true, false, false, false, false, false, false, null); + assertErrors(hbck, new ERROR_CODE[] {ERROR_CODE.NOT_IN_META_OR_DEPLOYED, + ERROR_CODE.NOT_IN_META_OR_DEPLOYED, ERROR_CODE.HOLE_IN_REGION_CHAIN}); + + // assert that the split META entry is still there. + Get get = new Get(hri.getRegionName()); + Result result = meta.get(get); + assertNotNull(result); + assertNotNull(MetaReader.parseCatalogResult(result).getFirst()); + + assertEquals(ROWKEYS.length, countRows()); + + // assert that we still have the split regions + assertEquals(tbl.getStartKeys().length, SPLITS.length + 1 + 1); //SPLITS + 1 is # regions pre-split. + assertNoErrors(doFsck(conf, false)); //should be fixed by now + } finally { + deleteTable(table); + IOUtils.closeQuietly(meta); } }