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 57ea6e6b6f4..d6c8607f769 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 @@ -29,6 +29,7 @@ import org.apache.hadoop.hbase.TableNotDisabledException; import org.apache.hadoop.hbase.TableNotFoundException; import org.apache.hadoop.hbase.client.RegionInfo; import org.apache.hadoop.hbase.client.RegionInfoBuilder; +import org.apache.hadoop.hbase.client.RegionReplicaUtil; import org.apache.hadoop.hbase.client.TableDescriptor; import org.apache.hadoop.hbase.master.MasterCoprocessorHost; import org.apache.hadoop.hbase.procedure2.ProcedureStateSerializer; @@ -90,6 +91,7 @@ public class TruncateTableProcedure // TODO: Move out... in the acquireLock() LOG.debug("waiting for '" + getTableName() + "' regions in transition"); regions = env.getAssignmentManager().getRegionStates().getRegionsOfTable(getTableName()); + RegionReplicaUtil.removeNonDefaultRegions(regions); assert regions != null && !regions.isEmpty() : "unexpected 0 regions"; ProcedureSyncWait.waitRegionInTransition(env, regions); 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 d6d54216d59..a8f7db5b7c8 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 @@ -22,6 +22,9 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; +import java.util.Arrays; +import java.util.stream.Collectors; + import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; @@ -30,7 +33,10 @@ import org.apache.hadoop.hbase.HBaseIOException; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TableNotDisabledException; import org.apache.hadoop.hbase.TableNotFoundException; +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; import org.apache.hadoop.hbase.client.RegionInfo; +import org.apache.hadoop.hbase.client.TableDescriptor; +import org.apache.hadoop.hbase.client.TableDescriptorBuilder; import org.apache.hadoop.hbase.master.MasterFileSystem; import org.apache.hadoop.hbase.procedure2.Procedure; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; @@ -39,6 +45,7 @@ import org.apache.hadoop.hbase.testclassification.MasterTests; import org.apache.hadoop.hbase.testclassification.MediumTests; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.FSUtils; +import org.apache.hadoop.hbase.util.ModifyRegionUtils; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -307,4 +314,63 @@ public class TestTruncateTableProcedure extends TestTableDDLProcedureBase { preserveSplits)); ProcedureTestingUtility.assertProcNotFailed(procExec, procId); } + + @Test(timeout = 60000) + public void testTruncateWithPreserveAfterSplit() throws Exception { + String[] families = new String[] { "f1", "f2" }; + byte[][] splitKeys = + new byte[][] { Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c") }; + TableName tableName = TableName.valueOf(name.getMethodName()); + RegionInfo[] regions = MasterProcedureTestingUtility.createTable(getMasterProcedureExecutor(), + tableName, splitKeys, families); + splitAndTruncate(tableName, regions); + } + + @Test(timeout = 60000) + public void testTruncatePreserveWithReplicaRegionAfterSplit() throws Exception { + String[] families = new String[] { "f1", "f2" }; + byte[][] splitKeys = + new byte[][] { Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c") }; + TableName tableName = TableName.valueOf(name.getMethodName()); + + // create a table with region replications + TableDescriptor htd = TableDescriptorBuilder.newBuilder(tableName) + .setRegionReplication(3) + .setColumnFamilies( + Arrays.stream(families) + .map(fam -> ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(fam)).build()) + .collect(Collectors.toList())) + .build(); + RegionInfo[] regions = ModifyRegionUtils.createRegionInfos(htd, splitKeys); + ProcedureExecutor procExec = getMasterProcedureExecutor(); + long procId = ProcedureTestingUtility.submitAndWait(procExec, + new CreateTableProcedure(procExec.getEnvironment(), htd, regions)); + ProcedureTestingUtility.assertProcNotFailed(procExec.getResult(procId)); + + splitAndTruncate(tableName, regions); + } + + private void splitAndTruncate(TableName tableName, RegionInfo[] regions) throws IOException, + InterruptedException { + + // split a region + UTIL.getAdmin().split(tableName, new byte[]{'0'}); + UTIL.waitUntilAllRegionsAssigned(tableName); + + // wait until split really happens + while (UTIL.getAdmin().getRegions(tableName).size() <= regions.length) { + Thread.sleep(50); + } + + // disable the table + UTIL.getAdmin().disableTable(tableName); + + // truncate the table + ProcedureExecutor procExec = getMasterProcedureExecutor(); + long procId = ProcedureTestingUtility.submitAndWait(procExec, + new TruncateTableProcedure(procExec.getEnvironment(), tableName, true)); + ProcedureTestingUtility.assertProcNotFailed(procExec, procId); + + UTIL.waitUntilAllRegionsAssigned(tableName); + } }