HBASE-21084 When cloning a snapshot including a split parent region, the split parent region of the cloned table will be online

This commit is contained in:
Toshihiro Suzuki 2018-08-21 21:38:01 +09:00
parent 409e742ac3
commit f05f116327
2 changed files with 88 additions and 7 deletions

View File

@ -39,6 +39,8 @@ import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher;
import org.apache.hadoop.hbase.master.MasterCoprocessorHost; import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
import org.apache.hadoop.hbase.master.MasterFileSystem; import org.apache.hadoop.hbase.master.MasterFileSystem;
import org.apache.hadoop.hbase.master.MetricsSnapshot; import org.apache.hadoop.hbase.master.MetricsSnapshot;
import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.master.assignment.AssignmentManager;
import org.apache.hadoop.hbase.master.procedure.CreateTableProcedure.CreateHdfsRegions; import org.apache.hadoop.hbase.master.procedure.CreateTableProcedure.CreateHdfsRegions;
import org.apache.hadoop.hbase.monitoring.MonitoredTask; import org.apache.hadoop.hbase.monitoring.MonitoredTask;
import org.apache.hadoop.hbase.monitoring.TaskMonitor; import org.apache.hadoop.hbase.monitoring.TaskMonitor;
@ -149,7 +151,26 @@ public class CloneSnapshotProcedure
break; break;
case CLONE_SNAPSHOT_ASSIGN_REGIONS: case CLONE_SNAPSHOT_ASSIGN_REGIONS:
CreateTableProcedure.setEnablingState(env, getTableName()); CreateTableProcedure.setEnablingState(env, getTableName());
addChildProcedure(env.getAssignmentManager().createRoundRobinAssignProcedures(newRegions));
// Separate newRegions to split regions and regions to assign
List<RegionInfo> splitRegions = new ArrayList<>();
List<RegionInfo> regionsToAssign = new ArrayList<>();
newRegions.forEach(ri -> {
if (ri.isOffline() && (ri.isSplit() || ri.isSplitParent())) {
splitRegions.add(ri);
} else {
regionsToAssign.add(ri);
}
});
// For split regions, add them to RegionStates
AssignmentManager am = env.getAssignmentManager();
splitRegions.forEach(ri ->
am.getRegionStates().updateRegionState(ri, RegionState.State.SPLIT)
);
addChildProcedure(env.getAssignmentManager()
.createRoundRobinAssignProcedures(regionsToAssign));
setNextState(CloneSnapshotState.CLONE_SNAPSHOT_UPDATE_DESC_CACHE); setNextState(CloneSnapshotState.CLONE_SNAPSHOT_UPDATE_DESC_CACHE);
break; break;
case CLONE_SNAPSHOT_UPDATE_DESC_CACHE: case CLONE_SNAPSHOT_UPDATE_DESC_CACHE:

View File

@ -17,13 +17,19 @@
*/ */
package org.apache.hadoop.hbase.client; package org.apache.hadoop.hbase.client;
import static org.junit.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.NamespaceDescriptor; import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.NamespaceNotFoundException; import org.apache.hadoop.hbase.NamespaceNotFoundException;
import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.master.assignment.RegionStates;
import org.apache.hadoop.hbase.master.snapshot.SnapshotManager; import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
import org.apache.hadoop.hbase.snapshot.SnapshotDoesNotExistException; import org.apache.hadoop.hbase.snapshot.SnapshotDoesNotExistException;
import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils; import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils;
@ -160,7 +166,8 @@ public class TestCloneSnapshotFromClient {
@Test(expected=SnapshotDoesNotExistException.class) @Test(expected=SnapshotDoesNotExistException.class)
public void testCloneNonExistentSnapshot() throws IOException, InterruptedException { public void testCloneNonExistentSnapshot() throws IOException, InterruptedException {
String snapshotName = "random-snapshot-" + System.currentTimeMillis(); String snapshotName = "random-snapshot-" + System.currentTimeMillis();
final TableName tableName = TableName.valueOf(name.getMethodName() + "-" + System.currentTimeMillis()); final TableName tableName = TableName.valueOf(name.getMethodName() + "-"
+ System.currentTimeMillis());
admin.cloneSnapshot(snapshotName, tableName); admin.cloneSnapshot(snapshotName, tableName);
} }
@ -172,7 +179,8 @@ public class TestCloneSnapshotFromClient {
@Test @Test
public void testCloneSnapshot() throws IOException, InterruptedException { public void testCloneSnapshot() throws IOException, InterruptedException {
final TableName clonedTableName = TableName.valueOf(name.getMethodName() + "-" + System.currentTimeMillis()); final TableName clonedTableName = TableName.valueOf(name.getMethodName() + "-"
+ System.currentTimeMillis());
testCloneSnapshot(clonedTableName, snapshotName0, snapshot0Rows); testCloneSnapshot(clonedTableName, snapshotName0, snapshot0Rows);
testCloneSnapshot(clonedTableName, snapshotName1, snapshot1Rows); testCloneSnapshot(clonedTableName, snapshotName1, snapshot1Rows);
testCloneSnapshot(clonedTableName, emptySnapshot, 0); testCloneSnapshot(clonedTableName, emptySnapshot, 0);
@ -196,7 +204,8 @@ public class TestCloneSnapshotFromClient {
public void testCloneSnapshotCrossNamespace() throws IOException, InterruptedException { public void testCloneSnapshotCrossNamespace() throws IOException, InterruptedException {
String nsName = "testCloneSnapshotCrossNamespace"; String nsName = "testCloneSnapshotCrossNamespace";
admin.createNamespace(NamespaceDescriptor.create(nsName).build()); admin.createNamespace(NamespaceDescriptor.create(nsName).build());
final TableName clonedTableName = TableName.valueOf(nsName, name.getMethodName() + "-" + System.currentTimeMillis()); final TableName clonedTableName = TableName.valueOf(nsName, name.getMethodName()
+ "-" + System.currentTimeMillis());
testCloneSnapshot(clonedTableName, snapshotName0, snapshot0Rows); testCloneSnapshot(clonedTableName, snapshotName0, snapshot0Rows);
testCloneSnapshot(clonedTableName, snapshotName1, snapshot1Rows); testCloneSnapshot(clonedTableName, snapshotName1, snapshot1Rows);
testCloneSnapshot(clonedTableName, emptySnapshot, 0); testCloneSnapshot(clonedTableName, emptySnapshot, 0);
@ -208,7 +217,8 @@ public class TestCloneSnapshotFromClient {
@Test @Test
public void testCloneLinksAfterDelete() throws IOException, InterruptedException { public void testCloneLinksAfterDelete() throws IOException, InterruptedException {
// Clone a table from the first snapshot // Clone a table from the first snapshot
final TableName clonedTableName = TableName.valueOf(name.getMethodName() + "1-" + System.currentTimeMillis()); final TableName clonedTableName = TableName.valueOf(name.getMethodName() + "1-"
+ System.currentTimeMillis());
admin.cloneSnapshot(snapshotName0, clonedTableName); admin.cloneSnapshot(snapshotName0, clonedTableName);
verifyRowCount(TEST_UTIL, clonedTableName, snapshot0Rows); verifyRowCount(TEST_UTIL, clonedTableName, snapshot0Rows);
@ -217,7 +227,8 @@ public class TestCloneSnapshotFromClient {
admin.snapshot(snapshotName2, clonedTableName); admin.snapshot(snapshotName2, clonedTableName);
// Clone the snapshot of the cloned table // Clone the snapshot of the cloned table
final TableName clonedTableName2 = TableName.valueOf(name.getMethodName() + "2-" + System.currentTimeMillis()); final TableName clonedTableName2 = TableName.valueOf(name.getMethodName() + "2-"
+ System.currentTimeMillis());
admin.cloneSnapshot(snapshotName2, clonedTableName2); admin.cloneSnapshot(snapshotName2, clonedTableName2);
verifyRowCount(TEST_UTIL, clonedTableName2, snapshot0Rows); verifyRowCount(TEST_UTIL, clonedTableName2, snapshot0Rows);
admin.disableTable(clonedTableName2); admin.disableTable(clonedTableName2);
@ -244,7 +255,8 @@ public class TestCloneSnapshotFromClient {
verifyRowCount(TEST_UTIL, clonedTableName2, snapshot0Rows); verifyRowCount(TEST_UTIL, clonedTableName2, snapshot0Rows);
// Clone a new table from cloned // Clone a new table from cloned
final TableName clonedTableName3 = TableName.valueOf(name.getMethodName() + "3-" + System.currentTimeMillis()); final TableName clonedTableName3 = TableName.valueOf(name.getMethodName() + "3-"
+ System.currentTimeMillis());
admin.cloneSnapshot(snapshotName2, clonedTableName3); admin.cloneSnapshot(snapshotName2, clonedTableName3);
verifyRowCount(TEST_UTIL, clonedTableName3, snapshot0Rows); verifyRowCount(TEST_UTIL, clonedTableName3, snapshot0Rows);
@ -254,6 +266,49 @@ public class TestCloneSnapshotFromClient {
admin.deleteSnapshot(snapshotName2); admin.deleteSnapshot(snapshotName2);
} }
@Test
public void testCloneSnapshotAfterSplittingRegion() throws IOException, InterruptedException {
// Turn off the CatalogJanitor
admin.catalogJanitorSwitch(false);
try {
List<RegionInfo> regionInfos = admin.getRegions(tableName);
RegionReplicaUtil.removeNonDefaultRegions(regionInfos);
// Split the first region
splitRegion(regionInfos.get(0));
// Take a snapshot
admin.snapshot(snapshotName2, tableName);
// Clone the snapshot to another table
TableName clonedTableName = TableName.valueOf(name.getMethodName() + "-"
+ System.currentTimeMillis());
admin.cloneSnapshot(snapshotName2, clonedTableName);
SnapshotTestingUtils.waitForTableToBeOnline(TEST_UTIL, clonedTableName);
RegionStates regionStates =
TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager().getRegionStates();
// The region count of the cloned table should be the same as the one of the original table
int openRegionCountOfOriginalTable =
regionStates.getRegionByStateOfTable(tableName).get(RegionState.State.OPEN).size();
int openRegionCountOfClonedTable =
regionStates.getRegionByStateOfTable(clonedTableName).get(RegionState.State.OPEN).size();
assertEquals(openRegionCountOfOriginalTable, openRegionCountOfClonedTable);
int splitRegionCountOfOriginalTable =
regionStates.getRegionByStateOfTable(tableName).get(RegionState.State.SPLIT).size();
int splitRegionCountOfClonedTable =
regionStates.getRegionByStateOfTable(clonedTableName).get(RegionState.State.SPLIT).size();
assertEquals(splitRegionCountOfOriginalTable, splitRegionCountOfClonedTable);
TEST_UTIL.deleteTable(clonedTableName);
} finally {
admin.catalogJanitorSwitch(true);
}
}
// ========================================================================== // ==========================================================================
// Helpers // Helpers
// ========================================================================== // ==========================================================================
@ -266,4 +321,9 @@ public class TestCloneSnapshotFromClient {
long expectedRows) throws IOException { long expectedRows) throws IOException {
SnapshotTestingUtils.verifyRowCount(util, tableName, expectedRows); SnapshotTestingUtils.verifyRowCount(util, tableName, expectedRows);
} }
protected void splitRegion(final RegionInfo regionInfo) throws IOException {
byte[][] splitPoints = Bytes.split(regionInfo.getStartKey(), regionInfo.getEndKey(), 1);
admin.split(regionInfo.getTable(), splitPoints[1]);
}
} }