HBASE-11275 [AccessController] postCreateTable hook fails when another CP creates table on their startup (Anoop Sam John)

This commit is contained in:
Andrew Purtell 2014-05-31 15:01:49 -07:00
parent 4118b0e734
commit af63fba391
3 changed files with 49 additions and 17 deletions

View File

@ -833,6 +833,8 @@ public class HMaster extends HRegionServer implements MasterServices, Server {
// We depend on there being only one instance of this executor running
// at a time. To do concurrency, would need fencing of enable/disable of
// tables.
// Any time changing this maxThreads to > 1, pls see the comment at
// AccessController#postCreateTableHandler
this.service.startExecutorService(ExecutorType.MASTER_TABLE_OPERATIONS, 1);
// Start log cleaner thread

View File

@ -43,7 +43,6 @@ import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.Tag;
import org.apache.hadoop.hbase.TagType;
import org.apache.hadoop.hbase.catalog.MetaReader;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HTable;
@ -135,10 +134,8 @@ public class AccessControlLists {
* @param master reference to HMaster
*/
static void init(MasterServices master) throws IOException {
if (!MetaReader.tableExists(master.getCatalogTracker(), ACL_TABLE_NAME)) {
master.createTable(ACL_TABLEDESC, null);
}
}
/**
* Stores a new user permission grant in the access control lists table.

View File

@ -48,6 +48,7 @@ import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.TableNotDisabledException;
import org.apache.hadoop.hbase.TableNotFoundException;
import org.apache.hadoop.hbase.Tag;
import org.apache.hadoop.hbase.catalog.MetaReader;
import org.apache.hadoop.hbase.client.Append;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Durability;
@ -178,6 +179,9 @@ public class AccessController extends BaseRegionObserver
private volatile boolean initialized = false;
// This boolean having relevance only in the Master.
private volatile boolean aclTabAvailable = false;
public HRegion getRegion() {
return regionEnv != null ? regionEnv.getRegion() : null;
}
@ -837,20 +841,44 @@ public class AccessController extends BaseRegionObserver
@Override
public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> c,
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
if (!AccessControlLists.isAclTable(desc)) {
String owner = desc.getOwnerString();
// default the table owner to current user, if not specified.
if (owner == null) owner = getActiveUser().getShortName();
UserPermission userperm = new UserPermission(Bytes.toBytes(owner), desc.getTableName(), null,
Action.values());
AccessControlLists.addUserPermission(c.getEnvironment().getConfiguration(), userperm);
}
}
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {}
@Override
public void postCreateTableHandler(ObserverContext<MasterCoprocessorEnvironment> c,
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {}
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
// When AC is used, it should be configured as the 1st CP.
// In Master, the table operations like create, are handled by a Thread pool but the max size
// for this pool is 1. So if multiple CPs create tables on startup, these creations will happen
// sequentially only.
// Related code in HMaster#startServiceThreads
// {code}
// // We depend on there being only one instance of this executor running
// // at a time. To do concurrency, would need fencing of enable/disable of
// // tables.
// this.service.startExecutorService(ExecutorType.MASTER_TABLE_OPERATIONS, 1);
// {code}
// In future if we change this pool to have more threads, then there is a chance for thread,
// creating acl table, getting delayed and by that time another table creation got over and
// this hook is getting called. In such a case, we will need a wait logic here which will
// wait till the acl table is created.
if (AccessControlLists.isAclTable(desc)) {
this.aclTabAvailable = true;
} else if (!(TableName.NAMESPACE_TABLE_NAME.equals(desc.getTableName()))) {
if (!aclTabAvailable) {
LOG.warn("Not adding owner permission for table " + desc.getTableName() + ". "
+ AccessControlLists.ACL_TABLE_NAME + " is not yet created. "
+ getClass().getSimpleName() + " should be configured as the first Coprocessor");
} else {
String owner = desc.getOwnerString();
// default the table owner to current user, if not specified.
if (owner == null)
owner = getActiveUser().getShortName();
UserPermission userperm = new UserPermission(Bytes.toBytes(owner), desc.getTableName(),
null, Action.values());
AccessControlLists.addUserPermission(c.getEnvironment().getConfiguration(), userperm);
}
}
}
@Override
public void preDeleteTable(ObserverContext<MasterCoprocessorEnvironment> c, TableName tableName)
@ -1088,8 +1116,13 @@ public class AccessController extends BaseRegionObserver
@Override
public void postStartMaster(ObserverContext<MasterCoprocessorEnvironment> ctx)
throws IOException {
if (!MetaReader.tableExists(ctx.getEnvironment().getMasterServices().getCatalogTracker(),
AccessControlLists.ACL_TABLE_NAME)) {
// initialize the ACL storage table
AccessControlLists.init(ctx.getEnvironment().getMasterServices());
} else {
aclTabAvailable = true;
}
}
@Override