From fe84985a5ef716cb11e4a4279a0d654c93103da6 Mon Sep 17 00:00:00 2001 From: Duo Zhang Date: Wed, 5 Dec 2018 18:19:15 +0800 Subject: [PATCH] HBASE-21550 Add a new method preCreateTableRegionInfos for MasterObserver which allows CPs to modify the TableDescriptor --- .../hbase/coprocessor/MasterObserver.java | 15 ++++ .../apache/hadoop/hbase/master/HMaster.java | 68 +++++++++---------- .../hbase/master/MasterCoprocessorHost.java | 14 ++++ .../hbase/coprocessor/TestMasterObserver.java | 14 +++- 4 files changed, 75 insertions(+), 36 deletions(-) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java index 573ac7a8a9..a0863e4ad7 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/MasterObserver.java @@ -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 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 diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java index 132e2714e1..e96dc3675d 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java @@ -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); - - return MasterProcedureUtil.submitProcedure( - new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { - @Override - protected void run() throws IOException { - getMaster().getMasterCoprocessorHost().preCreateTable(tableDescriptor, newRegions); - - LOG.info(getClientIdAuditPrefix() + " create " + tableDescriptor); - - // 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(); + RegionInfo[] newRegions = ModifyRegionUtils.createRegionInfos(desc, splitKeys); + sanityCheckTableDescriptor(desc); - getMaster().getMasterCoprocessorHost().postCreateTable(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 " + 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(), desc, newRegions, latch)); + latch.await(); + + getMaster().getMasterCoprocessorHost().postCreateTable(desc, newRegions); + } - @Override - protected String getDescription() { - return "CreateTableProcedure"; - } - }); + @Override + protected String getDescription() { + return "CreateTableProcedure"; + } + }); } @Override diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java index 019c64f659..51e30c4766 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java @@ -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(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() { diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java index a606e27c40..d8a5b4c26f 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java @@ -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 ctx, TableDescriptor desc) + throws IOException { + preCreateTableRegionInfosCalled = true; + return desc; + } + @Override public void preCreateTable(ObserverContext 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 -- 2.17.1