From 0318331ccd840f7e2b3276eccd1a0f9c040285a8 Mon Sep 17 00:00:00 2001 From: Jonathan Hsieh Date: Mon, 9 Jul 2012 07:45:49 +0000 Subject: [PATCH] HBASE-4379 [hbck] Does not complain about tables with no end region [Z,] (Anoop Sam John) git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1358953 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/hadoop/hbase/util/HBaseFsck.java | 42 +++++++++++++- .../util/hbck/TableIntegrityErrorHandler.java | 9 +++ .../hbck/TableIntegrityErrorHandlerImpl.java | 7 +++ .../hadoop/hbase/util/TestHBaseFsck.java | 56 +++++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) 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 640a3127ead..2f2bb7c351b 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 @@ -1702,6 +1702,13 @@ public class HBaseFsck { getTableInfo(), hi); } + @Override + public void handleRegionEndKeyNotEmpty(byte[] curEndKey) throws IOException { + errors.reportError(ERROR_CODE.LAST_REGION_ENDKEY_NOT_EMPTY, + "Last region should end with an empty key. You need to " + + "create a new region and regioninfo in HDFS to plug the hole.", getTableInfo()); + } + @Override public void handleDegenerateRegion(HbckInfo hi) throws IOException{ errors.reportError(ERROR_CODE.DEGENERATE_REGION, @@ -1786,6 +1793,21 @@ public class HBaseFsck { fixes++; } + public void handleRegionEndKeyNotEmpty(byte[] curEndKey) throws IOException { + errors.reportError(ERROR_CODE.LAST_REGION_ENDKEY_NOT_EMPTY, + "Last region should end with an empty key. Creating a new " + + "region and regioninfo in HDFS to plug the hole.", getTableInfo()); + HTableDescriptor htd = getTableInfo().getHTD(); + // from curEndKey to EMPTY_START_ROW + HRegionInfo newRegion = new HRegionInfo(htd.getName(), curEndKey, + HConstants.EMPTY_START_ROW); + + HRegion region = HBaseFsckRepair.createHDFSRegionDir(conf, newRegion, htd); + LOG.info("Table region end key was not empty. Created new empty region: " + newRegion + + " " + region); + fixes++; + } + /** * There is a hole in the hdfs regions that violates the table integrity * rules. Create a new empty region that patches the hole. @@ -1955,6 +1977,12 @@ public class HBaseFsck { * @throws IOException */ public boolean checkRegionChain(TableIntegrityErrorHandler handler) throws IOException { + // When table is disabled no need to check for the region chain. Some of the regions + // accidently if deployed, this below code might report some issues like missing start + // or end regions or region hole in chain and may try to fix which is unwanted. + if (disabledTables.contains(this.tableName.getBytes())) { + return true; + } int originalErrorsCount = errors.getErrorList().size(); Multimap regions = sc.calcCoverage(); SortedSet splits = sc.getSplits(); @@ -2026,6 +2054,12 @@ public class HBaseFsck { prevKey = key; } + // When the last region of a table is proper and having an empty end key, 'prevKey' + // will be null. + if (prevKey != null) { + handler.handleRegionEndKeyNotEmpty(prevKey); + } + for (Collection overlap : overlapGroups.asMap().values()) { handler.handleOverlapGroup(overlap); } @@ -2536,7 +2570,7 @@ public class HBaseFsck { UNKNOWN, NO_META_REGION, NULL_ROOT_REGION, NO_VERSION_FILE, NOT_IN_META_HDFS, NOT_IN_META, NOT_IN_META_OR_DEPLOYED, NOT_IN_HDFS_OR_DEPLOYED, NOT_IN_HDFS, SERVER_DOES_NOT_MATCH_META, NOT_DEPLOYED, MULTI_DEPLOYED, SHOULD_NOT_BE_DEPLOYED, MULTI_META_REGION, RS_CONNECT_FAILURE, - FIRST_REGION_STARTKEY_NOT_EMPTY, DUPE_STARTKEYS, + FIRST_REGION_STARTKEY_NOT_EMPTY, LAST_REGION_ENDKEY_NOT_EMPTY, DUPE_STARTKEYS, HOLE_IN_REGION_CHAIN, OVERLAP_IN_REGION_CHAIN, REGION_CYCLE, DEGENERATE_REGION, ORPHAN_HDFS_REGION, LINGERING_SPLIT_PARENT } @@ -2544,6 +2578,7 @@ public class HBaseFsck { public void report(String message); public void reportError(String message); public void reportError(ERROR_CODE errorCode, String message); + public void reportError(ERROR_CODE errorCode, String message, TableInfo table); public void reportError(ERROR_CODE errorCode, String message, TableInfo table, HbckInfo info); public void reportError(ERROR_CODE errorCode, String message, TableInfo table, HbckInfo info1, HbckInfo info2); public int summarize(); @@ -2579,6 +2614,11 @@ public class HBaseFsck { showProgress = 0; } + public synchronized void reportError(ERROR_CODE errorCode, String message, TableInfo table) { + errorTables.add(table); + reportError(errorCode, message); + } + public synchronized void reportError(ERROR_CODE errorCode, String message, TableInfo table, HbckInfo info) { errorTables.add(table); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/hbck/TableIntegrityErrorHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/hbck/TableIntegrityErrorHandler.java index 2d49d01af10..4310bf866a3 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/hbck/TableIntegrityErrorHandler.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/hbck/TableIntegrityErrorHandler.java @@ -48,6 +48,15 @@ public interface TableIntegrityErrorHandler { * has an empty start key. */ void handleRegionStartKeyNotEmpty(HbckInfo hi) throws IOException; + + /** + * Callback for handling case where a Table has a last region that does not + * have an empty end key. + * + * @param curEndKey The end key of the current last region. There should be a new region + * with start key as this and an empty end key. + */ + void handleRegionEndKeyNotEmpty(byte[] curEndKey) throws IOException; /** * Callback for handling a region that has the same start and end key. diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/hbck/TableIntegrityErrorHandlerImpl.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/hbck/TableIntegrityErrorHandlerImpl.java index 2c34da806d9..af379fd1ee2 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/hbck/TableIntegrityErrorHandlerImpl.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/hbck/TableIntegrityErrorHandlerImpl.java @@ -53,6 +53,13 @@ abstract public class TableIntegrityErrorHandlerImpl implements @Override public void handleRegionStartKeyNotEmpty(HbckInfo hi) throws IOException { } + + /** + * {@inheritDoc} + */ + @Override + public void handleRegionEndKeyNotEmpty(byte[] curEndKey) throws IOException { + } /** * {@inheritDoc} 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 68c62a43e22..6c1f37ae686 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 @@ -1094,6 +1094,62 @@ public class TestHBaseFsck { } } + /** + * This creates and fixes a bad table with a missing region which is the 1st region -- hole in + * meta and data missing in the fs. + */ + @Test + public void testMissingFirstRegion() throws Exception { + String table = "testMissingFirstRegion"; + try { + setupTable(table); + assertEquals(ROWKEYS.length, countRows()); + + // Mess it up by leaving a hole in the assignment, meta, and hdfs data + TEST_UTIL.getHBaseAdmin().disableTable(table); + deleteRegion(conf, tbl.getTableDescriptor(), Bytes.toBytes(""), Bytes.toBytes("A"), true, + true, true); + TEST_UTIL.getHBaseAdmin().enableTable(table); + + HBaseFsck hbck = doFsck(conf, false); + assertErrors(hbck, new ERROR_CODE[] { ERROR_CODE.FIRST_REGION_STARTKEY_NOT_EMPTY }); + // fix hole + doFsck(conf, true); + // check that hole fixed + assertNoErrors(doFsck(conf, false)); + } finally { + deleteTable(table); + } + } + + /** + * This creates and fixes a bad table with missing last region -- hole in meta and data missing in + * the fs. + */ + @Test + public void testMissingLastRegion() throws Exception { + String table = "testMissingLastRegion"; + try { + setupTable(table); + assertEquals(ROWKEYS.length, countRows()); + + // Mess it up by leaving a hole in the assignment, meta, and hdfs data + TEST_UTIL.getHBaseAdmin().disableTable(table); + deleteRegion(conf, tbl.getTableDescriptor(), Bytes.toBytes("C"), Bytes.toBytes(""), true, + true, true); + TEST_UTIL.getHBaseAdmin().enableTable(table); + + HBaseFsck hbck = doFsck(conf, false); + assertErrors(hbck, new ERROR_CODE[] { ERROR_CODE.LAST_REGION_ENDKEY_NOT_EMPTY }); + // fix hole + doFsck(conf, true); + // check that hole fixed + assertNoErrors(doFsck(conf, false)); + } finally { + deleteTable(table); + } + } + @org.junit.Rule public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu = new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();