
oracle.kv.impl.admin.plan.FailoverPlan 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.
The newest version!
/*-
* 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.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;
import oracle.kv.impl.admin.Admin;
import oracle.kv.impl.admin.IllegalCommandException;
import oracle.kv.impl.admin.param.Parameters;
import oracle.kv.impl.admin.plan.task.DeleteTopo;
import oracle.kv.impl.admin.plan.task.ParallelBundle;
import oracle.kv.impl.admin.plan.task.RepairShardQuorum;
import oracle.kv.impl.admin.topo.TopologyCandidate;
import oracle.kv.impl.topo.Datacenter;
import oracle.kv.impl.topo.DatacenterId;
import oracle.kv.impl.topo.RepGroupId;
import oracle.kv.impl.topo.Topology;
/**
* Performs a failover by repairing shard quorum and deploying the specified
* topology.
*/
public class FailoverPlan extends DeployTopoPlan {
private static final long serialVersionUID = 1L;
private static final String TOPO_CANDIDATE_NAME_PREFIX =
TopologyCandidate.INTERNAL_NAME_PREFIX + "failover-plan-";
private final Set allPrimaryZones;
private final Set offlineZones;
private volatile boolean isForce;
private FailoverPlan(String planName,
Planner planner,
Topology current,
TopologyCandidate candidate,
Set allPrimaryZones,
Set offlineZones) {
super(planName, planner, current, candidate);
this.allPrimaryZones = allPrimaryZones;
this.offlineZones = offlineZones;
this.isForce = false;
}
/**
* Creates a plan that will perform a failover, converting the specified
* offline zones to secondary zones, and optionally converting secondary
* zones to primary zones.
*
* @param planName a custom name for the plan, or null for the default
* @param planner the planner to use to manage plans
* @param current the current topology
* @param newPrimaryZones IDs of any new primary zones
* @param offlineZones IDs of offline zones
* @return the created plan
* @throws IllegalCommandException if any zone IDs are not found, if the
* new primary zones and offline zones overlap, if the offline zones set is
* empty, or if the specified zones and topology do not result in any
* online primary zones
*/
public static FailoverPlan create(String planName,
Planner planner,
Topology current,
Set newPrimaryZones,
Set offlineZones) {
final Set allPrimaryZones =
getAllPrimaryZones(current, newPrimaryZones, offlineZones);
/*
* There is a window where two failover plan names could end up with the
* same postfix ID. There is also a possibility the the postfix could
* be different than the plan ID. However this is highly unlikely in
* practice and does not seem worth fixing.
*/
final int canId = planner.getNextPlanId();
final String candidateName = TOPO_CANDIDATE_NAME_PREFIX + canId;
Admin admin = planner.getAdmin();
admin.createFailoverTopology(candidateName,
Parameters.DEFAULT_POOL_NAME,
newPrimaryZones,
offlineZones);
final TopologyCandidate candidate = admin.getCandidate(candidateName);
final FailoverPlan plan =
new FailoverPlan(planName, planner, current, candidate,
allPrimaryZones, offlineZones);
plan.generateTasks(current, candidate, null);
return plan;
}
/* Return if this plan is executed with force flag */
public boolean isForce() {
return isForce;
}
/**
* Returns a set of the IDs of the zones that should be primary zones after
* performing the failover, including all current zones not included in the
* offline zones, plus any secondary zones in newPrimaryZones. Also
* perform all checks on newPrimaryZones and offlineZones parameters.
*/
private static Set getAllPrimaryZones(
Topology current,
Set newPrimaryZones,
Set offlineZones)
throws IllegalCommandException {
final Set zonesNotFound = new HashSet<>();
for (final DatacenterId dcId : newPrimaryZones) {
if (current.get(dcId) == null) {
zonesNotFound.add(dcId);
}
}
for (final DatacenterId dcId : offlineZones) {
if (current.get(dcId) == null) {
zonesNotFound.add(dcId);
}
}
if (!zonesNotFound.isEmpty()) {
throw new IllegalCommandException(
"Zones were not found: " + zonesNotFound);
}
if (!Collections.disjoint(newPrimaryZones, offlineZones)) {
throw new IllegalCommandException(
"The primary zones and offline zones must not overlap");
}
if (offlineZones.isEmpty()) {
throw new IllegalCommandException(
"The offline zones must not be empty");
}
final Set allPrimaryZones =
new HashSet<>(newPrimaryZones);
for (final Datacenter zone : current.getDatacenterMap().getAll()) {
if (zone.getDatacenterType().isPrimary() &&
!offlineZones.contains(zone.getResourceId())) {
allPrimaryZones.add(zone.getResourceId());
}
}
if (allPrimaryZones.isEmpty()) {
throw new IllegalCommandException(
"The options to the failover command did not result in any" +
" online primary zones, but at least one online primary" +
" zone is required");
}
return allPrimaryZones;
}
@Override
protected void generateTasks(Topology current,
TopologyCandidate candidate,
RepGroupId failedShard) {
/* failedShard is always null */
assert failedShard == null;
/* Add tasks first to repair quorum in all shards in parallel */
final ParallelBundle tasks = new ParallelBundle();
for (final RepGroupId rgId : current.getRepGroupMap().getAllIds()) {
tasks.addTask(new RepairShardQuorum(this, rgId, allPrimaryZones,
offlineZones));
}
addTask(tasks);
super.generateTasks(current, candidate, failedShard);
/* Remove the generated topology candidate */
addTask(new DeleteTopo(this, candidateName));
}
@Override
public String getDefaultName() {
return "Failover";
}
@Override
public void preExecuteCheck(boolean force, Logger executeLogger) {
super.preExecuteCheck(force, executeLogger);
/* Verify that all shards meet the initial requirements */
final Admin admin = getAdmin();
RepairShardQuorum.verify(this, allPrimaryZones, offlineZones,
admin.getCurrentTopology(),
admin.getCurrentParameters(),
admin.getLoginManager(),
executeLogger,
force);
isForce = force;
}
/** First remove the generated topology candidate. */
@Override
synchronized void requestCancellation() {
try {
getAdmin().deleteTopoCandidate(candidateName);
} catch (IllegalCommandException e) {
/* The candidate was not found -- OK */
}
super.requestCancellation();
}
@Override
public Set getOfflineZones() {
return offlineZones;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy