* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-
package org.opendaylight.controller.cluster.raft;
+import static java.util.Objects.requireNonNull;
+
import akka.actor.ActorContext;
import akka.actor.ActorRef;
import akka.actor.ActorSelection;
import akka.actor.Props;
import akka.cluster.Cluster;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import java.util.ArrayList;
+import com.google.common.collect.ImmutableList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import java.util.function.LongSupplier;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.controller.cluster.DataPersistenceProvider;
+import org.opendaylight.controller.cluster.io.FileBackedOutputStreamFactory;
+import org.opendaylight.controller.cluster.raft.base.messages.ApplyState;
import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior;
import org.opendaylight.controller.cluster.raft.persisted.ServerConfigurationPayload;
import org.opendaylight.controller.cluster.raft.persisted.ServerInfo;
private final ActorContext context;
+ private final @NonNull Executor executor;
+
private final String id;
private final ElectionTerm termInformation;
private Optional<Cluster> cluster;
- public RaftActorContextImpl(ActorRef actor, ActorContext context, String id,
- ElectionTerm termInformation, long commitIndex, long lastApplied, Map<String, String> peerAddresses,
- ConfigParams configParams, DataPersistenceProvider persistenceProvider, Logger logger) {
+ private final Consumer<ApplyState> applyStateConsumer;
+
+ private final FileBackedOutputStreamFactory fileBackedOutputStreamFactory;
+
+ private RaftActorLeadershipTransferCohort leadershipTransferCohort;
+
+ public RaftActorContextImpl(final ActorRef actor, final ActorContext context, final String id,
+ final @NonNull ElectionTerm termInformation, final long commitIndex, final long lastApplied,
+ final @NonNull Map<String, String> peerAddresses,
+ final @NonNull ConfigParams configParams, final @NonNull DataPersistenceProvider persistenceProvider,
+ final @NonNull Consumer<ApplyState> applyStateConsumer, final @NonNull Logger logger,
+ final @NonNull Executor executor) {
this.actor = actor;
this.context = context;
this.id = id;
- this.termInformation = termInformation;
+ this.termInformation = requireNonNull(termInformation);
+ this.executor = requireNonNull(executor);
this.commitIndex = commitIndex;
this.lastApplied = lastApplied;
- this.configParams = configParams;
- this.persistenceProvider = persistenceProvider;
- this.log = logger;
+ this.configParams = requireNonNull(configParams);
+ this.persistenceProvider = requireNonNull(persistenceProvider);
+ log = requireNonNull(logger);
+ this.applyStateConsumer = requireNonNull(applyStateConsumer);
+
+ fileBackedOutputStreamFactory = new FileBackedOutputStreamFactory(
+ configParams.getFileBackedStreamingThreshold(), configParams.getTempFileDirectory());
- for(Map.Entry<String, String> e: peerAddresses.entrySet()) {
+ for (Map.Entry<String, String> e : requireNonNull(peerAddresses).entrySet()) {
peerInfoMap.put(e.getKey(), new PeerInfo(e.getKey(), e.getValue(), VotingState.VOTING));
}
}
@VisibleForTesting
- public void setPayloadVersion(short payloadVersion) {
+ public void setPayloadVersion(final short payloadVersion) {
this.payloadVersion = payloadVersion;
}
return payloadVersion;
}
- public void setConfigParams(ConfigParams configParams) {
+ public void setConfigParams(final ConfigParams configParams) {
this.configParams = configParams;
}
@Override
- public ActorRef actorOf(Props props){
+ public ActorRef actorOf(final Props props) {
return context.actorOf(props);
}
@Override
- public ActorSelection actorSelection(String path){
+ public ActorSelection actorSelection(final String path) {
return context.actorSelection(path);
}
}
@Override
+ public final Executor getExecutor() {
+ return executor;
+ }
+
+ @Override
+ @SuppressWarnings("checkstyle:IllegalCatch")
public Optional<Cluster> getCluster() {
- if(cluster == null) {
+ if (cluster == null) {
try {
cluster = Optional.of(Cluster.get(getActorSystem()));
- } catch(Exception e) {
+ } catch (Exception e) {
// An exception means there's no cluster configured. This will only happen in unit tests.
- log.debug("{}: Could not obtain Cluster: {}", getId(), e);
+ log.debug("{}: Could not obtain Cluster", getId(), e);
cluster = Optional.empty();
}
}
return commitIndex;
}
- @Override public void setCommitIndex(long commitIndex) {
+ @Override public void setCommitIndex(final long commitIndex) {
this.commitIndex = commitIndex;
}
}
@Override
- public void setLastApplied(long lastApplied) {
+ public void setLastApplied(final long lastApplied) {
+ final Throwable stackTrace = log.isTraceEnabled() ? new Throwable() : null;
+ log.debug("{}: Moving last applied index from {} to {}", id, this.lastApplied, lastApplied, stackTrace);
this.lastApplied = lastApplied;
}
@Override
- public void setReplicatedLog(ReplicatedLog replicatedLog) {
+ public void setReplicatedLog(final ReplicatedLog replicatedLog) {
this.replicatedLog = replicatedLog;
}
return replicatedLog;
}
- @Override public ActorSystem getActorSystem() {
+ @Override
+ public ActorSystem getActorSystem() {
return context.system();
}
- @Override public Logger getLogger() {
- return this.log;
+ @Override
+ public Logger getLogger() {
+ return log;
}
@Override
}
@Override
- public PeerInfo getPeerInfo(String peerId) {
+ public PeerInfo getPeerInfo(final String peerId) {
return peerInfoMap.get(peerId);
}
@Override
- public String getPeerAddress(String peerId) {
+ public String getPeerAddress(final String peerId) {
String peerAddress;
PeerInfo peerInfo = peerInfoMap.get(peerId);
- if(peerInfo != null) {
+ if (peerInfo != null) {
peerAddress = peerInfo.getAddress();
- if(peerAddress == null) {
+ if (peerAddress == null) {
peerAddress = configParams.getPeerAddressResolver().resolve(peerId);
peerInfo.setAddress(peerAddress);
}
}
@Override
- public void updatePeerIds(ServerConfigurationPayload serverConfig){
- votingMember = true;
- boolean foundSelf = false;
- Set<String> currentPeers = new HashSet<>(this.getPeerIds());
- for(ServerInfo server: serverConfig.getServerConfig()) {
- if(getId().equals(server.getId())) {
- foundSelf = true;
- if(!server.isVoting()) {
- votingMember = false;
- }
+ public void updatePeerIds(final ServerConfigurationPayload serverConfig) {
+ boolean newVotingMember = false;
+ var currentPeers = new HashSet<>(getPeerIds());
+ for (var server : serverConfig.getServerConfig()) {
+ if (getId().equals(server.peerId())) {
+ newVotingMember = server.isVoting();
} else {
- VotingState votingState = server.isVoting() ? VotingState.VOTING: VotingState.NON_VOTING;
- if(!currentPeers.contains(server.getId())) {
- this.addToPeers(server.getId(), null, votingState);
+ final var votingState = server.isVoting() ? VotingState.VOTING : VotingState.NON_VOTING;
+ if (currentPeers.contains(server.peerId())) {
+ getPeerInfo(server.peerId()).setVotingState(votingState);
+ currentPeers.remove(server.peerId());
} else {
- this.getPeerInfo(server.getId()).setVotingState(votingState);
- currentPeers.remove(server.getId());
+ addToPeers(server.peerId(), null, votingState);
}
}
}
- for(String peerIdToRemove: currentPeers) {
- this.removePeer(peerIdToRemove);
- }
-
- if(!foundSelf) {
- votingMember = false;
+ for (String peerIdToRemove : currentPeers) {
+ removePeer(peerIdToRemove);
}
+ votingMember = newVotingMember;
log.debug("{}: Updated server config: isVoting: {}, peers: {}", id, votingMember, peerInfoMap.values());
setDynamicServerConfigurationInUse();
}
@Override
- public void addToPeers(String peerId, String address, VotingState votingState) {
+ public void addToPeers(final String peerId, final String address, final VotingState votingState) {
peerInfoMap.put(peerId, new PeerInfo(peerId, address, votingState));
numVotingPeers = -1;
}
@Override
- public void removePeer(String name) {
- if(getId().equals(name)) {
+ public void removePeer(final String name) {
+ if (getId().equals(name)) {
votingMember = false;
} else {
peerInfoMap.remove(name);
}
}
- @Override public ActorSelection getPeerActorSelection(String peerId) {
+ @Override public ActorSelection getPeerActorSelection(final String peerId) {
String peerAddress = getPeerAddress(peerId);
- if(peerAddress != null){
+ if (peerAddress != null) {
return actorSelection(peerAddress);
}
return null;
}
@Override
- public void setPeerAddress(String peerId, String peerAddress) {
+ public void setPeerAddress(final String peerId, final String peerAddress) {
PeerInfo peerInfo = peerInfoMap.get(peerId);
- if(peerInfo != null) {
+ if (peerInfo != null) {
log.info("Peer address for peer {} set to {}", peerId, peerAddress);
peerInfo.setAddress(peerAddress);
}
@Override
public SnapshotManager getSnapshotManager() {
- if(snapshotManager == null){
+ if (snapshotManager == null) {
snapshotManager = new SnapshotManager(this, log);
}
return snapshotManager;
}
@Override
- public void setTotalMemoryRetriever(LongSupplier retriever) {
+ public void setTotalMemoryRetriever(final LongSupplier retriever) {
totalMemoryRetriever = retriever == null ? JVM_MEMORY_RETRIEVER : retriever;
}
@Override
public void setDynamicServerConfigurationInUse() {
- this.dynamicServerConfiguration = true;
+ dynamicServerConfiguration = true;
}
@Override
- public ServerConfigurationPayload getPeerServerInfo(boolean includeSelf) {
+ public ServerConfigurationPayload getPeerServerInfo(final boolean includeSelf) {
if (!isDynamicServerConfigurationInUse()) {
return null;
}
- Collection<PeerInfo> peers = getPeers();
- List<ServerInfo> newConfig = new ArrayList<>(peers.size() + 1);
- for(PeerInfo peer: peers) {
+ final var peers = getPeers();
+ final var newConfig = ImmutableList.<ServerInfo>builderWithExpectedSize(peers.size() + (includeSelf ? 1 : 0));
+ for (PeerInfo peer : peers) {
newConfig.add(new ServerInfo(peer.getId(), peer.isVoting()));
}
- if(includeSelf) {
+ if (includeSelf) {
newConfig.add(new ServerInfo(getId(), votingMember));
}
- return new ServerConfigurationPayload(newConfig);
+ return new ServerConfigurationPayload(newConfig.build());
}
@Override
@Override
public boolean anyVotingPeers() {
- if(numVotingPeers < 0) {
+ if (numVotingPeers < 0) {
numVotingPeers = 0;
- for(PeerInfo info: getPeers()) {
- if(info.isVoting()) {
+ for (PeerInfo info: getPeers()) {
+ if (info.isVoting()) {
numVotingPeers++;
}
}
}
void setCurrentBehavior(final RaftActorBehavior behavior) {
- this.currentBehavior = Preconditions.checkNotNull(behavior);
+ currentBehavior = requireNonNull(behavior);
+ }
+
+ @Override
+ public Consumer<ApplyState> getApplyStateConsumer() {
+ return applyStateConsumer;
}
+ @Override
+ public FileBackedOutputStreamFactory getFileBackedOutputStreamFactory() {
+ return fileBackedOutputStreamFactory;
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
void close() {
if (currentBehavior != null) {
try {
}
}
}
+
+ @Override
+ public RaftActorLeadershipTransferCohort getRaftActorLeadershipTransferCohort() {
+ return leadershipTransferCohort;
+ }
+
+ @Override
+ @SuppressWarnings("checkstyle:hiddenField")
+ public void setRaftActorLeadershipTransferCohort(final RaftActorLeadershipTransferCohort leadershipTransferCohort) {
+ this.leadershipTransferCohort = leadershipTransferCohort;
+ }
}