+ 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)
+ if (requestVote.getTerm() < currentTerm()) {
+ grantVote = false;
+
+ // 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())) {
+
+ boolean candidateLatest = false;
+
+ // From §5.4.1
+ // Raft determines which of two logs is more up-to-date
+ // by comparing the index and term of the last entries in the
+ // logs. If the logs have last entries with different terms, then
+ // the log with the later term is more up-to-date. If the logs
+ // end with the same term, then whichever log is longer is
+ // more up-to-date.
+ if (requestVote.getLastLogTerm() > lastTerm()) {
+ candidateLatest = true;
+ } else if ((requestVote.getLastLogTerm() == lastTerm())
+ && requestVote.getLastLogIndex() >= lastIndex()) {
+ candidateLatest = true;
+ }
+
+ if (candidateLatest) {
+ grantVote = true;
+ }
+ }
+ return grantVote;
+ }