replicatedLog.lastIndex(), replicatedLog.snapshotIndex,
replicatedLog.snapshotTerm, replicatedLog.size());
currentBehavior = switchBehavior(RaftState.Follower);
+ onStateChanged();
}
}
} else if (message instanceof FindLeader) {
getSender().tell(
- new FindLeaderReply(
- context.getPeerAddress(currentBehavior.getLeaderId())),
+ new FindLeaderReply(getLeaderAddress()),
getSelf()
);
// TODO: Handle failure in saving the snapshot
- } else if (message instanceof FindLeader){
-
- getSender().tell(new FindLeaderReply(
- context.getPeerAddress(currentBehavior.getLeaderId())),
- getSelf());
-
} else if (message instanceof AddRaftPeer){
// FIXME : Do not add raft peers like this.
RaftState state =
currentBehavior.handleMessage(getSender(), message);
+ RaftActorBehavior oldBehavior = currentBehavior;
currentBehavior = switchBehavior(state);
+ if(oldBehavior != currentBehavior){
+ onStateChanged();
+ }
}
}
* @return A reference to the leader if known, null otherwise
*/
protected ActorSelection getLeader(){
- String leaderId = currentBehavior.getLeaderId();
- if (leaderId == null) {
+ String leaderAddress = getLeaderAddress();
+
+ if(leaderAddress == null){
return null;
}
- String peerAddress = context.getPeerAddress(leaderId);
- LOG.debug("getLeader leaderId = " + leaderId + " peerAddress = "
- + peerAddress);
- return context.actorSelection(peerAddress);
+
+ return context.actorSelection(leaderAddress);
+ }
+
+ /**
+ *
+ * @return the current leader's id
+ */
+ protected String getLeaderId(){
+ return currentBehavior.getLeaderId();
}
protected RaftState getRaftState() {
return currentBehavior.state();
}
+ protected ReplicatedLogEntry getLastLogEntry() {
+ return replicatedLog.last();
+ }
+
+ protected Long getCurrentTerm(){
+ return context.getTermInformation().getCurrentTerm();
+ }
+
+ protected Long getCommitIndex(){
+ return context.getCommitIndex();
+ }
+
+ protected Long getLastApplied(){
+ return context.getLastApplied();
+ }
+
/**
* setPeerAddress sets the address of a known peer at a later time.
* <p>
*/
protected abstract void applySnapshot(Object snapshot);
+ /**
+ * This method will be called by the RaftActor when the state of the
+ * RaftActor changes. The derived actor can then use methods like
+ * isLeader or getLeader to do something useful
+ */
+ protected abstract void onStateChanged();
+
private RaftActorBehavior switchBehavior(RaftState state) {
if (currentBehavior != null) {
if (currentBehavior.state() == state) {
} else {
behavior = new Leader(context);
}
+
+
+
return behavior;
}
deleteMessages(sequenceNumber);
}
+ private String getLeaderAddress(){
+ if(isLeader()){
+ return getSelf().path().toString();
+ }
+ String leaderId = currentBehavior.getLeaderId();
+ if (leaderId == null) {
+ return null;
+ }
+ String peerAddress = context.getPeerAddress(leaderId);
+ LOG.debug("getLeaderAddress leaderId = " + leaderId + " peerAddress = "
+ + peerAddress);
+
+ return peerAddress;
+ }
+
private class ReplicatedLogImpl extends AbstractReplicatedLogImpl {
}
@Override public void update(long currentTerm, String votedFor) {
- LOG.info("Set currentTerm={}, votedFor={}", currentTerm, votedFor);
+ LOG.debug("Set currentTerm={}, votedFor={}", currentTerm, votedFor);
this.currentTerm = currentTerm;
this.votedFor = votedFor;