diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ProcedureSyncWait.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ProcedureSyncWait.java index 5c03a4a3bee..d0dea0a840d 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ProcedureSyncWait.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ProcedureSyncWait.java @@ -149,17 +149,22 @@ public final class ProcedureSyncWait { protected static List getRegionsFromMeta(final MasterProcedureEnv env, final TableName tableName) throws IOException { + return getRegionsFromMeta(env, tableName, false); + } + + protected static List getRegionsFromMeta(final MasterProcedureEnv env, + final TableName tableName, final boolean excludeOfflinedSplitParents) throws IOException { return ProcedureSyncWait.waitFor(env, "regions of table=" + tableName + " from meta", new ProcedureSyncWait.Predicate>() { - @Override - public List evaluate() throws IOException { - if (TableName.META_TABLE_NAME.equals(tableName)) { - return new MetaTableLocator().getMetaRegions(env.getMasterServices().getZooKeeper()); - } - return MetaTableAccessor.getTableRegions(env.getMasterServices().getZooKeeper(), - env.getMasterServices().getConnection(), tableName); - } - }); + @Override + public List evaluate() throws IOException { + if (TableName.META_TABLE_NAME.equals(tableName)) { + return new MetaTableLocator().getMetaRegions(env.getMasterServices().getZooKeeper()); + } + return MetaTableAccessor.getTableRegions(env.getMasterServices().getZooKeeper(), + env.getMasterServices().getConnection(), tableName, excludeOfflinedSplitParents); + } + }); } protected static void waitRegionInTransition(final MasterProcedureEnv env, diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/TruncateTableProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/TruncateTableProcedure.java index 9dccef6d455..735e94f17af 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/TruncateTableProcedure.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/TruncateTableProcedure.java @@ -85,7 +85,7 @@ public class TruncateTableProcedure // TODO: Move out... in the acquireLock() LOG.debug("waiting for '" + getTableName() + "' regions in transition"); - regions = ProcedureSyncWait.getRegionsFromMeta(env, getTableName()); + regions = ProcedureSyncWait.getRegionsFromMeta(env, getTableName(), true); assert regions != null && !regions.isEmpty() : "unexpected 0 regions"; ProcedureSyncWait.waitRegionInTransition(env, regions); @@ -102,15 +102,17 @@ public class TruncateTableProcedure break; case TRUNCATE_TABLE_CLEAR_FS_LAYOUT: DeleteTableProcedure.deleteFromFs(env, getTableName(), regions, true); + setNextState(TruncateTableState.TRUNCATE_TABLE_CREATE_FS_LAYOUT); + break; + case TRUNCATE_TABLE_CREATE_FS_LAYOUT: if (!preserveSplits) { // if we are not preserving splits, generate a new single region + //recreateRegionInfo in TRUNCATE_TABLE_CREATE_FS_LAYOUT phase, since if create fs layout fails + //we need to refresh the region encoded name to prevent dir name conflict regions = Arrays.asList(ModifyRegionUtils.createHRegionInfos(hTableDescriptor, null)); } else { regions = recreateRegionInfo(regions); } - setNextState(TruncateTableState.TRUNCATE_TABLE_CREATE_FS_LAYOUT); - break; - case TRUNCATE_TABLE_CREATE_FS_LAYOUT: regions = CreateTableProcedure.createFsLayout(env, hTableDescriptor, regions); CreateTableProcedure.updateTableDescCache(env, getTableName()); setNextState(TruncateTableState.TRUNCATE_TABLE_ADD_TO_META); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestTruncateTableProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestTruncateTableProcedure.java index 941dd2fef6b..7a3df0f01c5 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestTruncateTableProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestTruncateTableProcedure.java @@ -250,4 +250,35 @@ public class TestTruncateTableProcedure { private ProcedureExecutor getMasterProcedureExecutor() { return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor(); } + + @Test(timeout=60000) + public void testTruncateWithPreserveAfterSplit() throws Exception{ + final String[] families = new String[] { "f1", "f2" }; + final byte[][] splitKeys = new byte[][] { + Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c") + }; + TableName tableName = TableName.valueOf("testTruncateWithPreserveAfterSplit"); + HRegionInfo[] regions = MasterProcedureTestingUtility.createTable( + getMasterProcedureExecutor(), tableName, splitKeys, families); + // load enough data so the table can split + MasterProcedureTestingUtility.loadData( + UTIL.getConnection(), tableName, 5000, splitKeys, families); + assertEquals(5000, UTIL.countRows(tableName)); + UTIL.getHBaseAdmin().split(tableName); + UTIL.waitUntilAllRegionsAssigned(tableName); + //wait until split really happens + while(UTIL.getHBaseAdmin().getTableRegions(tableName).size() <= regions.length) { + Thread.sleep(50); + } + // disable the table + UTIL.getHBaseAdmin().disableTable(tableName); + // truncate the table + final ProcedureExecutor procExec = getMasterProcedureExecutor(); + long procId = ProcedureTestingUtility.submitAndWait(procExec, + new TruncateTableProcedure(procExec.getEnvironment(), tableName, true)); + ProcedureTestingUtility.assertProcNotFailed(procExec, procId); + + UTIL.waitUntilAllRegionsAssigned(tableName); + + } }