diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java index d8ebcc9e23..2f817740c9 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java @@ -760,13 +760,15 @@ public class HBaseAdmin implements Admin { CreateTableResponse response = executeCallable( new MasterCallable(getConnection()) { + Long nonceGroup = ng.getNonceGroup(); + Long nonce = ng.newNonce(); @Override public CreateTableResponse call(int callTimeout) throws ServiceException { HBaseRpcController controller = rpcControllerFactory.newController(); controller.setCallTimeout(callTimeout); controller.setPriority(desc.getTableName()); CreateTableRequest request = RequestConverter.buildCreateTableRequest( - desc, splitKeys, ng.getNonceGroup(), ng.newNonce()); + desc, splitKeys, nonceGroup, nonce); return master.createTable(controller, request); } }); @@ -933,13 +935,15 @@ public class HBaseAdmin implements Admin { private Future deleteTableAsyncV2(final TableName tableName) throws IOException { DeleteTableResponse response = executeCallable( new MasterCallable(getConnection()) { + Long nonceGroup = ng.getNonceGroup(); + Long nonce = ng.newNonce(); @Override public DeleteTableResponse call(int callTimeout) throws ServiceException { HBaseRpcController controller = rpcControllerFactory.newController(); controller.setCallTimeout(callTimeout); controller.setPriority(tableName); DeleteTableRequest req = - RequestConverter.buildDeleteTableRequest(tableName, ng.getNonceGroup(),ng.newNonce()); + RequestConverter.buildDeleteTableRequest(tableName, nonceGroup, nonce); return master.deleteTable(controller,req); } }); @@ -1048,10 +1052,12 @@ public class HBaseAdmin implements Admin { public void truncateTable(final TableName tableName, final boolean preserveSplits) throws IOException { executeCallable(new MasterCallable(getConnection()) { + Long nonceGroup = ng.getNonceGroup(); + Long nonce = ng.newNonce(); @Override public Void call(int callTimeout) throws ServiceException { TruncateTableRequest req = RequestConverter.buildTruncateTableRequest( - tableName, preserveSplits, ng.getNonceGroup(), ng.newNonce()); + tableName, preserveSplits, nonceGroup, nonce); master.truncateTable(null, req); return null; } @@ -1184,6 +1190,8 @@ public class HBaseAdmin implements Admin { TableName.isLegalFullyQualifiedTableName(tableName.getName()); EnableTableResponse response = executeCallable( new MasterCallable(getConnection()) { + Long nonceGroup = ng.getNonceGroup(); + Long nonce = ng.newNonce(); @Override public EnableTableResponse call(int callTimeout) throws ServiceException { HBaseRpcController controller = rpcControllerFactory.newController(); @@ -1192,7 +1200,7 @@ public class HBaseAdmin implements Admin { LOG.info("Started enable of " + tableName); EnableTableRequest req = - RequestConverter.buildEnableTableRequest(tableName, ng.getNonceGroup(),ng.newNonce()); + RequestConverter.buildEnableTableRequest(tableName, nonceGroup, nonce); return master.enableTable(controller,req); } }); @@ -1376,6 +1384,8 @@ public class HBaseAdmin implements Admin { TableName.isLegalFullyQualifiedTableName(tableName.getName()); DisableTableResponse response = executeCallable( new MasterCallable(getConnection()) { + Long nonceGroup = ng.getNonceGroup(); + Long nonce = ng.newNonce(); @Override public DisableTableResponse call(int callTimeout) throws ServiceException { HBaseRpcController controller = rpcControllerFactory.newController(); @@ -1385,7 +1395,7 @@ public class HBaseAdmin implements Admin { LOG.info("Started disable of " + tableName); DisableTableRequest req = RequestConverter.buildDisableTableRequest( - tableName, ng.getNonceGroup(), ng.newNonce()); + tableName, nonceGroup, nonce); return master.disableTable(controller, req); } }); @@ -1665,13 +1675,15 @@ public class HBaseAdmin implements Admin { public void addColumn(final TableName tableName, final HColumnDescriptor column) throws IOException { executeCallable(new MasterCallable(getConnection()) { + Long nonceGroup = ng.getNonceGroup(); + Long nonce = ng.newNonce(); @Override public Void call(int callTimeout) throws ServiceException { HBaseRpcController controller = rpcControllerFactory.newController(); controller.setCallTimeout(callTimeout); controller.setPriority(tableName); AddColumnRequest req = RequestConverter.buildAddColumnRequest( - tableName, column, ng.getNonceGroup(), ng.newNonce()); + tableName, column, nonceGroup, nonce); master.addColumn(controller,req); return null; } @@ -1716,13 +1728,15 @@ public class HBaseAdmin implements Admin { public void deleteColumn(final TableName tableName, final byte [] columnName) throws IOException { executeCallable(new MasterCallable(getConnection()) { + Long nonceGroup = ng.getNonceGroup(); + Long nonce = ng.newNonce(); @Override public Void call(int callTimeout) throws ServiceException { HBaseRpcController controller = rpcControllerFactory.newController(); controller.setCallTimeout(callTimeout); controller.setPriority(tableName); DeleteColumnRequest req = RequestConverter.buildDeleteColumnRequest( - tableName, columnName, ng.getNonceGroup(), ng.newNonce()); + tableName, columnName, nonceGroup, nonce); master.deleteColumn(controller, req); return null; } @@ -1767,13 +1781,15 @@ public class HBaseAdmin implements Admin { public void modifyColumn(final TableName tableName, final HColumnDescriptor descriptor) throws IOException { executeCallable(new MasterCallable(getConnection()) { + Long nonceGroup = ng.getNonceGroup(); + Long nonce = ng.newNonce(); @Override public Void call(int callTimeout) throws ServiceException { HBaseRpcController controller = rpcControllerFactory.newController(); controller.setCallTimeout(callTimeout); controller.setPriority(tableName); ModifyColumnRequest req = RequestConverter.buildModifyColumnRequest( - tableName, descriptor, ng.getNonceGroup(), ng.newNonce()); + tableName, descriptor, nonceGroup, nonce); master.modifyColumn(controller, req); return null; } @@ -2839,13 +2855,15 @@ public class HBaseAdmin implements Admin { } executeCallable(new MasterCallable(getConnection()) { + Long nonceGroup = ng.getNonceGroup(); + Long nonce = ng.newNonce(); @Override public Void call(int callTimeout) throws ServiceException { HBaseRpcController controller = rpcControllerFactory.newController(); controller.setCallTimeout(callTimeout); controller.setPriority(tableName); ModifyTableRequest request = RequestConverter.buildModifyTableRequest( - tableName, htd, ng.getNonceGroup(), ng.newNonce()); + tableName, htd, nonceGroup, nonce); master.modifyTable(controller, request); return null; } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAdmin2.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAdmin2.java index db1146bbd9..9654376e40 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAdmin2.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestAdmin2.java @@ -28,18 +28,17 @@ import java.util.List; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; +import com.google.protobuf.ServiceException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.CoprocessorEnvironment; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HRegionLocation; import org.apache.hadoop.hbase.HTableDescriptor; -import org.apache.hadoop.hbase.ipc.HBaseRpcController; -import org.apache.hadoop.hbase.regionserver.Store; -import org.apache.hadoop.hbase.testclassification.LargeTests; import org.apache.hadoop.hbase.MasterNotRunningException; import org.apache.hadoop.hbase.MiniHBaseCluster; import org.apache.hadoop.hbase.NotServingRegionException; @@ -52,11 +51,18 @@ import org.apache.hadoop.hbase.TableNotEnabledException; import org.apache.hadoop.hbase.TableNotFoundException; import org.apache.hadoop.hbase.ZooKeeperConnectionException; import org.apache.hadoop.hbase.constraint.ConstraintException; +import org.apache.hadoop.hbase.coprocessor.BaseMasterObserver; +import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment; +import org.apache.hadoop.hbase.coprocessor.MasterObserver; +import org.apache.hadoop.hbase.coprocessor.ObserverContext; +import org.apache.hadoop.hbase.ipc.HBaseRpcController; import org.apache.hadoop.hbase.master.AssignmentManager; import org.apache.hadoop.hbase.master.HMaster; import org.apache.hadoop.hbase.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.regionserver.HRegionServer; import org.apache.hadoop.hbase.regionserver.Region; +import org.apache.hadoop.hbase.regionserver.Store; +import org.apache.hadoop.hbase.testclassification.LargeTests; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; import org.apache.hadoop.hbase.wal.DefaultWALProvider; @@ -68,8 +74,6 @@ import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; -import com.google.protobuf.ServiceException; - /** * Class to test HBaseAdmin. * Spins up the minicluster once at test start and then takes it down afterward. @@ -78,6 +82,7 @@ import com.google.protobuf.ServiceException; @Category(LargeTests.class) public class TestAdmin2 { private static final Log LOG = LogFactory.getLog(TestAdmin2.class); + private static boolean DELAY_CREATE_TABLE = false; private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); private Admin admin; @@ -88,6 +93,9 @@ public class TestAdmin2 { TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 250); TEST_UTIL.getConfiguration().setInt("hbase.client.retries.number", 6); TEST_UTIL.getConfiguration().setInt("hbase.regionserver.metahandler.count", 30); + TEST_UTIL.getConfiguration() + .setClass("hbase.coprocessor.master.classes", DelayMasterObserver.class, + MasterObserver.class); TEST_UTIL.getConfiguration().setBoolean( "hbase.master.enabletable.roundrobin", true); //Set a very short keeptime for processedServers, see HBASE-18014 @@ -891,4 +899,46 @@ public class TestAdmin2 { assertEquals(initialState, admin.isSnapshotCleanupEnabled()); } + @Test public void testCreateTableTwiceWithNonce() throws Exception { + final TableName tableName = TableName.valueOf("testCreateTableTwiceWithNonce"); + final String cf2 = "cf2"; + final String cf3 = "cf3"; + final HTableDescriptor htd = new HTableDescriptor(tableName); + htd.addFamily(new HColumnDescriptor(cf2)); + htd.addFamily(new HColumnDescriptor(cf3)); + int oldTimeout = TEST_UTIL.getConfiguration(). + getInt(HConstants.HBASE_RPC_TIMEOUT_KEY, HConstants.DEFAULT_HBASE_RPC_TIMEOUT); + TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_RPC_TIMEOUT_KEY, 1500); + try (Admin hbaseadmin = new HBaseAdmin(TEST_UTIL.getConfiguration())) { + DELAY_CREATE_TABLE = true; + hbaseadmin.createTable(htd, null); + } + //should be called once + assertEquals(DelayMasterObserver.preCreateTableCalled, 1); + HTableDescriptor currentHtd = admin.getTableDescriptor(tableName); + assertTrue(currentHtd.hasFamily(Bytes.toBytes(cf2))); + assertTrue(currentHtd.hasFamily(Bytes.toBytes(cf3))); + } + + public static class DelayMasterObserver extends BaseMasterObserver { + static int preCreateTableCalled = 0; + + @Override public void start(CoprocessorEnvironment env) throws IOException { + } + + @Override public void preCreateTable(ObserverContext ctx, + HTableDescriptor desc, HRegionInfo[] regions) throws IOException { + if (desc.getTableName().equals(TableName.valueOf("testCreateTableTwiceWithNonce"))) { + preCreateTableCalled++; + if (DELAY_CREATE_TABLE) { + try { + Thread.sleep(4500); + } catch (InterruptedException e) { + } + DELAY_CREATE_TABLE = false; + } + } + } + } + } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateTableProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateTableProcedure.java index 8860711b45..a402f9ada0 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateTableProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateTableProcedure.java @@ -18,14 +18,14 @@ package org.apache.hadoop.hbase.master.procedure; -import java.io.IOException; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.DoNotRetryIOException; import org.apache.hadoop.hbase.HBaseTestingUtility; -import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.ProcedureInfo; @@ -44,15 +44,11 @@ import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - @Category(MediumTests.class) public class TestCreateTableProcedure { private static final Log LOG = LogFactory.getLog(TestCreateTableProcedure.class); protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); - private static void setupConf(Configuration conf) { conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1); } @@ -249,29 +245,4 @@ public class TestCreateTableProcedure { return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor(); } - public static class FaultyCreateTableProcedure extends CreateTableProcedure { - private int retries = 0; - - public FaultyCreateTableProcedure() { - // Required by the Procedure framework to create the procedure on replay - } - - public FaultyCreateTableProcedure(final MasterProcedureEnv env, - final HTableDescriptor hTableDescriptor, final HRegionInfo[] newRegions) - throws IOException { - super(env, hTableDescriptor, newRegions); - } - - @Override - protected void rollbackState(final MasterProcedureEnv env, final CreateTableState state) - throws IOException { - if (retries++ < 3) { - LOG.info("inject rollback failure state=" + state); - throw new IOException("injected failure number " + retries); - } else { - super.rollbackState(env, state); - retries = 0; - } - } - } }