Skip to content

Commit

Permalink
HBASE-13394 Failed to recreate a table when quota is enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
Matteo Bertozzi committed Apr 27, 2015
1 parent 79db629 commit b96952b
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 15 deletions.
Expand Up @@ -1344,8 +1344,7 @@ public long createTable(HTableDescriptor hTableDescriptor,
HRegionInfo[] newRegions = ModifyRegionUtils.createHRegionInfos(hTableDescriptor, splitKeys);
checkInitialized();
sanityCheckTableDescriptor(hTableDescriptor);
this.quotaManager.checkNamespaceTableAndRegionQuota(hTableDescriptor.getTableName(),
newRegions.length);

if (cpHost != null) {
cpHost.preCreateTable(hTableDescriptor, newRegions);
}
Expand Down
Expand Up @@ -284,6 +284,11 @@ private boolean prepareCreate(final MasterProcedureEnv env) throws IOException {

private void preCreate(final MasterProcedureEnv env)
throws IOException, InterruptedException {
if (!getTableName().isSystemTable()) {
ProcedureSyncWait.getMasterQuotaManager(env)
.checkNamespaceTableAndRegionQuota(getTableName(), newRegions.size());
}

final MasterCoprocessorHost cpHost = env.getMasterCoprocessorHost();
if (cpHost != null) {
final HRegionInfo[] regions = newRegions == null ? null :
Expand Down
Expand Up @@ -53,7 +53,6 @@
import org.apache.hadoop.hbase.protobuf.generated.MasterProcedureProtos.DeleteTableState;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
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.security.UserGroupInformation;

Expand Down Expand Up @@ -406,17 +405,6 @@ protected static void deleteTableDescriptorCache(final MasterProcedureEnv env,

protected static void deleteTableStates(final MasterProcedureEnv env, final TableName tableName)
throws IOException {
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();
}
});
ProcedureSyncWait.getMasterQuotaManager(env).removeTableFromNamespaceQuota(tableName);
}
}
Expand Up @@ -42,6 +42,7 @@
import org.apache.hadoop.hbase.procedure2.Procedure;
import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
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.Threads;
import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
Expand Down Expand Up @@ -176,4 +177,15 @@ public Boolean evaluate() throws IOException {
});
}
}

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();
}
});
}
}
Expand Up @@ -23,6 +23,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.IOException;
import java.util.Collections;
Expand All @@ -41,6 +42,7 @@
import org.apache.hadoop.hbase.DoNotRetryIOException;
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.HTableDescriptor;
import org.apache.hadoop.hbase.MiniHBaseCluster;
Expand Down Expand Up @@ -100,6 +102,7 @@ public static void before() throws Exception {
UTIL.getConfiguration().set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
MasterSyncObserver.class.getName());
Configuration conf = UTIL.getConfiguration();
conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 5);
conf.setBoolean(QuotaUtil.QUOTA_CONF_KEY, true);
conf.setClass("hbase.coprocessor.regionserver.classes", CPRegionServerObserver.class,
RegionServerObserver.class);
Expand Down Expand Up @@ -470,6 +473,58 @@ public void testRegionOperations() throws Exception {
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,
IOException {
return getQuotaManager().getState(namespace);
Expand Down Expand Up @@ -569,6 +624,7 @@ private NamespaceAuditor getQuotaManager() {

public static class MasterSyncObserver extends BaseMasterObserver {
volatile CountDownLatch tableDeletionLatch;
static boolean throwExceptionInPreCreateTableHandler;

@Override
public void preDeleteTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
Expand All @@ -582,6 +638,14 @@ public void postDeleteTableHandler(
throws IOException {
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 {
Expand Down

0 comments on commit b96952b

Please sign in to comment.