HBASE-21550 Add a new method preCreateTableRegionInfos for MasterObserver which allows CPs to modify the TableDescriptor

This commit is contained in:
Duo Zhang 2018-12-05 18:19:15 +08:00 committed by zhangduo
parent 8bf966c8e9
commit f49baf259e
4 changed files with 72 additions and 33 deletions

View File

@ -70,6 +70,21 @@ import org.apache.yetus.audience.InterfaceStability;
@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)
@InterfaceStability.Evolving
public interface MasterObserver {
/**
* Called before we create the region infos for this table. Called as part of create table RPC
* call.
* @param ctx the environment to interact with the framework and master
* @param desc the TableDescriptor for the table
* @return the TableDescriptor used to create the table. Default is the one passed in. Return
* {@code null} means cancel the creation.
*/
default TableDescriptor preCreateTableRegionsInfos(
final ObserverContext<MasterCoprocessorEnvironment> ctx, TableDescriptor desc)
throws IOException {
return desc;
}
/**
* Called before a new table is created by
* {@link org.apache.hadoop.hbase.master.HMaster}. Called as part of create

View File

@ -2030,45 +2030,45 @@ public class HMaster extends HRegionServer implements MasterServices {
}
@Override
public long createTable(
final TableDescriptor tableDescriptor,
final byte [][] splitKeys,
final long nonceGroup,
final long nonce) throws IOException {
public long createTable(final TableDescriptor tableDescriptor, final byte[][] splitKeys,
final long nonceGroup, final long nonce) throws IOException {
checkInitialized();
String namespace = tableDescriptor.getTableName().getNamespaceAsString();
TableDescriptor desc = getMasterCoprocessorHost().preCreateTableRegionsInfos(tableDescriptor);
if (desc == null) {
throw new IOException("Creation for " + tableDescriptor + " is canceled by CP");
}
String namespace = desc.getTableName().getNamespaceAsString();
this.clusterSchemaService.getNamespace(namespace);
RegionInfo[] newRegions = ModifyRegionUtils.createRegionInfos(tableDescriptor, splitKeys);
sanityCheckTableDescriptor(tableDescriptor);
RegionInfo[] newRegions = ModifyRegionUtils.createRegionInfos(desc, splitKeys);
sanityCheckTableDescriptor(desc);
return MasterProcedureUtil.submitProcedure(
new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) {
@Override
protected void run() throws IOException {
getMaster().getMasterCoprocessorHost().preCreateTable(tableDescriptor, newRegions);
return MasterProcedureUtil
.submitProcedure(new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) {
@Override
protected void run() throws IOException {
getMaster().getMasterCoprocessorHost().preCreateTable(desc, newRegions);
LOG.info(getClientIdAuditPrefix() + " create " + tableDescriptor);
LOG.info(getClientIdAuditPrefix() + " create " + desc);
// TODO: We can handle/merge duplicate requests, and differentiate the case of
// TableExistsException by saying if the schema is the same or not.
//
// We need to wait for the procedure to potentially fail due to "prepare" sanity
// checks. This will block only the beginning of the procedure. See HBASE-19953.
ProcedurePrepareLatch latch = ProcedurePrepareLatch.createBlockingLatch();
submitProcedure(new CreateTableProcedure(
procedureExecutor.getEnvironment(), tableDescriptor, newRegions, latch));
latch.await();
// TODO: We can handle/merge duplicate requests, and differentiate the case of
// TableExistsException by saying if the schema is the same or not.
//
// We need to wait for the procedure to potentially fail due to "prepare" sanity
// checks. This will block only the beginning of the procedure. See HBASE-19953.
ProcedurePrepareLatch latch = ProcedurePrepareLatch.createBlockingLatch();
submitProcedure(
new CreateTableProcedure(procedureExecutor.getEnvironment(), desc, newRegions, latch));
latch.await();
getMaster().getMasterCoprocessorHost().postCreateTable(tableDescriptor, newRegions);
}
getMaster().getMasterCoprocessorHost().postCreateTable(desc, newRegions);
}
@Override
protected String getDescription() {
return "CreateTableProcedure";
}
});
@Override
protected String getDescription() {
return "CreateTableProcedure";
}
});
}
@Override

View File

@ -317,6 +317,20 @@ public class MasterCoprocessorHost
/* Implementation of hooks for invoking MasterObservers */
public TableDescriptor preCreateTableRegionsInfos(TableDescriptor desc) throws IOException {
if (coprocEnvironments.isEmpty()) {
return desc;
}
return execOperationWithResult(
new ObserverOperationWithResult<MasterObserver, TableDescriptor>(masterObserverGetter, desc) {
@Override
protected TableDescriptor call(MasterObserver observer) throws IOException {
return observer.preCreateTableRegionsInfos(this, getResult());
}
});
}
public void preCreateTable(final TableDescriptor htd, final RegionInfo[] regions)
throws IOException {
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {

View File

@ -94,6 +94,7 @@ public class TestMasterObserver {
public static class CPMasterObserver implements MasterCoprocessor, MasterObserver {
private boolean preCreateTableRegionInfosCalled;
private boolean preCreateTableCalled;
private boolean postCreateTableCalled;
private boolean preDeleteTableCalled;
@ -186,6 +187,7 @@ public class TestMasterObserver {
private boolean postLockHeartbeatCalled;
public void resetStates() {
preCreateTableRegionInfosCalled = false;
preCreateTableCalled = false;
postCreateTableCalled = false;
preDeleteTableCalled = false;
@ -297,6 +299,14 @@ public class TestMasterObserver {
return preMergeRegionsCalled && postMergeRegionsCalled;
}
@Override
public TableDescriptor preCreateTableRegionsInfos(
ObserverContext<MasterCoprocessorEnvironment> ctx, TableDescriptor desc)
throws IOException {
preCreateTableRegionInfosCalled = true;
return desc;
}
@Override
public void preCreateTable(ObserverContext<MasterCoprocessorEnvironment> env,
TableDescriptor desc, RegionInfo[] regions) throws IOException {
@ -310,11 +320,11 @@ public class TestMasterObserver {
}
public boolean wasCreateTableCalled() {
return preCreateTableCalled && postCreateTableCalled;
return preCreateTableRegionInfosCalled && preCreateTableCalled && postCreateTableCalled;
}
public boolean preCreateTableCalledOnly() {
return preCreateTableCalled && !postCreateTableCalled;
return preCreateTableRegionInfosCalled && preCreateTableCalled && !postCreateTableCalled;
}
@Override