X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-akka-raft%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fraft%2Fbehaviors%2FAbstractRaftActorBehavior.java;h=0210dc4b1d0ed703a7e76fb8651f97b908563629;hp=0b0b4c7cd642480f92dd600a4f8f10be07977dc4;hb=ce0c4f4fc0557aaf46a73913a18b83ec29051570;hpb=ee303a25aa7c90ab9f7f28c1effef5254a4c7676 diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehavior.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehavior.java index 0b0b4c7cd6..0210dc4b1d 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehavior.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehavior.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.cluster.raft.behaviors; import akka.actor.ActorRef; import akka.actor.Cancellable; +import com.google.common.base.Preconditions; import java.util.Random; import java.util.concurrent.TimeUnit; import org.opendaylight.controller.cluster.raft.ClientRequestTracker; @@ -17,7 +18,7 @@ import org.opendaylight.controller.cluster.raft.RaftActorContext; import org.opendaylight.controller.cluster.raft.RaftState; import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry; import org.opendaylight.controller.cluster.raft.SerializationUtils; -import org.opendaylight.controller.cluster.raft.base.messages.ApplyLogEntries; +import org.opendaylight.controller.cluster.raft.base.messages.ApplyJournalEntries; import org.opendaylight.controller.cluster.raft.base.messages.ApplyState; import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout; import org.opendaylight.controller.cluster.raft.messages.AppendEntries; @@ -38,7 +39,6 @@ import scala.concurrent.duration.FiniteDuration; * set currentTerm = T, convert to follower (§5.1) */ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { - /** * Information about the RaftActor whose behavior this class represents */ @@ -54,31 +54,41 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { */ private Cancellable electionCancel = null; - /** - * - */ - protected String leaderId = null; - private long replicatedToAllIndex = -1; private final String logName; private final RaftState state; - protected AbstractRaftActorBehavior(RaftActorContext context, RaftState state) { - this.context = context; - this.state = state; + AbstractRaftActorBehavior(final RaftActorContext context, final RaftState state) { + this.context = Preconditions.checkNotNull(context); + this.state = Preconditions.checkNotNull(state); this.LOG = context.getLogger(); logName = String.format("%s (%s)", context.getId(), state); } + public static RaftActorBehavior createBehavior(final RaftActorContext context, final RaftState state) { + switch (state) { + case Candidate: + return new Candidate(context); + case Follower: + return new Follower(context); + case IsolatedLeader: + return new IsolatedLeader(context); + case Leader: + return new Leader(context); + default: + throw new IllegalArgumentException("Unhandled state " + state); + } + } + @Override - public RaftState state() { + public final RaftState state() { return state; } - public String logName() { + protected final String logName() { return logName; } @@ -102,7 +112,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { * * @param sender The actor that sent this message * @param appendEntries The AppendEntries message - * @return + * @return a new behavior if it was changed or the current behavior */ protected abstract RaftActorBehavior handleAppendEntries(ActorRef sender, AppendEntries appendEntries); @@ -114,7 +124,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { * * @param sender * @param appendEntries - * @return + * @return a new behavior if it was changed or the current behavior */ protected RaftActorBehavior appendEntries(ActorRef sender, AppendEntries appendEntries) { @@ -128,7 +138,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { sender.tell( new AppendEntriesReply(context.getId(), currentTerm(), false, - lastIndex(), lastTerm()), actor() + lastIndex(), lastTerm(), context.getPayloadVersion()), actor() ); return this; } @@ -147,7 +157,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { * * @param sender The actor that sent this message * @param appendEntriesReply The AppendEntriesReply message - * @return + * @return a new behavior if it was changed or the current behavior */ protected abstract RaftActorBehavior handleAppendEntriesReply(ActorRef sender, AppendEntriesReply appendEntriesReply); @@ -158,12 +168,28 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { * * @param sender * @param requestVote - * @return + * @return a new behavior if it was changed or the current behavior */ protected RaftActorBehavior requestVote(ActorRef sender, RequestVote requestVote) { LOG.debug("{}: In requestVote: {}", logName(), requestVote); + boolean grantVote = canGrantVote(requestVote); + + if(grantVote) { + context.getTermInformation().updateAndPersist(requestVote.getTerm(), requestVote.getCandidateId()); + } + + RequestVoteReply reply = new RequestVoteReply(currentTerm(), grantVote); + + LOG.debug("{}: requestVote returning: {}", logName(), reply); + + sender.tell(reply, actor()); + + return this; + } + + protected boolean canGrantVote(RequestVote requestVote){ boolean grantVote = false; // Reply false if term < currentTerm (§5.1) @@ -173,7 +199,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { // If votedFor is null or candidateId, and candidate’s log is at // least as up-to-date as receiver’s log, grant vote (§5.2, §5.4) } else if (votedFor() == null || votedFor() - .equals(requestVote.getCandidateId())) { + .equals(requestVote.getCandidateId())) { boolean candidateLatest = false; @@ -187,24 +213,15 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { if (requestVote.getLastLogTerm() > lastTerm()) { candidateLatest = true; } else if ((requestVote.getLastLogTerm() == lastTerm()) - && requestVote.getLastLogIndex() >= lastIndex()) { + && requestVote.getLastLogIndex() >= lastIndex()) { candidateLatest = true; } if (candidateLatest) { grantVote = true; - context.getTermInformation().updateAndPersist(requestVote.getTerm(), - requestVote.getCandidateId()); } } - - RequestVoteReply reply = new RequestVoteReply(currentTerm(), grantVote); - - LOG.debug("{}: requestVote returning: {}", logName(), reply); - - sender.tell(reply, actor()); - - return this; + return grantVote; } /** @@ -217,15 +234,14 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { * * @param sender The actor that sent this message * @param requestVoteReply The RequestVoteReply message - * @return + * @return a new behavior if it was changed or the current behavior */ protected abstract RaftActorBehavior handleRequestVoteReply(ActorRef sender, RequestVoteReply requestVoteReply); /** - * Creates a random election duration * - * @return + * @return a random election duration */ protected FiniteDuration electionDuration() { long variance = new Random().nextInt(context.getConfigParams().getElectionTimeVariance()); @@ -242,79 +258,72 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { } } + protected boolean canStartElection() { + return context.getRaftPolicy().automaticElectionsEnabled() && context.isVotingMember(); + } + /** * schedule a new election * - * @param interval + * @param interval the duration after which we should trigger a new election */ protected void scheduleElection(FiniteDuration interval) { stopElection(); - // Schedule an election. When the scheduler triggers an ElectionTimeout - // message is sent to itself - electionCancel = - context.getActorSystem().scheduler().scheduleOnce(interval, - context.getActor(), new ElectionTimeout(), - context.getActorSystem().dispatcher(), context.getActor()); + if(canStartElection()) { + // Schedule an election. When the scheduler triggers an ElectionTimeout message is sent to itself + electionCancel = context.getActorSystem().scheduler().scheduleOnce(interval, context.getActor(), + ElectionTimeout.INSTANCE, context.getActorSystem().dispatcher(), context.getActor()); + } } /** - * Get the current term - * @return + * @return the current term */ protected long currentTerm() { return context.getTermInformation().getCurrentTerm(); } /** - * Get the candidate for whom we voted in the current term - * @return + * @return the candidate for whom we voted in the current term */ protected String votedFor() { return context.getTermInformation().getVotedFor(); } /** - * Get the actor associated with this behavior - * @return + * @return the actor associated with this behavior */ protected ActorRef actor() { return context.getActor(); } /** - * Get the term from the last entry in the log * - * @return + * @return the term from the last entry in the log */ protected long lastTerm() { return context.getReplicatedLog().lastTerm(); } /** - * Get the index from the last entry in the log - * - * @return + * @return the index from the last entry in the log */ protected long lastIndex() { return context.getReplicatedLog().lastIndex(); } /** - * Find the client request tracker for a specific logIndex - * * @param logIndex - * @return + * @return the client request tracker for the specified logIndex */ protected ClientRequestTracker findClientRequestTracker(long logIndex) { return null; } /** - * Find the client request tracker for a specific logIndex - * * @param logIndex - * @return + * @return the client request tracker for the specified logIndex */ protected ClientRequestTracker removeClientRequestTracker(long logIndex) { return null; @@ -322,9 +331,8 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { /** - * Find the log index from the previous to last entry in the log * - * @return + * @return log index from the previous to last entry in the log */ protected long prevLogIndex(long index){ ReplicatedLogEntry prevEntry = @@ -336,8 +344,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { } /** - * Find the log term from the previous to last entry in the log - * @return + * @return log term from the previous to last entry in the log */ protected long prevLogTerm(long index){ ReplicatedLogEntry prevEntry = @@ -393,7 +400,7 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { // will be used during recovery //in case if the above code throws an error and this message is not sent, it would be fine // as the append entries received later would initiate add this message to the journal - actor().tell(new ApplyLogEntries((int) context.getLastApplied()), actor()); + actor().tell(new ApplyJournalEntries(context.getLastApplied()), actor()); } protected Object fromSerializableMessage(Object serializable){ @@ -414,21 +421,29 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { return this; } - @Override public String getLeaderId() { - return leaderId; + @Override + public RaftActorBehavior switchBehavior(RaftActorBehavior behavior) { + return internalSwitchBehavior(behavior); + } + + protected RaftActorBehavior internalSwitchBehavior(RaftState newState) { + if(context.getRaftPolicy().automaticElectionsEnabled()){ + return internalSwitchBehavior(createBehavior(context, newState)); + } + return this; } - protected RaftActorBehavior switchBehavior(RaftActorBehavior behavior) { - LOG.info("{} :- Switching from behavior {} to {}", logName(), this.state(), behavior.state()); + private RaftActorBehavior internalSwitchBehavior(RaftActorBehavior newBehavior) { + LOG.info("{} :- Switching from behavior {} to {}", logName(), this.state(), newBehavior.state()); try { close(); } catch (Exception e) { LOG.error("{}: Failed to close behavior : {}", logName(), this.state(), e); } - - return behavior; + return newBehavior; } + protected int getMajorityVoteCount(int numPeers) { // Votes are required from a majority of the peers including self. // The numMajority field therefore stores a calculated value @@ -460,20 +475,14 @@ public abstract class AbstractRaftActorBehavior implements RaftActorBehavior { * @param snapshotCapturedIndex */ protected void performSnapshotWithoutCapture(final long snapshotCapturedIndex) { - // we would want to keep the lastApplied as its used while capturing snapshots - long lastApplied = context.getLastApplied(); - long tempMin = Math.min(snapshotCapturedIndex, (lastApplied > -1 ? lastApplied - 1 : -1)); - - if (tempMin > -1 && context.getReplicatedLog().isPresent(tempMin)) { - LOG.debug("{}: fakeSnapshot purging log to {} for term {}", logName(), tempMin, - context.getTermInformation().getCurrentTerm()); - - //use the term of the temp-min, since we check for isPresent, entry will not be null - ReplicatedLogEntry entry = context.getReplicatedLog().get(tempMin); - context.getReplicatedLog().snapshotPreCommit(tempMin, entry.getTerm()); - context.getReplicatedLog().snapshotCommit(); - setReplicatedToAllIndex(tempMin); + long actualIndex = context.getSnapshotManager().trimLog(snapshotCapturedIndex); + + if(actualIndex != -1){ + setReplicatedToAllIndex(actualIndex); } } + protected String getId(){ + return context.getId(); + } }