HBASE-17319 Truncate table with preserve after split may cause truncation to fail (Allan Yang)

This commit is contained in:
tedyu 2016-12-15 13:45:11 -08:00
parent ffe70158cc
commit f3a3069796
3 changed files with 51 additions and 13 deletions

View File

@ -149,17 +149,22 @@ public final class ProcedureSyncWait {
protected static List<HRegionInfo> getRegionsFromMeta(final MasterProcedureEnv env, protected static List<HRegionInfo> getRegionsFromMeta(final MasterProcedureEnv env,
final TableName tableName) throws IOException { final TableName tableName) throws IOException {
return getRegionsFromMeta(env, tableName, false);
}
protected static List<HRegionInfo> getRegionsFromMeta(final MasterProcedureEnv env,
final TableName tableName, final boolean excludeOfflinedSplitParents) throws IOException {
return ProcedureSyncWait.waitFor(env, "regions of table=" + tableName + " from meta", return ProcedureSyncWait.waitFor(env, "regions of table=" + tableName + " from meta",
new ProcedureSyncWait.Predicate<List<HRegionInfo>>() { new ProcedureSyncWait.Predicate<List<HRegionInfo>>() {
@Override @Override
public List<HRegionInfo> evaluate() throws IOException { public List<HRegionInfo> evaluate() throws IOException {
if (TableName.META_TABLE_NAME.equals(tableName)) { if (TableName.META_TABLE_NAME.equals(tableName)) {
return new MetaTableLocator().getMetaRegions(env.getMasterServices().getZooKeeper()); return new MetaTableLocator().getMetaRegions(env.getMasterServices().getZooKeeper());
} }
return MetaTableAccessor.getTableRegions(env.getMasterServices().getZooKeeper(), return MetaTableAccessor.getTableRegions(env.getMasterServices().getZooKeeper(),
env.getMasterServices().getConnection(), tableName); env.getMasterServices().getConnection(), tableName, excludeOfflinedSplitParents);
} }
}); });
} }
protected static void waitRegionInTransition(final MasterProcedureEnv env, protected static void waitRegionInTransition(final MasterProcedureEnv env,

View File

@ -85,7 +85,7 @@ public class TruncateTableProcedure
// TODO: Move out... in the acquireLock() // TODO: Move out... in the acquireLock()
LOG.debug("waiting for '" + getTableName() + "' regions in transition"); 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"; assert regions != null && !regions.isEmpty() : "unexpected 0 regions";
ProcedureSyncWait.waitRegionInTransition(env, regions); ProcedureSyncWait.waitRegionInTransition(env, regions);
@ -102,15 +102,17 @@ public class TruncateTableProcedure
break; break;
case TRUNCATE_TABLE_CLEAR_FS_LAYOUT: case TRUNCATE_TABLE_CLEAR_FS_LAYOUT:
DeleteTableProcedure.deleteFromFs(env, getTableName(), regions, true); DeleteTableProcedure.deleteFromFs(env, getTableName(), regions, true);
setNextState(TruncateTableState.TRUNCATE_TABLE_CREATE_FS_LAYOUT);
break;
case TRUNCATE_TABLE_CREATE_FS_LAYOUT:
if (!preserveSplits) { if (!preserveSplits) {
// if we are not preserving splits, generate a new single region // 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)); regions = Arrays.asList(ModifyRegionUtils.createHRegionInfos(hTableDescriptor, null));
} else { } else {
regions = recreateRegionInfo(regions); regions = recreateRegionInfo(regions);
} }
setNextState(TruncateTableState.TRUNCATE_TABLE_CREATE_FS_LAYOUT);
break;
case TRUNCATE_TABLE_CREATE_FS_LAYOUT:
regions = CreateTableProcedure.createFsLayout(env, hTableDescriptor, regions); regions = CreateTableProcedure.createFsLayout(env, hTableDescriptor, regions);
CreateTableProcedure.updateTableDescCache(env, getTableName()); CreateTableProcedure.updateTableDescCache(env, getTableName());
setNextState(TruncateTableState.TRUNCATE_TABLE_ADD_TO_META); setNextState(TruncateTableState.TRUNCATE_TABLE_ADD_TO_META);

View File

@ -250,4 +250,35 @@ public class TestTruncateTableProcedure {
private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() { private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() {
return UTIL.getHBaseCluster().getMaster().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<MasterProcedureEnv> procExec = getMasterProcedureExecutor();
long procId = ProcedureTestingUtility.submitAndWait(procExec,
new TruncateTableProcedure(procExec.getEnvironment(), tableName, true));
ProcedureTestingUtility.assertProcNotFailed(procExec, procId);
UTIL.waitUntilAllRegionsAssigned(tableName);
}
} }