![JAR search and dependency download from the Maven repository](/logo.png)
oracle.kv.impl.api.rgstate.RepGroupStateTable Maven / Gradle / Ivy
/*-
* 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.api.rgstate;
import static oracle.kv.impl.util.ObjectUtil.checkNull;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import oracle.kv.impl.api.Request;
import oracle.kv.impl.api.Response;
import oracle.kv.impl.api.StatusChanges;
import oracle.kv.impl.api.TopologyInfo;
import oracle.kv.impl.api.TopologyManager;
import oracle.kv.impl.topo.RepGroup;
import oracle.kv.impl.topo.RepGroupId;
import oracle.kv.impl.topo.RepNodeId;
import oracle.kv.impl.topo.ResourceId;
import oracle.kv.impl.topo.Topology;
import com.sleepycat.je.rep.ReplicatedEnvironment.State;
import com.sleepycat.je.rep.StateChangeEvent;
/**
* The RepGroupStateTable tracks the dynamic (non-structural) state associated
* with the replication groups and the replication nodes underlying the KV
* Store. It can be indexed just like the RepGroupMap via the group id and the
* node number. This state information serves as the basis for request
* dispatching.
*
* The state information, due to its dynamic nature, is not stored
* persistently. [RNs could potentially benefit, from having it stored
* persistently, across quick restarts.]
*
* The HA state maintained in the table is maintained in one of two ways:
*
* - Via the HA listener for state that is local to the rep group associated
* with this RN, if the state table is associated with a RN and not a KV
* client.
* -
* From HA status returned in a
Response
. This update method
* applies to both RNs and KV clients.
*
*
* The state table is loosely coupled with the Topology. It's possible that one
* or the other tables may be temporarily inconsistent with each other.
*
* Associated with the RepGroupStateTable is an update thread that uses
* internal ping requests attempts to keep the state associated with each RN
* and RG as current as possible.
*/
public class RepGroupStateTable implements TopologyManager.PostUpdateListener{
/**
* Identifies the component (RN or KV Client) that's tracking the
* state of the nodes.
*/
private final ResourceId trackerId;
private final boolean async;
private final Logger logger;
/**
* A lazily populated map from rep group to the state associated with the
* RepGroup. All access to groupMap is done exclusively via the
* synchronized method getGroupState.
*/
private final Map groupMap;
public RepGroupStateTable(ResourceId trackerId,
boolean async,
Logger logger) {
this.trackerId = trackerId;
this.async = async;
this.logger = checkNull("logger", logger);
groupMap = new ConcurrentHashMap();
}
/**
* Returns the RepNodeState associated with every RN in the state table.
*/
public synchronized Collection getRepNodeStates() {
final Collection rns = new HashSet();
for (RepGroupState rgs : groupMap.values()) {
rns.addAll(rgs.getRepNodeStates());
}
return rns;
}
/**
* Returns the RepNodeStates whose requestHandler need repair.
*/
synchronized Collection getRNStatesNeedingRepair() {
final Collection rns = new HashSet();
for (RepGroupState rgs : groupMap.values()) {
for (RepNodeState state : rgs.getRepNodeStates()) {
if (state.reqHandlerNeedsRepair()) {
rns.add(state);
}
}
}
return rns;
}
/**
* Returns the group state associated with the groupId. If an entry does
* not exist, an empty entry is created for it.
*
* @param rgId identifies the RepGroup
*
* @return the GroupEntry identified by the repGroupId
*/
public synchronized RepGroupState getGroupState(RepGroupId rgId) {
RepGroupState rgs = groupMap.get(rgId);
if (rgs != null) {
return rgs;
}
rgs = new RepGroupState(rgId, trackerId, async, logger);
groupMap.put(rgId, rgs);
return rgs;
}
public RepNodeState getNodeState(RepNodeId rnId) {
RepGroupState rg = getGroupState(new RepGroupId(rnId.getGroupId()));
return rg.get(rnId);
}
public State getRepState(RepNodeId rnId) {
RepGroupState rgs = getGroupState(new RepGroupId(rnId.getGroupId()));
return rgs.get(rnId).getRepState();
}
/**
* Updates the state table in response to a Listener state change event.
*
*
* @param event the change event
*/
public void update(StateChangeEvent event) {
/* Only RNs get state change events, KV clients do not. */
final RepNodeId rnId = (RepNodeId) trackerId;
RepGroupState rgs = getGroupState(new RepGroupId(rnId.getGroupId()));
RepNodeId masterId = null;
if (event.getState().isReplica() || event.getState().isMaster()) {
String masterName = event.getMasterNodeName();
masterId = RepNodeId.parse(masterName);
}
rgs.update(rnId,
masterId,
event.getState(),
event.getEventTime());
}
/**
* Updates the table with status changes from a response.
*
* @param request part of request/response pair
* @param response part of the request/response pair
* @param respMs the elapsed time associated with the response
*/
public void update(Request request,
Response response,
int respMs) {
RepNodeId rnId = response.getRespondingRN();
RepGroupState rgs = getGroupState(new RepGroupId(rnId.getGroupId()));
RepNodeState rnState = getNodeState(rnId);
rnState.updateVLSN(response.getVLSN());
rnState.accumRespTime(request.isWrite(), respMs);
final TopologyInfo topoInfo = response.getTopoInfo();
if ((topoInfo != null) && (topoInfo.getChanges() == null)) {
/* Responder has obsolete topology */
rnState.updateTopoSeqNum(topoInfo.getSourceSeqNum());
}
final StatusChanges changes = response.getStatusChanges();
if (changes == null) {
return;
}
final RepNodeId masterId = changes.getCurrentMaster();
rgs.update(rnId, masterId, changes.getState(),
changes.getStatusTime());
}
/**
* Merge any topology related changes into the state table
*/
@Override
public boolean postUpdate(Topology topology) {
for (RepGroup rg : topology.getRepGroupMap().getAll()) {
getGroupState(rg.getResourceId()).update(rg, topology);
}
return false;
}
}