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) @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)
@InterfaceStability.Evolving @InterfaceStability.Evolving
public interface MasterObserver { 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 * Called before a new table is created by
* {@link org.apache.hadoop.hbase.master.HMaster}. Called as part of create * {@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 @Override
public long createTable( public long createTable(final TableDescriptor tableDescriptor, final byte[][] splitKeys,
final TableDescriptor tableDescriptor, final long nonceGroup, final long nonce) throws IOException {
final byte [][] splitKeys,
final long nonceGroup,
final long nonce) throws IOException {
checkInitialized(); checkInitialized();
TableDescriptor desc = getMasterCoprocessorHost().preCreateTableRegionsInfos(tableDescriptor);
String namespace = tableDescriptor.getTableName().getNamespaceAsString(); if (desc == null) {
throw new IOException("Creation for " + tableDescriptor + " is canceled by CP");
}
String namespace = desc.getTableName().getNamespaceAsString();
this.clusterSchemaService.getNamespace(namespace); this.clusterSchemaService.getNamespace(namespace);
RegionInfo[] newRegions = ModifyRegionUtils.createRegionInfos(tableDescriptor, splitKeys); RegionInfo[] newRegions = ModifyRegionUtils.createRegionInfos(desc, splitKeys);
sanityCheckTableDescriptor(tableDescriptor); sanityCheckTableDescriptor(desc);
return MasterProcedureUtil.submitProcedure( return MasterProcedureUtil
new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { .submitProcedure(new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) {
@Override @Override
protected void run() throws IOException { protected void run() throws IOException {
getMaster().getMasterCoprocessorHost().preCreateTable(tableDescriptor, newRegions); 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 // TODO: We can handle/merge duplicate requests, and differentiate the case of
// TableExistsException by saying if the schema is the same or not. // 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 // 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. // checks. This will block only the beginning of the procedure. See HBASE-19953.
ProcedurePrepareLatch latch = ProcedurePrepareLatch.createBlockingLatch(); ProcedurePrepareLatch latch = ProcedurePrepareLatch.createBlockingLatch();
submitProcedure(new CreateTableProcedure( submitProcedure(
procedureExecutor.getEnvironment(), tableDescriptor, newRegions, latch)); new CreateTableProcedure(procedureExecutor.getEnvironment(), desc, newRegions, latch));
latch.await(); latch.await();
getMaster().getMasterCoprocessorHost().postCreateTable(tableDescriptor, newRegions); getMaster().getMasterCoprocessorHost().postCreateTable(desc, newRegions);
} }
@Override @Override
protected String getDescription() { protected String getDescription() {
return "CreateTableProcedure"; return "CreateTableProcedure";
} }
}); });
} }
@Override @Override

View File

@ -317,6 +317,20 @@ public class MasterCoprocessorHost
/* Implementation of hooks for invoking MasterObservers */ /* 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) public void preCreateTable(final TableDescriptor htd, final RegionInfo[] regions)
throws IOException { throws IOException {
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() { execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {

View File

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