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%2FFollower.java;h=0149b57e6e94f8ddf076a406f14eea1546d2aa1e;hp=d4755e63586f564cd71d106529cef910074b8cba;hb=8882e6077db69d22bcc57fcf12dd4a02a81a4967;hpb=4f14faf543088e101a8b3d234a30f4d6b3d68d77 diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java index d4755e6358..0149b57e6e 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java @@ -14,10 +14,10 @@ import java.util.ArrayList; 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.ServerConfigurationPayload; import org.opendaylight.controller.cluster.raft.Snapshot; import org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot; import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout; -import org.opendaylight.controller.cluster.raft.base.messages.FollowerInitialSyncUpStatus; import org.opendaylight.controller.cluster.raft.messages.AppendEntries; import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply; import org.opendaylight.controller.cluster.raft.messages.InstallSnapshot; @@ -40,15 +40,22 @@ public class Follower extends AbstractRaftActorBehavior { private SnapshotTracker snapshotTracker = null; - private final InitialSyncStatusTracker initialSyncStatusTracker; + private final SyncStatusTracker initialSyncStatusTracker; + + private static final int SYNC_THRESHOLD = 10; public Follower(RaftActorContext context) { + this(context, null); + } + + public Follower(RaftActorContext context, String initialLeaderId) { super(context, RaftState.Follower); + leaderId = initialLeaderId; - initialSyncStatusTracker = new InitialSyncStatusTracker(context.getActor()); + initialSyncStatusTracker = new SyncStatusTracker(context.getActor(), getId(), SYNC_THRESHOLD); if(context.getRaftPolicy().automaticElectionsEnabled()) { - if (context.getPeerAddresses().isEmpty()) { + if (context.getPeerIds().isEmpty() && getLeaderId() == null) { actor().tell(ELECTION_TIMEOUT, actor()); } else { scheduleElection(electionDuration()); @@ -102,7 +109,7 @@ public class Follower extends AbstractRaftActorBehavior { // to make it easier to read. Before refactoring ensure tests // cover the code properly - if (snapshotTracker != null) { + if (snapshotTracker != null || context.getSnapshotManager().isApplying()) { // if snapshot install is in progress, follower should just acknowledge append entries with a reply. AppendEntriesReply reply = new AppendEntriesReply(context.getId(), currentTerm(), true, lastIndex(), lastTerm(), context.getPayloadVersion()); @@ -147,7 +154,7 @@ public class Follower extends AbstractRaftActorBehavior { int addEntriesFrom = 0; if (context.getReplicatedLog().size() > 0) { - // Find the entry up until which the one that is not in the follower's log + // Find the entry up until the one that is not in the follower's log for (int i = 0;i < appendEntries.getEntries().size(); i++, addEntriesFrom++) { ReplicatedLogEntry matchEntry = appendEntries.getEntries().get(i); ReplicatedLogEntry newEntry = context.getReplicatedLog().get(matchEntry.getIndex()); @@ -161,12 +168,19 @@ public class Follower extends AbstractRaftActorBehavior { continue; } - LOG.debug("{}: Removing entries from log starting at {}", logName(), + if(!context.getRaftPolicy().applyModificationToStateBeforeConsensus()) { + + LOG.debug("{}: Removing entries from log starting at {}", logName(), matchEntry.getIndex()); - // Entries do not match so remove all subsequent entries - context.getReplicatedLog().removeFromAndPersist(matchEntry.getIndex()); - break; + // Entries do not match so remove all subsequent entries + context.getReplicatedLog().removeFromAndPersist(matchEntry.getIndex()); + break; + } else { + sender.tell(new AppendEntriesReply(context.getId(), currentTerm(), false, lastIndex, + lastTerm(), context.getPayloadVersion(), true), actor()); + return this; + } } } @@ -181,6 +195,10 @@ public class Follower extends AbstractRaftActorBehavior { LOG.debug("{}: Append entry to log {}", logName(), entry.getData()); context.getReplicatedLog().appendAndPersist(entry); + + if(entry.getData() instanceof ServerConfigurationPayload) { + context.updatePeerIds((ServerConfigurationPayload)entry.getData()); + } } LOG.debug("{}: Log size is now {}", logName(), context.getReplicatedLog().size()); @@ -313,7 +331,7 @@ public class Follower extends AbstractRaftActorBehavior { if (message instanceof ElectionTimeout) { LOG.debug("{}: Received ElectionTimeout - switching to Candidate", logName()); - return switchBehavior(new Candidate(context)); + return internalSwitchBehavior(RaftState.Candidate); } else if (message instanceof InstallSnapshot) { InstallSnapshot installSnapshot = (InstallSnapshot) message; @@ -327,12 +345,14 @@ public class Follower extends AbstractRaftActorBehavior { return super.handleMessage(sender, message); } - private void handleInstallSnapshot(ActorRef sender, InstallSnapshot installSnapshot) { + private void handleInstallSnapshot(final ActorRef sender, InstallSnapshot installSnapshot) { LOG.debug("{}: InstallSnapshot received from leader {}, datasize: {} , Chunk: {}/{}", logName(), installSnapshot.getLeaderId(), installSnapshot.getData().size(), installSnapshot.getChunkIndex(), installSnapshot.getTotalChunks()); + leaderId = installSnapshot.getLeaderId(); + if(snapshotTracker == null){ snapshotTracker = new SnapshotTracker(LOG, installSnapshot.getTotalChunks()); } @@ -340,6 +360,9 @@ public class Follower extends AbstractRaftActorBehavior { updateInitialSyncStatus(installSnapshot.getLastIncludedIndex(), installSnapshot.getLeaderId()); try { + final InstallSnapshotReply reply = new InstallSnapshotReply( + currentTerm(), context.getId(), installSnapshot.getChunkIndex(), true); + if(snapshotTracker.addChunk(installSnapshot.getChunkIndex(), installSnapshot.getData(), installSnapshot.getLastChunkHashCode())){ Snapshot snapshot = Snapshot.create(snapshotTracker.getSnapshot(), @@ -347,21 +370,33 @@ public class Follower extends AbstractRaftActorBehavior { installSnapshot.getLastIncludedIndex(), installSnapshot.getLastIncludedTerm(), installSnapshot.getLastIncludedIndex(), - installSnapshot.getLastIncludedTerm()); - - actor().tell(new ApplySnapshot(snapshot), actor()); + installSnapshot.getLastIncludedTerm(), + context.getTermInformation().getCurrentTerm(), + context.getTermInformation().getVotedFor(), + context.getPeerServerInfo()); - snapshotTracker = null; + ApplySnapshot.Callback applySnapshotCallback = new ApplySnapshot.Callback() { + @Override + public void onSuccess() { + LOG.debug("{}: handleInstallSnapshot returning: {}", logName(), reply); - } + sender.tell(reply, actor()); + } - InstallSnapshotReply reply = new InstallSnapshotReply( - currentTerm(), context.getId(), installSnapshot.getChunkIndex(), true); + @Override + public void onFailure() { + sender.tell(new InstallSnapshotReply(currentTerm(), context.getId(), -1, false), actor()); + } + }; - LOG.debug("{}: handleInstallSnapshot returning: {}", logName(), reply); + actor().tell(new ApplySnapshot(snapshot, applySnapshotCallback), actor()); - sender.tell(reply, actor()); + snapshotTracker = null; + } else { + LOG.debug("{}: handleInstallSnapshot returning: {}", logName(), reply); + sender.tell(reply, actor()); + } } catch (SnapshotTracker.InvalidChunkException e) { LOG.debug("{}: Exception in InstallSnapshot of follower", logName(), e); @@ -388,36 +423,4 @@ public class Follower extends AbstractRaftActorBehavior { SnapshotTracker getSnapshotTracker(){ return snapshotTracker; } - - private class InitialSyncStatusTracker { - - private static final long INVALID_LOG_INDEX = -2L; - private long initialLeaderCommit = INVALID_LOG_INDEX; - private boolean initialSyncUpDone = false; - private String syncedLeaderId = null; - private final ActorRef actor; - - public InitialSyncStatusTracker(ActorRef actor) { - this.actor = actor; - } - - public void update(String leaderId, long leaderCommit, long commitIndex){ - - if(!leaderId.equals(syncedLeaderId)){ - initialSyncUpDone = false; - initialLeaderCommit = INVALID_LOG_INDEX; - syncedLeaderId = leaderId; - } - - if(!initialSyncUpDone){ - if(initialLeaderCommit == INVALID_LOG_INDEX){ - actor.tell(new FollowerInitialSyncUpStatus(false, getId()), ActorRef.noSender()); - initialLeaderCommit = leaderCommit; - } else if(commitIndex >= initialLeaderCommit){ - actor.tell(new FollowerInitialSyncUpStatus(true, getId()), ActorRef.noSender()); - initialSyncUpDone = true; - } - } - } - } }