
oracle.kv.impl.admin.SoftwareVersionUpdater 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;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import oracle.kv.KVVersion;
import oracle.kv.impl.admin.param.Parameters;
import oracle.kv.impl.admin.param.StorageNodeParams;
import oracle.kv.impl.param.DurationParameter;
import oracle.kv.impl.param.ParameterListener;
import oracle.kv.impl.param.ParameterMap;
import oracle.kv.impl.param.ParameterState;
import oracle.kv.impl.security.login.LoginManager;
import oracle.kv.impl.sna.StorageNodeAgentAPI;
import oracle.kv.impl.sna.StorageNodeStatus;
import oracle.kv.impl.topo.StorageNodeId;
import oracle.kv.impl.topo.Topology;
import oracle.kv.impl.util.KVThreadFactory;
import oracle.kv.impl.util.registry.RegistryUtils;
import oracle.kv.impl.util.server.LoggerUtils;
class SoftwareVersionUpdater implements ParameterListener {
private static final int MAX_PLAN_WAIT_MS = 5 * 60 * 1000;
private static final int MIN_THREADS = 1;
private static final String THREAD_NAME = "SoftwareVersionUpdater";
private static final String UPDATE_VERSION_PLAN_NAME =
"UpdateVersionMetadata";
private static final String UPDATE_GLOBAL_VERSION_PLAN_NAME =
"UpdateGlobalVersionMetadata";
private final Admin admin;
private final Logger logger;
private final AtomicBoolean isShutdown;
private final ScheduledThreadPoolExecutor executors;
private final Map agents;
private long pollIntervalMS;
private long bootTime;
/* Set in findUpdates */
private KVVersion storeVersion = null;
final HashSet snVersions = new HashSet();
private static long SHORT_POLL_MS = 1000 * 60;
private static long SHORT_POLL_MAX_DUR = 1000 * 60 * 60;
private boolean useShortPoll = false;
/**
* A thread that periodically checks the SNs software version.
* If needed, the value is updated in the admin database as a
* parameter for the SN. May also update the store version which
* is a global parameter.
*/
SoftwareVersionUpdater(Admin admin,
long pollIntervalMS,
Logger logger) {
String threadName =
admin.getParams().getAdminParams().getAdminId() + "_" + THREAD_NAME;
this.admin = admin;
this.logger = logger;
this.pollIntervalMS = pollIntervalMS;
isShutdown = new AtomicBoolean(false);
bootTime = System.currentTimeMillis();
agents = new ConcurrentHashMap();
executors =
new ScheduledThreadPoolExecutor
(MIN_THREADS, new KVThreadFactory(threadName, logger));
/*
* Do initial check of SN to see if potential system is in
* the process of upgrade.
*/
findUpdates();
AgentInfo agentInfo = new AgentInfo(admin.toString());
if (snVersions.size() == 1) {
/*
* All SNs are at the same software version so
* just do the normal polling.
*/
setupFuture(agentInfo, pollIntervalMS);
} else {
/*
* Either we don't have the software version for all SNs, or
* there are SNs at different software versions. In this case
* set up a short poll time in case we are in the midst of an
* upgrade.
*/
setupFuture(agentInfo, SHORT_POLL_MS);
useShortPoll= true;
}
agents.put(admin.toString(), agentInfo);
}
void shutdown() {
logger.fine("Shutting down " + THREAD_NAME);
isShutdown.set(true);
unregisterAgent(admin.toString());
executors.shutdown();
/*
* Best effort to shutdown. If the await returns false, we proceed
* anyway.
*/
try {
executors.awaitTermination(1000,
TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
logger.info (THREAD_NAME + " interrupted during shutdown: " +
LoggerUtils.getStackTrace(e));
}
}
@Override
public void newParameters(ParameterMap oldMap, ParameterMap newMap) {
DurationParameter pi =
(DurationParameter)newMap.getOrDefault(
ParameterState.AP_VERSION_CHECK_INTERVAL);
if (pi.toMillis() != pollIntervalMS) {
pollIntervalMS = pi.toMillis() ;
resetAgents(pollIntervalMS);
}
}
private void process() {
processInternal();
if (useShortPoll) {
if (snVersions.size() == 1 ||
System.currentTimeMillis() > (bootTime + SHORT_POLL_MAX_DUR)) {
resetAgents(pollIntervalMS);
useShortPoll = false;
}
}
}
private void processInternal() {
Integer planId = null;
HashMap updates = findUpdates();
if (updates.isEmpty()) {
return;
}
if (!updates.isEmpty()) {
logger.fine(THREAD_NAME + "Updating software version.");
planId =
admin.getPlanner().createUpdateSoftwareVersionPlan(
UPDATE_VERSION_PLAN_NAME, updates);
try {
admin.approvePlan(planId);
admin.executePlan(planId, false);
admin.awaitPlan(planId,
MAX_PLAN_WAIT_MS, TimeUnit.MILLISECONDS);
} catch (Exception e) {
logger.log(Level.WARNING,
THREAD_NAME + "Encountered exception " +
"running update SN version plan.",
e);
admin.cancelPlan(planId);
throw e;
}
}
/*
* Check if we need to update the kvstore version.
*/
if (storeVersion == null) {
return;
}
final ParameterMap pm =
new ParameterMap(ParameterState.GLOBAL_TYPE,
ParameterState.GLOBAL_TYPE);
pm.setParameter(ParameterState.GP_STORE_VERSION,
storeVersion.getNumericVersionString());
planId =
admin.getPlanner().createChangeGlobalComponentsParamsPlan(
UPDATE_GLOBAL_VERSION_PLAN_NAME, pm, true);
try {
admin.approvePlan(planId);
admin.executePlan(planId, false);
admin.awaitPlan(planId,
MAX_PLAN_WAIT_MS, TimeUnit.MILLISECONDS);
} catch (Exception e) {
logger.log(Level.WARNING,
"THREAD_NAME " + "Encountered exception " +
"running update store version plan.",
e);
admin.cancelPlan(planId);
throw e;
}
}
/**
* Returns set of SN's and corresponding versions and may
* set the storeVersion member if the information is available, otherwise
* the storeVersion member is set to null. The storeVersion member variable
* is set if a new store version is determined.
*
* This method sets the value of the snVersions member variable.
* SnVersions is populated with the software versions of all
* SN's in the KVStore. It is cleared if the version
* of one or more SN's version cannot be determined
* from the admin metadata or directly from the SN.
*
* This method set the value of the storeVersion if all SNs versions
* can be determined from the Admin metadata or directly from the SNs,
* otherwise storeVersion is set to null.
*
* @returns a map of Storage Node identifier to the KVVersion that needs
* updating in the Admin metadata database.
*/
private HashMap findUpdates() {
final HashMap retVal =
new HashMap();
final Topology topo = admin.getCurrentTopology();
final Parameters params = admin.getCurrentParameters();
final LoginManager loginMgr = admin.getLoginManager();
final RegistryUtils regUtils =
new RegistryUtils(topo, loginMgr);
ParameterMap gp = params.getGlobalParams().getMap();
storeVersion = null;
KVVersion minVersion = null;
boolean gotAll = true;
snVersions.clear();
for (StorageNodeParams tSNp : params.getStorageNodeParams()) {
KVVersion snVersion = null;
StorageNodeId snId = tSNp.getStorageNodeId();
ParameterMap snParams = tSNp.getMap();
KVVersion dbVersion =
getVersion(
snParams.get(ParameterState.SN_SOFTWARE_VERSION).asString());
try {
StorageNodeAgentAPI sna = regUtils.getStorageNodeAgent(snId);
StorageNodeStatus sns = sna.ping();
snVersion = sns.getKVVersion();
if (!snVersion.equals(dbVersion)) {
retVal.put(snId, snVersion.getNumericVersionString());
}
} catch (NotBoundException | RemoteException e) {
}
if (snVersion == null && dbVersion == null) {
gotAll = false;
} else {
KVVersion tMin = getMin(snVersion, dbVersion);
if (minVersion == null) {
minVersion = tMin;
} else if (minVersion.compareTo(tMin) > 0) {
minVersion = tMin;
}
}
if (snVersion != null) {
snVersions.add(snVersion);
}
if (dbVersion != null) {
snVersions.add(dbVersion);
}
}
if (gotAll) {
KVVersion dbStoreVersion =
getVersion(gp.get(ParameterState.GP_STORE_VERSION).asString());
if (dbStoreVersion == null ||
dbStoreVersion.compareTo(minVersion) < 0) {
storeVersion = minVersion;
}
} else {
snVersions.clear();
}
return retVal;
}
private void setupFuture(AgentInfo info, long pollMillis) {
Runnable pollTask = new PollTask(info);
Future> future =
executors.scheduleAtFixedRate(pollTask,
pollMillis, // initial delay
pollMillis,
TimeUnit.MILLISECONDS);
info.setFuture(future);
}
private synchronized void unregisterAgent(String name) {
AgentInfo info = agents.remove(name);
if (info == null) {
/* Nothing to do. */
return;
}
if (info.future == null) {
return;
}
logger.fine("Removing " + name + " from executing");
info.future.cancel(false);
}
private synchronized void resetAgents(long pollMillis) {
logger.info
(THREAD_NAME + ": resetting interval to: " + pollMillis +
" milliseconds (" + agents.size() + " agents)");
for (final String key : new ArrayList<>(agents.keySet())) {
final AgentInfo info = agents.remove(key);
if (info.future != null) {
info.future.cancel(false);
}
setupFuture(info, pollMillis);
agents.put(key, info);
}
}
private KVVersion getVersion(String versionString) {
KVVersion retVal = null;
try {
retVal = KVVersion.parseVersion(versionString);
} catch (Exception e) {
}
return retVal;
}
private KVVersion getMin(KVVersion v1, KVVersion v2) {
if (v1 == null ) {
return v2;
}
if (v2 == null) {
return v1;
}
if (v1.compareTo(v2) < 0) {
return v1;
}
return v2;
}
private class PollTask implements Runnable {
private final AgentInfo agentInfo;
PollTask(AgentInfo agentInfo) {
this.agentInfo = agentInfo;
}
@Override
public void run() {
try {
if (isShutdown.get()) {
logger.fine("SoftwareVersionUpdater is shutdown");
return;
}
logger.fine(THREAD_NAME + " polling " + agentInfo);
process();
} catch (Exception e) {
}
}
}
private class AgentInfo {
private final String name;
private Future> future;
AgentInfo(String name) {
this.name = name;
}
void setFuture(Future> f) {
this.future = f;
}
@Override
public String toString() {
return name;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy