HBASE-13394 Failed to recreate a table when quota is enabled

This commit is contained in:
Matteo Bertozzi 2015-04-27 21:43:39 +01:00
parent 79db629323
commit b96952beef
5 changed files with 83 additions and 15 deletions

View File

@ -1344,8 +1344,7 @@ public class HMaster extends HRegionServer implements MasterServices, Server {
HRegionInfo[] newRegions = ModifyRegionUtils.createHRegionInfos(hTableDescriptor, splitKeys); HRegionInfo[] newRegions = ModifyRegionUtils.createHRegionInfos(hTableDescriptor, splitKeys);
checkInitialized(); checkInitialized();
sanityCheckTableDescriptor(hTableDescriptor); sanityCheckTableDescriptor(hTableDescriptor);
this.quotaManager.checkNamespaceTableAndRegionQuota(hTableDescriptor.getTableName(),
newRegions.length);
if (cpHost != null) { if (cpHost != null) {
cpHost.preCreateTable(hTableDescriptor, newRegions); cpHost.preCreateTable(hTableDescriptor, newRegions);
} }

View File

@ -284,6 +284,11 @@ public class CreateTableProcedure
private void preCreate(final MasterProcedureEnv env) private void preCreate(final MasterProcedureEnv env)
throws IOException, InterruptedException { throws IOException, InterruptedException {
if (!getTableName().isSystemTable()) {
ProcedureSyncWait.getMasterQuotaManager(env)
.checkNamespaceTableAndRegionQuota(getTableName(), newRegions.size());
}
final MasterCoprocessorHost cpHost = env.getMasterCoprocessorHost(); final MasterCoprocessorHost cpHost = env.getMasterCoprocessorHost();
if (cpHost != null) { if (cpHost != null) {
final HRegionInfo[] regions = newRegions == null ? null : final HRegionInfo[] regions = newRegions == null ? null :

View File

@ -53,7 +53,6 @@ import org.apache.hadoop.hbase.protobuf.generated.MasterProcedureProtos;
import org.apache.hadoop.hbase.protobuf.generated.MasterProcedureProtos.DeleteTableState; import org.apache.hadoop.hbase.protobuf.generated.MasterProcedureProtos.DeleteTableState;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.procedure2.StateMachineProcedure; import org.apache.hadoop.hbase.procedure2.StateMachineProcedure;
import org.apache.hadoop.hbase.quotas.MasterQuotaManager;
import org.apache.hadoop.hbase.util.FSUtils; import org.apache.hadoop.hbase.util.FSUtils;
import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.UserGroupInformation;
@ -406,17 +405,6 @@ public class DeleteTableProcedure
protected static void deleteTableStates(final MasterProcedureEnv env, final TableName tableName) protected static void deleteTableStates(final MasterProcedureEnv env, final TableName tableName)
throws IOException { throws IOException {
getMasterQuotaManager(env).removeTableFromNamespaceQuota(tableName); ProcedureSyncWait.getMasterQuotaManager(env).removeTableFromNamespaceQuota(tableName);
}
private static MasterQuotaManager getMasterQuotaManager(final MasterProcedureEnv env)
throws IOException {
return ProcedureSyncWait.waitFor(env, "quota manager to be available",
new ProcedureSyncWait.Predicate<MasterQuotaManager>() {
@Override
public MasterQuotaManager evaluate() throws IOException {
return env.getMasterServices().getMasterQuotaManager();
}
});
} }
} }

View File

@ -42,6 +42,7 @@ import org.apache.hadoop.hbase.master.ServerManager;
import org.apache.hadoop.hbase.procedure2.Procedure; import org.apache.hadoop.hbase.procedure2.Procedure;
import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
import org.apache.hadoop.hbase.procedure2.ProcedureResult; import org.apache.hadoop.hbase.procedure2.ProcedureResult;
import org.apache.hadoop.hbase.quotas.MasterQuotaManager;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
import org.apache.hadoop.hbase.util.Threads; import org.apache.hadoop.hbase.util.Threads;
import org.apache.hadoop.hbase.zookeeper.MetaTableLocator; import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
@ -176,4 +177,15 @@ public final class ProcedureSyncWait {
}); });
} }
} }
protected static MasterQuotaManager getMasterQuotaManager(final MasterProcedureEnv env)
throws IOException {
return ProcedureSyncWait.waitFor(env, "quota manager to be available",
new ProcedureSyncWait.Predicate<MasterQuotaManager>() {
@Override
public MasterQuotaManager evaluate() throws IOException {
return env.getMasterServices().getMasterQuotaManager();
}
});
}
} }

View File

@ -23,6 +23,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
@ -41,6 +42,7 @@ import org.apache.hadoop.hbase.CoprocessorEnvironment;
import org.apache.hadoop.hbase.DoNotRetryIOException; import org.apache.hadoop.hbase.DoNotRetryIOException;
import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.MiniHBaseCluster; import org.apache.hadoop.hbase.MiniHBaseCluster;
@ -100,6 +102,7 @@ public class TestNamespaceAuditor {
UTIL.getConfiguration().set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, UTIL.getConfiguration().set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
MasterSyncObserver.class.getName()); MasterSyncObserver.class.getName());
Configuration conf = UTIL.getConfiguration(); Configuration conf = UTIL.getConfiguration();
conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 5);
conf.setBoolean(QuotaUtil.QUOTA_CONF_KEY, true); conf.setBoolean(QuotaUtil.QUOTA_CONF_KEY, true);
conf.setClass("hbase.coprocessor.regionserver.classes", CPRegionServerObserver.class, conf.setClass("hbase.coprocessor.regionserver.classes", CPRegionServerObserver.class,
RegionServerObserver.class); RegionServerObserver.class);
@ -470,6 +473,58 @@ public class TestNamespaceAuditor {
htable.close(); htable.close();
} }
/*
* Create a table and make sure that the table creation fails after adding this table entry into
* namespace quota cache. Now correct the failure and recreate the table with same name.
* HBASE-13394
*/
@Test(timeout = 180000)
public void testRecreateTableWithSameNameAfterFirstTimeFailure() throws Exception {
String nsp1 = prefix + "_testRecreateTable";
NamespaceDescriptor nspDesc =
NamespaceDescriptor.create(nsp1)
.addConfiguration(TableNamespaceManager.KEY_MAX_REGIONS, "20")
.addConfiguration(TableNamespaceManager.KEY_MAX_TABLES, "1").build();
ADMIN.createNamespace(nspDesc);
final TableName tableOne = TableName.valueOf(nsp1 + TableName.NAMESPACE_DELIM + "table1");
byte[] columnFamily = Bytes.toBytes("info");
HTableDescriptor tableDescOne = new HTableDescriptor(tableOne);
tableDescOne.addFamily(new HColumnDescriptor(columnFamily));
MasterSyncObserver.throwExceptionInPreCreateTableHandler = true;
try {
try {
ADMIN.createTable(tableDescOne);
fail("Table " + tableOne.toString() + "creation should fail.");
} catch (Exception exp) {
LOG.error(exp);
}
assertFalse(ADMIN.tableExists(tableOne));
NamespaceTableAndRegionInfo nstate = getNamespaceState(nsp1);
assertEquals("First table creation failed in namespace so number of tables in namespace "
+ "should be 0.", 0, nstate.getTables().size());
MasterSyncObserver.throwExceptionInPreCreateTableHandler = false;
try {
ADMIN.createTable(tableDescOne);
} catch (Exception e) {
fail("Table " + tableOne.toString() + "creation should succeed.");
LOG.error(e);
}
assertTrue(ADMIN.tableExists(tableOne));
nstate = getNamespaceState(nsp1);
assertEquals("First table was created successfully so table size in namespace should "
+ "be one now.", 1, nstate.getTables().size());
} finally {
MasterSyncObserver.throwExceptionInPreCreateTableHandler = false;
if (ADMIN.tableExists(tableOne)) {
ADMIN.disableTable(tableOne);
deleteTable(tableOne);
}
ADMIN.deleteNamespace(nsp1);
}
}
private NamespaceTableAndRegionInfo getNamespaceState(String namespace) throws KeeperException, private NamespaceTableAndRegionInfo getNamespaceState(String namespace) throws KeeperException,
IOException { IOException {
return getQuotaManager().getState(namespace); return getQuotaManager().getState(namespace);
@ -569,6 +624,7 @@ public class TestNamespaceAuditor {
public static class MasterSyncObserver extends BaseMasterObserver { public static class MasterSyncObserver extends BaseMasterObserver {
volatile CountDownLatch tableDeletionLatch; volatile CountDownLatch tableDeletionLatch;
static boolean throwExceptionInPreCreateTableHandler;
@Override @Override
public void preDeleteTable(ObserverContext<MasterCoprocessorEnvironment> ctx, public void preDeleteTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
@ -582,6 +638,14 @@ public class TestNamespaceAuditor {
throws IOException { throws IOException {
tableDeletionLatch.countDown(); tableDeletionLatch.countDown();
} }
@Override
public void preCreateTableHandler(ObserverContext<MasterCoprocessorEnvironment> ctx,
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
if (throwExceptionInPreCreateTableHandler) {
throw new IOException("Throw exception as it is demanded.");
}
}
} }
private void deleteTable(final TableName tableName) throws Exception { private void deleteTable(final TableName tableName) throws Exception {