From 7e8ce1c5cc9f0f15e5a456869435c96221fbfa8b 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 | 62 +++++++++---------- .../hbase/master/MasterCoprocessorHost.java | 14 +++++ .../hbase/coprocessor/TestMasterObserver.java | 14 ++++- 4 files changed, 72 insertions(+), 33 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 a37f21a8569..a1e9be5b8fd 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 @@ -69,6 +69,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 ecc9bde7855..a023a4f7d0b 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 @@ -2009,45 +2009,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 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 072ae8ae660..2471b54afad 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 @@ -316,6 +316,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 579b6d34e33..42e8424e6b8 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