use of io.atomix.protocols.raft.protocol.PollRequest in project atomix by atomix.
the class FollowerRole method sendPollRequests.
/**
* Polls all members of the cluster to determine whether this member should transition to the CANDIDATE state.
*/
private void sendPollRequests() {
// Set a new timer within which other nodes must respond in order for this node to transition to candidate.
heartbeatTimer = raft.getThreadContext().schedule(raft.getElectionTimeout(), () -> {
log.debug("Failed to poll a majority of the cluster in {}", raft.getElectionTimeout());
resetHeartbeatTimeout();
});
// Create a quorum that will track the number of nodes that have responded to the poll request.
final AtomicBoolean complete = new AtomicBoolean();
final Set<DefaultRaftMember> votingMembers = raft.getCluster().getActiveMemberStates().stream().map(RaftMemberContext::getMember).collect(Collectors.toSet());
// If there are no other members in the cluster, immediately transition to leader.
if (votingMembers.isEmpty()) {
raft.transition(RaftServer.Role.CANDIDATE);
return;
}
final Quorum quorum = new Quorum(raft.getCluster().getQuorum(), (elected) -> {
// If a majority of the cluster indicated they would vote for us then transition to candidate.
complete.set(true);
if (elected) {
raft.transition(RaftServer.Role.CANDIDATE);
} else {
resetHeartbeatTimeout();
}
});
// First, load the last log entry to get its term. We load the entry
// by its index since the index is required by the protocol.
final Indexed<RaftLogEntry> lastEntry = raft.getLogWriter().getLastEntry();
final long lastTerm;
if (lastEntry != null) {
lastTerm = lastEntry.entry().term();
} else {
lastTerm = 0;
}
log.debug("Polling members {}", votingMembers);
// of the cluster and vote each member for a vote.
for (DefaultRaftMember member : votingMembers) {
log.debug("Polling {} for next term {}", member, raft.getTerm() + 1);
PollRequest request = PollRequest.builder().withTerm(raft.getTerm()).withCandidate(raft.getCluster().getMember().nodeId()).withLastLogIndex(lastEntry != null ? lastEntry.index() : 0).withLastLogTerm(lastTerm).build();
raft.getProtocol().poll(member.nodeId(), request).whenCompleteAsync((response, error) -> {
raft.checkThread();
if (isRunning() && !complete.get()) {
if (error != null) {
log.warn("{}", error.getMessage());
quorum.fail();
} else {
if (response.term() > raft.getTerm()) {
raft.setTerm(response.term());
}
if (!response.accepted()) {
log.debug("Received rejected poll from {}", member);
quorum.fail();
} else if (response.term() != raft.getTerm()) {
log.debug("Received accepted poll for a different term from {}", member);
quorum.fail();
} else {
log.debug("Received accepted poll from {}", member);
quorum.succeed();
}
}
}
}, raft.getThreadContext());
}
}
Aggregations