oracle.kv.impl.admin.plan.Planner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of oracle-nosql-server Show documentation
Show all versions of oracle-nosql-server Show documentation
NoSQL Database Server - supplies build and runtime support for the server (store) side of the Oracle NoSQL Database.
/*-
* Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle NoSQL
* Database made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle NoSQL Database for a copy of the license and
* additional information.
*/
package oracle.kv.impl.admin.plan;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import oracle.kv.KVVersion;
import oracle.kv.impl.admin.Admin;
import oracle.kv.impl.admin.AdminServiceParams;
import oracle.kv.impl.admin.CommandResult;
import oracle.kv.impl.admin.IllegalCommandException;
import oracle.kv.impl.admin.NonfatalAssertionException;
import oracle.kv.impl.admin.PlanLocksHeldException;
import oracle.kv.impl.admin.SnConsistencyUtils.ParamCheckResults;
import oracle.kv.impl.admin.param.StorageNodeParams;
import oracle.kv.impl.admin.plan.Plan.State;
import oracle.kv.impl.admin.plan.task.Utils;
import oracle.kv.impl.api.table.FieldMap;
import oracle.kv.impl.api.table.IndexImpl.AnnotatedField;
import oracle.kv.impl.api.table.TableImpl;
import oracle.kv.impl.api.table.TableLimits;
import oracle.kv.impl.fault.CommandFaultException;
import oracle.kv.impl.fault.OperationFaultException;
import oracle.kv.impl.param.ParameterMap;
import oracle.kv.impl.topo.AdminId;
import oracle.kv.impl.topo.AdminType;
import oracle.kv.impl.topo.ArbNodeId;
import oracle.kv.impl.topo.DatacenterId;
import oracle.kv.impl.topo.DatacenterType;
import oracle.kv.impl.topo.RepGroupId;
import oracle.kv.impl.topo.RepNodeId;
import oracle.kv.impl.topo.ResourceId;
import oracle.kv.impl.topo.StorageNodeId;
import oracle.kv.impl.util.KVThreadFactory;
import oracle.kv.impl.util.server.LoggerUtils;
import oracle.kv.table.FieldDef;
import oracle.kv.table.TimeToLive;
import oracle.kv.util.ErrorMessage;
/**
* The Planner creates and executes plans. Plans are the means by which
* topological changes are made to a store. They are also used for creating
* and modifying system metadata, such as tables, indexes, and security
* information.
*
* Plan creation consists of populating the plan with tasks which perform the
* actual work. A single plan often comprises a number of tasks. Plan
* execution is asynchronous, which is especially important to long-running
* plans and those which affect many nodes in the system. Plan execution is
* idempotent in order to be resilient in the face of node failures, including
* that of the admin node handling the plan.
*
* Error Handling
* ==============
* IllegalCommandException is used to indicate user error, such as a bad
* parameter, or a user-provoked illegal plan transition. It is thrown
* synchronously, in direct response to a user action. Examples:
* Bad parameter when creating a plan:
* - The user should fix the parameter and resubmit the
* User tries an illegal plan state transition, such as executing a plan that
* is not approved, approving a plan that is not pending, or executing a plan
* that has completed, etc.
* - The user should be notified that this was an illegal action
*
* OperationFaultException is thrown when plan execution runs into some kind of
* resource problem, such as a RejectedExecutionException from lack of threads,
* or a network problem, lack of ports, timeout, etc. In this case, the user is
* notified and the GUI will present the option of retrying or rolling back the
* plan.
*
* An AdminFaultException is thrown when an unexpected exception occurs during
* plan execution. The fault handler processes the exception in such a way that
* the Admin will not go down, but that the exception will be logged under
* SEVERE and will be dumped to stderr. The problem is not going to get any
* better without installing a bug fix, but the Admin should not go down.
* The UI presents the option of retrying or rolling back the plan.
*
* Concurrency Limitations:
* ========================
* Plans may be created and approved for an indeterminate amount of
* time before they are executed. However, topology dependent plans must clone
* a copy of the topology at creation time, and use that to create a set of
* directions to execute. Because of that, the topology must stay constant from
* that point to execution point, and therefore only one topology changing
* plan can be implemented at a time.
*
* Synchronization:
* ========================
*
* New plan creation is serialized by synchronizing on the planner object (via
* method synchronization). Manipulation of existing plans, such as execution
* or restart etc, is synchronized at the Admin.
*
* In general, we would like to express the monitor locking sequence as going
* from big objects to smaller objects, so the Admin would be locked before the
* Planner, and the Planner before the Plan. However we observe that in some
* cases the plan is locked and then wants to update itself, requiring it the
* thread to synchronize on the Planner, violating the aforementioned ideal.
* Hence the desire to eliminate synchronization on the Planner for updates to
* existing plans. This is a TBD: see deadlocks described in [#22963] and
* [#22992], both of which we believe have been eliminated, but other deadlocks
* might be lurking, and therefore a comprehensive survey of synchronization in
* Admin is called for.
*/
public class Planner {
/**
* The executor that we'll use for carrying out execution of the plan and
* the tasks within it.
*/
private ExecutorService executor;
private final Logger logger;
private final Admin admin;
private final AtomicInteger planIdGenerator;
/**
* A dummy plan ID for use when locking for a command, not a plan. This
* value will be different from all real plan IDs, because they are
* non-negative.
*/
private static final int COMMAND_LOCK_PLAN_ID = -1;
private final Catalog catalog;
/**
*/
public Planner(Admin admin,
AdminServiceParams params,
int nextPlanId) {
this.admin = admin;
logger = LoggerUtils.getLogger(this.getClass(), params);
executor = Executors.newCachedThreadPool
(new KVThreadFactory("Planner", logger));
catalog = new Catalog();
planIdGenerator = new AtomicInteger(nextPlanId);
}
/**
* Returns the next plan ID.
*/
public int getNextPlanId() {
return planIdGenerator.get();
}
/**
* Returns the next plan ID and advances the ID. The new ID is persisted.
*/
public int getAndIncrementPlanId() {
final int next = planIdGenerator.getAndIncrement();
admin.saveNextId(planIdGenerator.get());
return next;
}
/**
* Review all in progress plans. Anything that is in RUNNING state did
* not finish, and should be deemed to be interrupted. Should be called
* by the Admin explicitly after the planner is constructed.
* {@literal
* 1.RUNNING plans ->INTERRUPT_REQUESTED -> INTERRUPTED, and
* will be restarted.
* 2.INTERRUPT_REQUESTED plans -> INTERRUPTED and are not restarted. The
* failover is as if the cleanup phase was interrupted by the user.
* 3.INTERRUPTED plans are left as is.
* }
*/
public Plan recover(Plan inProgressPlan) {
if (inProgressPlan == null) {
return null;
}
Plan restart = null;
final State originalState = inProgressPlan.getState();
if (inProgressPlan.getState() == State.RUNNING) {
inProgressPlan.markAsInterrupted();
/* Rerun it */
restart = inProgressPlan;
}
if (inProgressPlan.getState() == State.INTERRUPT_REQUESTED) {
/*
* Let it move to interrupted state and stay there. The user had
* previously requested an interrupt.
*/
inProgressPlan.markAsInterrupted();
}
logger.log(Level.INFO,
"{0} originally in {1}, transitioned to {2}, {3} be " +
"restarted automatically",
new Object[] {inProgressPlan, originalState,
inProgressPlan.getState(),
(restart == null) ? "will not" : "will"});
/*
* All non-terminated plans, including those that are in ERROR or
* INTERRUPT state should be put in the catalog. Even the
* non-restarted ones need to be there, so the user can decide manually
* whether to retry them.
*/
registerForRecovery(inProgressPlan);
admin.savePlan(inProgressPlan, "Plan Recovery");
return restart;
}
/**
* Registers the specified plan. Package access for unit test.
*/
void register(Plan plan) {
catalog.addNewPlan(plan, false);
}
/**
* Registers the specified plan for recovery. Concerning exclusivity,
* different rules apply during recovery.
*/
private void registerForRecovery(Plan plan) {
catalog.addNewPlan(plan, true);
}
/* For unit test support. */
public void clearLocks(int planId) {
catalog.clearLocks(planId);
}
public void clearLocksForCommand() {
catalog.clearLocks(COMMAND_LOCK_PLAN_ID);
}
/**
* Shuts down the planner. No new plans will be executed. If force is true
* any running plans are interrupted. If force is false and wait is true
* then this method will wait for executing plans to complete. The wait
* flag is ignored if force is true.
*
* @param force interrupt running plans if true
* @param wait wait for running plans to complete if force is false
*/
public void shutdown(boolean force, boolean wait) {
if (force) {
executor.shutdownNow();
return;
}
executor.shutdown();
if (wait) {
try {
executor.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
logger.log(Level.INFO, "Shutdown Planner failed: {0}", e);
}
}
}
/**
* Returns true if the planner has been shutdown.
*
* @return true if the planner has been shutdown
*/
public boolean isShutdown() {
return executor.isShutdown();
}
/*
* NOTE that all plan creation is serial, so that each type of plan can
* validate itself in a stable context. The catalog, and plan registration,
* check for runtime constraints, such as plan exclusiveness, but since
* registration is only done after the plan is created, it can't validate
* for non-runtime constraints. For example, the DeployStorePlan must
* check whether the topology holds any other repNodes at creation time.
*/
/**
* Creates a data center and registers it with the topology.
*/
public synchronized int
createDeployDatacenterPlan(String planName,
String datacenterName,
int repFactor,
DatacenterType datacenterType,
boolean allowArbiters,
boolean masterAffinity) {
final DeployDatacenterPlan plan =
new DeployDatacenterPlan(planName, this,
admin.getCurrentTopology(),
datacenterName, repFactor,
datacenterType,
allowArbiters,
masterAffinity);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a storage node and registers it with the topology.
*/
public synchronized int
createDeploySNPlan(String planName,
DatacenterId datacenterId,
StorageNodeParams inputSNP) {
final DeploySNPlan plan =
new DeploySNPlan(planName, this,
admin.getCurrentTopology(),
datacenterId, inputSNP);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates an Admin instance and updates the Parameters to reflect it.
*/
public synchronized int createDeployAdminPlan(String name,
StorageNodeId snid,
AdminType type) {
final DeployAdminPlan plan = new DeployAdminPlan(name,
this, snid,
type);
register(plan);
return admin.saveCreatePlan(plan);
}
/*
* Creates a PRIMARY Admin instance. For unit tests.
*/
public int createDeployAdminPlan(String name,
StorageNodeId snid) {
return createDeployAdminPlan(name, snid, AdminType.PRIMARY);
}
/**
* If victim
is not null
, then removes the Admin
* with specified AdminId
. Otherwise, if dcid
is
* not null
, then removes all Admins in the specified
* datacenter. If failedSN
is true then remove admins hosted
* on the failed SNs.
*/
public synchronized int createRemoveAdminPlan(String name,
DatacenterId dcid,
AdminId victim,
boolean failedSN) {
/*
* Don't allow removal of admin hosted on failed SN support
* with failedSN flag until all of the Admins are upgraded.
* Otherwise, failedSN value may be lost if an older Admin
* becomes the master and reads then writes failedSN information.
* We are avoiding SN version check on failed SN hosting to
* be removed Admin.
*/
final KVVersion FAILED_SN_SUPPORT = KVVersion.R18_1;
if ((failedSN) &&
!admin.checkAdminGroupVersion(FAILED_SN_SUPPORT,
victim, failedSN)) {
throw new IllegalCommandException(
"Cannot support removal of admin hosted on failed" +
"SN until all Admin nodes are at or above software version " +
FAILED_SN_SUPPORT.getNumericVersionString());
}
final RemoveAdminPlan plan =
new RemoveAdminPlan(name, this, dcid, victim, failedSN);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to deploy the specified TopologyCandidate. Allow
* for passing for failedShard parameter during deploy topology
*/
public synchronized int createDeployTopoPlan(String planName,
String candidateName,
RepGroupId failedShard) {
/*
* Don't allow removing failed shard support until all of the
* Admins are upgraded. Otherwise, failedShard value may be lost
* if an older Admin becomes the master and reads then writes
* failed shard information.
*/
final KVVersion FAILED_SHARD_SUPPORT = KVVersion.R18_1;
if ((failedShard != null) &&
!admin.checkAdminGroupVersion(FAILED_SHARD_SUPPORT,
failedShard)) {
throw new IllegalCommandException(
"Cannot support failed shard removal until" +
"all Admin nodes are at or above software version " +
FAILED_SHARD_SUPPORT.getNumericVersionString());
}
final DeployTopoPlan plan =
DeployTopoPlan.create(planName,
this,
admin.getCurrentTopology(),
admin.getCandidate(candidateName),
failedShard);
register(plan);
return admin.saveCreatePlan(plan);
}
public synchronized int createFailoverPlan(
String planName,
Set newPrimaryZones,
Set offlineZones) {
final FailoverPlan plan = FailoverPlan.create(
planName, this, admin.getCurrentTopology(),
newPrimaryZones, offlineZones);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to stop of all RepNodes in the store.
*/
public synchronized int
createStopAllRepNodesPlan(String planName) {
final StopAllRepNodesPlan plan =
new StopAllRepNodesPlan(planName, this,
admin.getCurrentTopology());
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to start all RepNodes the store.
*/
public synchronized int
createStartAllRepNodesPlan(String planName) {
final StartAllRepNodesPlan plan =
new StartAllRepNodesPlan(planName, this,
admin.getCurrentTopology());
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to stop the given set of RepNodes.
*/
public synchronized int
createStopRepNodesPlan(String planName, Set rnids) {
final StopRepNodesPlan plan =
new StopRepNodesPlan(planName, this,
admin.getCurrentTopology(), rnids);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to start the given set of RepNodes.
*/
public synchronized int
createStartRepNodesPlan(String planName, Set rnids) {
final StartRepNodesPlan plan =
new StartRepNodesPlan(planName, this,
admin.getCurrentTopology(), rnids);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to stop the specified services.
*/
public synchronized int
createStopServicesPlan(String planName,
Set extends ResourceId> serviceIds) {
final Plan plan = new StopServicesPlan(planName, this,
admin.getCurrentTopology(),
serviceIds);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to start the specified services.
*/
public synchronized int
createStartServicesPlan(String planName,
Set extends ResourceId> serviceIds) {
final Plan plan = new StartServicesPlan(planName, this,
admin.getCurrentTopology(),
serviceIds);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan for replacing a potentially failed node in the store.
* Any resources known to be allocated on the failed node will be
* moved to the new node. The new node must be an as yet unused node.
*/
public synchronized int
createMigrateSNPlan(String planName,
StorageNodeId oldNode,
StorageNodeId newNode) {
final MigrateSNPlan plan =
new MigrateSNPlan(planName, this,
admin.getCurrentTopology(),
oldNode, newNode);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan for removing a storageNode. Removal is only permitted
* for stopped storageNodes which do not house any services. It's meant to
* remove defunct storageNodes after a migration has been run, or if
* an initial deployment failed.
*/
public synchronized int
createRemoveSNPlan(String planName,
StorageNodeId targetNode) {
final RemoveSNPlan plan =
new RemoveSNPlan(planName, this,
admin.getCurrentTopology(), targetNode);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan for removing a datacenter. Removal is only permitted for
* empty datacenters; that is, datacenters which contain no
* storage nodes.
*/
public synchronized int
createRemoveDatacenterPlan(String planName,
DatacenterId targetId) {
final RemoveDatacenterPlan plan =
new RemoveDatacenterPlan(planName, this,
admin.getCurrentTopology(),
targetId);
register(plan);
return admin.saveCreatePlan(plan);
}
public synchronized int createAddTablePlan(String planName,
TableImpl table,
String parentName,
boolean systemPlan) {
final Plan plan = TablePlanGenerator.
createAddTablePlan(planName, this,
table, parentName, systemPlan);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates evolve table plan for user tables.
*/
public int createEvolveTablePlan(String planName,
String namespace,
String tableName,
int tableVersion,
FieldMap fieldMap,
TimeToLive ttl) {
return createEvolveTablePlan(planName,
namespace,
tableName,
tableVersion,
fieldMap,
ttl,
null, /* description (no change) */
false /* systemTable */);
}
/**
* Creates evolve table plan.
*/
public synchronized int createEvolveTablePlan(String planName,
String namespace,
String tableName,
int tableVersion,
FieldMap fieldMap,
TimeToLive ttl,
String description,
boolean systemTable) {
final Plan plan = TablePlanGenerator.
createEvolveTablePlan(planName, this,
namespace,
tableName,
tableVersion, fieldMap,
ttl,
description,
systemTable);
register(plan);
return admin.saveCreatePlan(plan);
}
public synchronized int createRemoveTablePlan(String planName,
String namespace,
String tableName) {
final Plan plan = TablePlanGenerator.
createRemoveTablePlan(planName, this,
admin.getCurrentTopology(),
namespace, tableName);
register(plan);
return admin.saveCreatePlan(plan);
}
public synchronized int createAddIndexPlan(String planName,
String namespace,
String indexName,
String tableName,
String[] indexedFields,
FieldDef.Type[] indexedTypes,
String description) {
final Plan plan = TablePlanGenerator.
createAddIndexPlan(planName, this,
admin.getCurrentTopology(),
namespace, indexName, tableName,
indexedFields, indexedTypes, description);
register(plan);
return admin.saveCreatePlan(plan);
}
public synchronized int createRemoveIndexPlan(String planName,
String namespace,
String indexName,
String tableName,
boolean override) {
final Plan plan = TablePlanGenerator.
createRemoveIndexPlan(planName, this,
admin.getCurrentTopology(),
namespace, indexName, tableName, override);
register(plan);
return admin.saveCreatePlan(plan);
}
public synchronized int createAddTextIndexPlan
(String planName, String namespace, String indexName, String tableName,
AnnotatedField[] ftsFields, Map properties,
String description, boolean override) {
final Plan plan = TablePlanGenerator.
createAddTextIndexPlan(planName, this,
namespace, indexName, tableName,
ftsFields, properties, description,
override);
register(plan);
return admin.saveCreatePlan(plan);
}
public synchronized int createBroadcastTableMDPlan() {
final Plan plan = TablePlanGenerator.createBroadcastTableMDPlan(this);
register(plan);
return admin.saveCreatePlan(plan);
}
public synchronized int createBroadcastSecurityMDPlan() {
final Plan plan = SecurityMetadataPlan.
createBroadcastSecurityMDPlan(this);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* TODO: future: consolidate change parameters plans for RN, SN, and admin.
*/
public synchronized int
createChangeParamsPlan(String planName,
ResourceId rid,
ParameterMap newParams) {
Plan plan = null;
if (rid instanceof RepNodeId) {
final Set ids = new HashSet<>();
ids.add((RepNodeId) rid);
plan =
new ChangeParamsPlan(planName, this,
admin.getCurrentTopology(),
ids, newParams);
} else if (rid instanceof StorageNodeId) {
plan =
new ChangeSNParamsPlan(planName, this,
(StorageNodeId) rid, newParams);
} else if (rid instanceof AdminId) {
plan =
new ChangeAdminParamsPlan(planName, this,
(AdminId) rid, newParams);
} else if (rid instanceof ArbNodeId) {
final Set ids = new HashSet<>();
ids.add((ArbNodeId) rid);
plan =
new ChangeANParamsPlan(planName, this,
admin.getCurrentTopology(),
ids, newParams);
}
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to apply parameters to all ArbNodes deployed in the
* specified datacenter or if null, to all ArbNodes in the store.
*/
public synchronized int
createChangeAllANParamsPlan(String planName,
DatacenterId dcid,
ParameterMap newParams) {
Set anIds = admin.getCurrentTopology().getArbNodeIds(dcid);
final Plan plan =
new ChangeANParamsPlan(planName, this,
admin.getCurrentTopology(),
anIds, newParams);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to apply parameters to all RepNodes deployed in the
* specified datacenter.
*/
public synchronized int
createChangeAllParamsPlan(String planName,
DatacenterId dcid,
ParameterMap newParams) {
final Plan plan =
new ChangeAllParamsPlan(planName, this,
admin.getCurrentTopology(),
dcid, newParams);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to apply parameters to all Admins deployed in the
* specified datacenter.
*/
public synchronized int
createChangeAllAdminsPlan(String planName,
DatacenterId dcid,
ParameterMap newParams) {
final Plan plan =
new ChangeAdminParamsPlan(planName, this, null,
dcid, admin.getCurrentTopology(),
newParams);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to apply new global components parameters to all services
* deployed in the store.
*/
public synchronized int
createChangeGlobalComponentsParamsPlan(String planName,
ParameterMap newParams,
boolean isSystemPlan) {
final Plan plan =
new ChangeGlobalComponentsParamsPlan(planName, this,
admin.getCurrentTopology(),
newParams,
isSystemPlan);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to apply new global security parameters to all services
* deployed in the store.
*/
public synchronized int
createChangeGlobalSecurityParamsPlan(String planName,
ParameterMap newParams) {
final Plan plan =
new ChangeGlobalSecurityParamsPlan(planName, this,
admin.getCurrentTopology(),
newParams);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a user and add it to the kvstore. Keep for compatible with
* clients earlier than R3.3.
*/
@Deprecated
public synchronized int
createCreateUserPlan(String planName,
String userName,
boolean isEnabled,
boolean isAdmin,
char[] plainPassword) {
return createCreateUserPlan(planName, userName, isEnabled, isAdmin,
plainPassword, null /* pwdLifetime*/ );
}
/**
* Creates a user and add it to the kvstore.
*/
public synchronized int
createCreateUserPlan(String planName,
String userName,
boolean isEnabled,
boolean isAdmin,
char[] plainPassword,
Long pwdLifetime) {
final SecurityMetadataPlan plan =
SecurityMetadataPlan.createCreateUserPlan(
planName, this, userName, isEnabled,
isAdmin, plainPassword, pwdLifetime);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates an external user and add it to the kvstore.
*/
public synchronized int
createCreateExternalUserPlan(String planName,
String userName,
boolean isEnabled,
boolean isAdmin) {
final SecurityMetadataPlan plan =
SecurityMetadataPlan.createCreateExternalUserPlan(
planName, this, userName, isEnabled, isAdmin);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Changes the information of a kvstore user.
*/
public synchronized int
createChangeUserPlan(String planName,
String userName,
Boolean isEnabled,
char[] plainPassword,
boolean retainPassword,
boolean clearRetainedPassword,
Long pwdLifetime) {
final SecurityMetadataPlan plan =
SecurityMetadataPlan.createChangeUserPlan(
planName, this, userName, isEnabled,
plainPassword, retainPassword, clearRetainedPassword,
pwdLifetime);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Changes the information of a kvstore user. Keep for compatible with
* clients earlier than R3.3.
*/
@Deprecated
public synchronized int
createChangeUserPlan(String planName,
String userName,
Boolean isEnabled,
char[] plainPassword,
boolean retainPassword,
boolean clearRetainedPassword) {
return createChangeUserPlan(
planName, userName, isEnabled, plainPassword, retainPassword,
clearRetainedPassword, null /* pwdLifeTime */);
}
/**
* Removes a user with the specified name from the store. Keep for
* compatible with clients earlier than R3.3.
*/
@Deprecated
public synchronized int
createDropUserPlan(String planName, String userName) {
return createDropUserPlan(planName, userName, false /* cascade */);
}
/**
* Removes a user with the specified name from the store.
*/
public synchronized int
createDropUserPlan(String planName, String userName, boolean cascade) {
final AbstractPlan plan = SecurityMetadataPlan.createDropUserPlan(
planName, this, userName, cascade);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a user-defined role and add it to the kvstore.
*/
public synchronized int createCreateRolePlan(String planName,
String roleName) {
final SecurityMetadataPlan plan =
SecurityMetadataPlan.createCreateRolePlan(planName, this, roleName);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Removes a user-defined role with the specified name from the store.
*/
public synchronized int createDropRolePlan(String planName,
String roleName) {
final SecurityMetadataPlan plan =
SecurityMetadataPlan.createDropRolePlan(planName, this, roleName);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Grant given roles to user in the store.
*/
public synchronized int
createGrantPlan(String planName, String grantee, Set roles) {
final SecurityMetadataPlan plan =
SecurityMetadataPlan.createGrantPlan(planName,
this, grantee, roles);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Grant given roles to another role.
*/
public synchronized int
createGrantRolesToRolePlan(String planName,
String grantee,
Set roles) {
final SecurityMetadataPlan plan =
SecurityMetadataPlan.createGrantRolesToRolePlan(
planName, this, grantee, roles);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Revoke given roles from user in the store.
*/
public synchronized int
createRevokePlan(String planName, String revokee, Set roles) {
final SecurityMetadataPlan plan =
SecurityMetadataPlan.createRevokePlan(planName,
this, revokee, roles);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Grant given roles to another role.
*/
public synchronized int
createRevokeRolesFromRolePlan(String planName,
String revokee,
Set roles) {
final SecurityMetadataPlan plan =
SecurityMetadataPlan.createRevokeRolesFromRolePlan(
planName, this, revokee, roles);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan that grants a set of privileges on, optionally, a table
* to a role.
*
* @param planName plan name
* @param roleName role name
* @param tableName table name, null if granting only system privileges
* @param privs privileges to grant
* @return planId
*/
public synchronized int
createGrantPrivilegePlan(String planName,
String roleName,
String namespace,
String tableName,
Set privs) {
final SecurityMetadataPlan plan =
SecurityMetadataPlan.createGrantPrivsPlan(planName,
this, roleName, namespace,
tableName, privs);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan that revokes a set of privileges on, optionally, a table
* from a role.
*
* @param planName plan name
* @param roleName role name
* @param tableName table name, null if revoking only system privileges
* @param privs privileges to revoke
* @return planId
*/
public synchronized int
createRevokePrivilegePlan(String planName,
String roleName,
String namespace,
String tableName,
Set privs) {
final SecurityMetadataPlan plan =
SecurityMetadataPlan.createRevokePrivsPlan(
planName, this, roleName, namespace,
tableName, privs);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan that grants a set of privileges on a namespace to a role.
*
* @param planName plan name
* @param roleName role name
* @param namespace namespace name
* @param privs privileges to grant
* @return planId
*/
public synchronized int
createGrantNamespacePrivilegePlan(String planName,
String roleName,
String namespace,
Set privs) {
final SecurityMetadataPlan plan =
SecurityMetadataPlan.createGrantNamespacePrivsPlan(
planName, this, roleName, namespace, privs);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan that revokes a set of privileges on a namespace
* from a role.
*
* @param planName plan name
* @param roleName role name
* @param namespace namespace name, null if revoking only system privileges
* @param privs privileges to revoke
* @return planId
*/
public synchronized int
createRevokeNamespacePrivilegePlan(String planName,
String roleName,
String namespace,
Set privs) {
final SecurityMetadataPlan plan =
SecurityMetadataPlan.createRevokeNamespacePrivsPlan(planName, this,
roleName, namespace, privs);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan that verifies and repairs the store topology.
*/
public synchronized int createRepairPlan(String planName) {
final RepairPlan plan = new RepairPlan(planName, this);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan that performs network restore from source node to target
* node.
*
* @param planName plan name
* @param sourceNode restore source node id
* @param targetNode restore target node id
* @param retainOrigLog if retain original log file
* @return planId
*/
public synchronized int createNetworkRestorePlan(String planName,
ResourceId sourceNode,
ResourceId targetNode,
boolean retainOrigLog) {
final NetworkRestorePlan plan = new NetworkRestorePlan(planName, this,
sourceNode,
targetNode,
retainOrigLog);
register(plan);
return admin.saveCreatePlan(plan);
}
public Integer createSNConsistencyPlan(String planName,
StorageNodeId snId,
ParamCheckResults pcr) {
SNParameterConsistencyPlan plan =
new SNParameterConsistencyPlan(planName,
this, snId, pcr);
register(plan);
return admin.saveCreatePlan(plan);
}
public Integer
createUpdateSoftwareVersionPlan(String planName,
HashMap update) {
final Plan plan =
new UpdateSoftwareVersionPlan(planName, this, update);
register(plan);
logger.info("Saving create update software version plan");
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan that enables specified request type on given shards or
* the entire store.
*
* @param planName plan name
* @param requestType type of request is being enabled
* @param resourceIds resource IDs will be enabled specified request type
* @param entireStore if the entire store will be enabled given request type
* @return planId
*/
public synchronized int
createEnableRequestsPlan(final String planName,
final String requestType,
final Set extends ResourceId> resourceIds,
final boolean entireStore) {
final EnableRequestsTypePlan plan =
new EnableRequestsTypePlan(planName, this, requestType,
resourceIds, entireStore);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Submits a plan for asynchronous execution. If a previous plan is still
* executing, we will currently throw an exception. In the future, plans
* may be queued, but queuing would require policies and mechanism to
* determine what should happen to the rest of the queue if a plan fails.
* For example, should we "run the next plan, but only if the current
* succeeds" or ".. regardless of if the current succeeds", etc.
*
* Plan execution can be repeated, in order to retry a plan.
* @throws PlanLocksHeldException
* @throws IllegalCommandException if there is a problem with executing the
* plan.
*/
public PlanRun executePlan(Plan plan, boolean force)
throws PlanLocksHeldException {
/* For now, a Planner will only execute an AbstractPlan. */
final AbstractPlan targetPlan;
if (plan instanceof AbstractPlan) {
targetPlan = (AbstractPlan) plan;
} else {
throw new NonfatalAssertionException
("Unknown Plan type: " + plan.getClass() +
" cannot be executed");
}
/* Check any preconditions for running the plan */
targetPlan.validateStartOfRun();
/* Check that the catalog's rules for running this plan are ok */
catalog.validateStart(plan);
PlanRun planRun = null;
try {
/**
* Make sure we can get any plan-exclusion locks we need. Lock
* before doing checks, to make sure that the topology does not
* change.
*
* Synchronize the catalog to avoid deadlocks due to plans
* attempting to lock the same locks in different order.
*/
synchronized (catalog) {
plan.getCatalogLocks();
}
/* Validate that this plan can run */
plan.preExecuteCheck(force, logger);
/*
* Executing a plan equates to executing each of its tasks and
* monitoring their state. We'll kick off this process by running a
* PlanExecutor in another thread.
*/
planRun = targetPlan.startNewRun();
final PlanExecutor planExec = new PlanExecutor(admin, this,
targetPlan,
planRun, logger);
final Future future = executor.submit(planExec);
/*
* Note that Catalog.addPlanFuture guards against the possibility
* that the execute thread has finished before the future is added
* to the catalog.
*/
catalog.addPlanFuture(targetPlan, future);
} catch (RejectedExecutionException e) {
final String problem =
"Plan did not start, insufficient resources for " +
"executing a plan";
if (planRun != null) {
plan.saveFailure(planRun, e, problem, ErrorMessage.NOSQL_5400,
CommandResult.PLAN_CANCEL, logger);
}
planFinished(targetPlan);
throw new CommandFaultException(
problem, new OperationFaultException(problem, e),
ErrorMessage.NOSQL_5400, CommandResult.PLAN_CANCEL);
}
return planRun;
}
/**
* Used by the PlanExecutor to indicate that it's finished execution.
*/
void planFinished(Plan plan) {
catalog.clearLocks(plan.getId());
catalog.clearPlan(plan);
}
public Admin getAdmin() {
return admin;
}
public synchronized int createAddNamespacePlan(String planName,
String namespace) {
final Plan plan = TablePlanGenerator.
createAddNamespacePlan(planName, this, namespace);
register(plan);
return admin.saveCreatePlan(plan);
}
public synchronized int createRemoveNamespacePlan(String planName,
String namespace, boolean cascade) {
final Plan plan = TablePlanGenerator.
createRemoveNamespacePlan(planName, this, namespace, cascade);
register(plan);
return admin.saveCreatePlan(plan);
}
/* -- plan locking -- */
/**
* Lock categories. These are provided to avoid name conflicts between
* components. They have no other locking semantics. Feel free to add as
* needed.
*/
public enum LockCategory {
TABLE,
INDEX,
NAMESPACE
}
/**
* Locks the specified name within the specified category. Throws
* PlanLocksHeldException if the name is already locked.
*/
public void lock(int planId, String planName,
LockCategory category, String... name)
throws PlanLocksHeldException {
catalog.lock(planId, planName, category, name);
}
/**
* Locks the elasticity lock. Throws PlanLocksHeldException if already
* locked.
*/
public void lockElasticity(int planId, String planName)
throws PlanLocksHeldException {
catalog.lockElasticityChange(planId, planName);
}
/**
* Locks the elasticity lock for the specified command. Throws
* PlanLocksHeldException if already locked.
*/
public void lockElasticityForCommand(String commandName)
throws PlanLocksHeldException {
catalog.lockElasticityChange(COMMAND_LOCK_PLAN_ID, commandName);
}
/**
* Locks the specified resource. Throws PlanLocksHeldException if the
* resource is already locked.
*/
public void lock(int planId, String planName, ResourceId rnId)
throws PlanLocksHeldException {
catalog.lock(planId, planName, rnId);
}
/**
* Locks the specified shard. Throws PlanLocksHeldException if the shard is
* already locked.
*/
public void lockShard(int planId, String planName, RepGroupId rgId)
throws PlanLocksHeldException {
catalog.lockShard(planId, planName, rgId);
}
/**
* A collection of non-finished plans. It is used to enforce runtime
* constraints such as:
* - only one exclusive plan can run at a time
* - rep nodes can't be targeted by more than one plan at a time.
* - execution time locks taken. Locks must be acquire for each execution,
* because the locks are transient and only last of the life of the
* Planner instance.
*
* The catalog lets the Admin query plan status, and interrupt running
* plans.
*
* The locking methods are synchronized, however is multiple locks are
* being taken the caller should first synchronize on the catalog instance.
* For example, locks are taken out at the beginning of plan execution
* from a call to plan.getCategoryLocks(). The monitor on the catalog
* should be held during that call to avoid deadlocks.
*/
private class Catalog {
private Plan currentExclusivePlan;
private Plan currentExecutingPlan;
private final Map> futures = new HashMap<>();
private final Map planMap = new HashMap<>();
/*
* Logical locks are used to govern which plans can run concurrently. A
* single high level elasticity lock is used to ensure that only a
* single elasticity plan can run at a time. Shard and RN locks
* coordinate between concurrent elasticity and repair plans. Repair
* plans are those that might move a single RN or migrate all the
* components on a single SN.
*
* Locking a shard requires first checking for locks against any RNs or
* ANs in the shard. The same applies in reverse; locking a RN/AN is
* only possible if there is no shard lock.
*/
private final Lock elasticityLock = new Lock();
private final Map rnAnLocks = new HashMap<>();
private final Map rgLocks = new HashMap<>();
private final Map generalLocks = new HashMap<>();
synchronized void lockElasticityChange(int planId, String planName)
throws PlanLocksHeldException {
if (!elasticityLock.get(planId, planName)) {
throw cantLock(planId, planName, elasticityLock);
}
}
/**
* Check the shard locks before locking the RN.
* @throws PlanLocksHeldException
*/
synchronized void lock(int planId, String planName, ResourceId resId)
throws PlanLocksHeldException {
final Lock rgl = rgLocks.get(Utils.getRepGroupId(resId));
if (rgl != null) {
if (rgl.lockingPlanId != planId) {
throw cantLock(planId, planName, rgl);
}
}
Lock rnl = rnAnLocks.get(resId);
if (rnl == null) {
rnl = new Lock();
rnAnLocks.put(resId, rnl);
}
if (!rnl.get(planId, planName)) {
throw cantLock(planId, planName, rnl);
}
}
private PlanLocksHeldException cantLock(int planId,
String planName,
Lock lock) {
String current = (planId != COMMAND_LOCK_PLAN_ID) ?
planId + "/" + planName :
planName + " command";
String running = (lock.lockingPlanId != COMMAND_LOCK_PLAN_ID) ?
lock.lockingPlanId + "/" + lock.lockingPlanName :
lock.lockingPlanName + " command";
return new PlanLocksHeldException
("Couldn't execute " + current + " because " +
running + " is running. Wait until that plan(command) " +
"is finished or interrupted", lock.lockingPlanId);
}
/**
* Check the RN locks as well as the RN
* @throws PlanLocksHeldException
*/
synchronized void lockShard(int planId,
String planName,
RepGroupId rgId)
throws PlanLocksHeldException {
Lock rgl = rgLocks.get(rgId);
if (rgl != null && rgl.locked) {
if (rgl.lockingPlanId == planId) {
return;
}
throw cantLock(planId, planName, rgl);
}
/* check RNs/ANs first */
for (Map.Entry entry : rnAnLocks.entrySet()) {
if (rgId.equals(Utils.getRepGroupId(entry.getKey()))) {
final Lock l = entry.getValue();
if ((l.lockingPlanId != planId) && l.locked) {
throw cantLock(planId, planName, l);
}
}
}
if (rgl == null) {
rgl = new Lock();
rgLocks.put(rgId, rgl);
}
rgl.get(planId, planName);
}
/**
* Locks the specified name within the specified category. Throws
* PlanLocksHeldException if the name is already locked.
*/
synchronized void lock(int planId, String planName,
LockCategory category, String... name)
throws PlanLocksHeldException {
assert name.length > 0;
/**
* The lock name is category.name1.name2. ... nameN
*/
final StringBuilder sb = new StringBuilder(category.toString());
for (String c : name) {
if (c != null) {
sb.append(".").append(c);
}
}
final String lockName = sb.toString();
logger.log(Level.FINE, "Plan {0} [{1}] locking {2}",
new Object[]{planId, planName, lockName});
/*
* General locks are determined by their presence or absence in the
* map. The Lock.locked flag is not used.
*/
final Lock lk = generalLocks.get(lockName);
if ((lk != null) && (lk.lockingPlanId != planId)) {
logger.log(Level.FINE, "Plan {0} [{1}] failed to lock {2}",
new Object[]{planId, planName, lockName});
throw cantLock(planId, planName, lk);
}
generalLocks.put(lockName, new Lock(planId, planName));
}
/**
* Removes all locks that pertain to this plan
*/
synchronized void clearLocks(int planId) {
Iterator iter = generalLocks.values().iterator();
while (iter.hasNext()) {
if (iter.next().lockingPlanId == planId) {
iter.remove();
}
}
iter = rnAnLocks.values().iterator();
while (iter.hasNext()) {
final Lock tl = iter.next();
if (tl.lockingPlanId == planId) {
iter.remove();
}
}
iter = rgLocks.values().iterator();
while (iter.hasNext()) {
final Lock tl = iter.next();
if (tl.lockingPlanId == planId) {
iter.remove();
}
}
elasticityLock.releaseForPlanId(planId);
}
/**
* A lock to coordinate operations.
*/
private class Lock {
boolean locked;
int lockingPlanId;
String lockingPlanName;
/**
* Creates an unlocked lock.
*/
Lock() {}
/**
* Creates a lock owned by the specified plan.
*/
Lock(int planId, String planName) {
locked = true;
lockingPlanId = planId;
lockingPlanName = planName;
}
/**
* Gets the lock if unlocked. Returns true if successful or the
* plan already owns the lock.
*/
synchronized boolean get(int planId, String planName) {
if (locked && (lockingPlanId != planId)) {
return false;
}
locked = true;
lockingPlanId = planId;
lockingPlanName = planName;
return true;
}
/**
* Release the component if this plan owns it.
*/
synchronized void releaseForPlanId(int planId) {
if (!locked) {
return;
}
if (lockingPlanId == planId) {
locked = false;
lockingPlanId = 0;
lockingPlanName = null;
}
}
}
/**
* Enforce exclusivity at plan creation time.
*
* no pending or 1 or more pending 1 pending/approved
* approved or approved non-ex exclusive plan
* plans plans
*
* New plan is ok ok throw exception
* exclusive (unless recovering)
*
* New plan is ok ok ok
* not
* exclusive
*/
synchronized void addNewPlan(Plan plan, boolean recovering) {
/* No need to enforce exclusivity. */
if (!plan.isExclusive()) {
planMap.put(plan.getId(), plan);
return;
}
if (currentExclusivePlan == null) {
currentExclusivePlan = plan;
planMap.put(plan.getId(), plan);
return;
}
/*
* During recovery, if multiple exclusive active plans are found,
* allow the latest-created such plan to prevail as the
* currentExclusivePlan. In any case, do not fail to register
* a plan during recovery. [#26303]
*/
if (recovering) {
planMap.put(plan.getId(), plan);
logger.info
("Multiple exclusive plans found during recovery. " +
"Consider canceling plan " + plan);
if (currentExclusivePlan.getCreateTime().
compareTo(plan.getCreateTime()) < 0){
currentExclusivePlan = plan;
}
return;
}
throw new IllegalCommandException
(plan + " is an exclusive type plan, and cannot be created " +
" because " + currentExclusivePlan +
" is active. Consider canceling " +
currentExclusivePlan + ".",
ErrorMessage.NOSQL_5300, CommandResult.NO_CLEANUP_JOBS);
}
synchronized void addPlanFuture(Plan plan, Future future) {
/*
* There is the small possibility that the plan execution thread
* will have executed and finished the plan before we save its
* future. Check so that we don't needlessly add it.
*/
if (!plan.getState().isTerminal()) {
futures.put(plan.getId(), future);
}
}
synchronized void validateStart(Plan plan) {
/*
* Plans that were created through Planner should be
* registered. This is really an assertion check for internal
* testing plans.
*/
if (getPlan(plan.getId()) == null) {
throw new NonfatalAssertionException
(plan + " must be registered.");
}
/* A non-exclusive plan has no restrictions on when it can run.*/
if (!plan.isExclusive()) {
return;
}
if (currentExecutingPlan != null) {
if (currentExecutingPlan.equals(plan)) {
throw new IllegalCommandException
(plan + " is already running", ErrorMessage.NOSQL_5300,
CommandResult.NO_CLEANUP_JOBS);
}
throw new IllegalCommandException
(currentExecutingPlan + " is running, can't start " + plan,
ErrorMessage.NOSQL_5300, CommandResult.NO_CLEANUP_JOBS);
}
currentExecutingPlan = plan;
}
synchronized void clearPlan(Plan plan) {
futures.remove(plan.getId());
if (currentExecutingPlan == plan) {
currentExecutingPlan = null;
}
if (!plan.getState().isTerminal()) {
return;
}
planMap.remove(plan.getId());
if (currentExclusivePlan == plan) {
currentExclusivePlan = null;
}
}
Plan getPlan(int planId) {
return planMap.get(planId);
}
}
/**
* Returns the specified plan from the cache of active Plans.
*/
public Plan getCachedPlan(int planId) {
return catalog.getPlan(planId);
}
private Plan getFromCatalog(int planId) {
final Plan plan = getCachedPlan(planId);
if (plan == null) {
/*
* Plan ids may be specified via the CLI, so a user specified
* invalid id may result in this problem, and this should be an
* IllegalCommandException.
*/
throw new IllegalCommandException("Plan " + planId +
" is not an active plan");
}
return plan;
}
/**
*/
public void approvePlan(int planId) {
final Plan plan = getFromCatalog(planId);
try {
((AbstractPlan) plan).requestApproval();
} catch (IllegalStateException e) {
/*
* convert this to IllegalCommandException, since this is a
* user initiated action.
*/
throw new IllegalCommandException(e.getMessage());
}
}
/**
* Cancels a PENDING or APPROVED plan. Returns the canceled plan.
*/
public Plan cancelPlan(int planId) {
final AbstractPlan plan = (AbstractPlan) getFromCatalog(planId);
try {
plan.requestCancellation();
planFinished(plan);
return plan;
} catch (IllegalStateException e) {
/*
* convert this to IllegalCommandException, since this is a
* user initiated action.
*/
throw new IllegalCommandException(e.getMessage(),
ErrorMessage.NOSQL_5200,
CommandResult.NO_CLEANUP_JOBS);
}
}
/**
* Interrupt a RUNNING plan. Users must retry or rollback interrupted
* plans.
*/
public void interruptPlan(int planId) {
final Plan plan = getFromCatalog(planId);
final AbstractPlan aplan = (AbstractPlan) plan;
if (aplan.cancelIfNotStarted()) {
/*
* If the plan isn't even running, change state to CANCEL,
* and clean up the related plan lock. No need to do any interrupt
* processing.
*/
planFinished(aplan);
return;
}
if (!(plan.getState().checkTransition(State.INTERRUPT_REQUESTED))) {
throw new IllegalCommandException
("Can't interrupt plan " + plan + " in state " +
plan.getState());
}
logger.info("User requesting interrupt of " + plan);
aplan.requestInterrupt();
}
/**
* Returns the logger for this planner.
*
* @return the logger
*/
Logger getLogger() {
return logger;
}
/* For unit test support */
public void setExecutor(ExecutorService executor) {
this.executor = executor;
}
/**
* Registers an externally managed Elasticsearch cluster and updates
* SNA Parameters to reflect it.
*/
public Integer createRegisterESClusterPlan(String planName,
String clusterName,
String transportHp,
boolean secure,
boolean forceClear) {
final Plan plan =
new RegisterESPlan(planName, this,
clusterName, transportHp, secure,
forceClear);
register(plan);
return admin.saveCreatePlan(plan);
}
public Integer createDeregisterESClusterPlan(String planName) {
final Plan plan = new DeregisterESPlan(planName, this);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Create a plan to verify data on a service node.
*/
public synchronized int createVerifyServicePlan(String planName,
ResourceId rid,
boolean verifyBtree,
boolean verifyLog,
boolean verifyIndex,
boolean verifyRecord,
long btreeDelay,
long logDelay) {
Plan plan = null;
if (rid instanceof RepNodeId) {
Set allRns = new HashSet<>();
allRns.add((RepNodeId) rid);
Map> rnsList =
new HashMap>();
rnsList.put(((RepNodeId) rid).getGroupId(), allRns);
plan = new VerifyDataPlan(planName, this, null, rnsList,
verifyBtree, verifyLog, verifyIndex,
verifyRecord, btreeDelay, logDelay);
} else if (rid instanceof AdminId) {
Set allAdmins = new HashSet<>();
allAdmins.add((AdminId) rid);
plan = new VerifyDataPlan(planName, this, allAdmins, null,
verifyBtree, verifyLog, verifyIndex,
verifyRecord, btreeDelay, logDelay);
} else {
throw new IllegalCommandException(rid + " is not a valid id" +
" to be verified");
}
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Create a plan to verify data on all admins that are deployed to the
* specified zone or all zones.
*/
public synchronized int createVerifyAllAdminsPlan(String planName,
DatacenterId dcid,
boolean verifyBtree,
boolean verifyLog,
boolean verifyIndex,
boolean verifyRecord,
long btreeDelay,
long logDelay) {
/* get all admins */
Set allId = getAdmin().getCurrentParameters().
getAdminIds(dcid, admin.getCurrentTopology());
Plan plan = new VerifyDataPlan(planName, this, allId, null,
verifyBtree, verifyLog, verifyIndex,
verifyRecord, btreeDelay, logDelay);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to verify data on all rns that are deployed to the
* specified zone or all zones.
*/
public synchronized int createVerifyAllRepNodesPlan(String planName,
DatacenterId dcid,
boolean verifyBtree,
boolean verifyLog,
boolean verifyIndex,
boolean verifyRecord,
long btreeDelay,
long logDelay) {
Set allId = admin.getCurrentTopology().getRepNodeIds(dcid);
Map> idsPerShard =
new HashMap>();
for (RepNodeId id : allId) {
int shardNum = id.getGroupId();
if (idsPerShard.get(shardNum) == null) {
idsPerShard.put(shardNum, new HashSet());
}
idsPerShard.get(shardNum).add(id);
}
Plan plan = new VerifyDataPlan(planName, this, null, idsPerShard,
verifyBtree, verifyLog, verifyIndex,
verifyRecord, btreeDelay, logDelay);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to verify data on all rns and admins that are deployed to
* the specified zone or all zones.
*/
public synchronized int createVerifyAllServicesPlan(String planName,
DatacenterId dcid,
boolean verifyBtree,
boolean verifyLog,
boolean verifyIndex,
boolean verifyRecord,
long btreeDelay,
long logDelay) {
Set allAdminId = getAdmin().getCurrentParameters().
getAdminIds(dcid, admin.getCurrentTopology());
Set allRnId = admin.getCurrentTopology().getRepNodeIds(dcid);
Map> rnIdsPerShard =
new HashMap>();
for (RepNodeId id : allRnId) {
int shardNum = id.getGroupId();
if (rnIdsPerShard.get(shardNum) == null) {
rnIdsPerShard.put(shardNum, new HashSet());
}
rnIdsPerShard.get(shardNum).add(id);
}
Plan plan = new VerifyDataPlan(planName, this, allAdminId,
rnIdsPerShard, verifyBtree, verifyLog,
verifyIndex, verifyRecord, btreeDelay,
logDelay);
register(plan);
return admin.saveCreatePlan(plan);
}
/**
* Creates a plan to set limits on a table.
*/
public Integer createTableLimitPlan(String planName,
String namespace, String tableName,
TableLimits newLimits) {
final Plan plan = TablePlanGenerator.
createSetTableLimitPlan(planName, this,
namespace, tableName, newLimits);
register(plan);
return admin.saveCreatePlan(plan);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy