Search in sources :

Example 1 with PollRequest

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());
    }
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Quorum(io.atomix.protocols.raft.utils.Quorum) DefaultRaftMember(io.atomix.protocols.raft.cluster.impl.DefaultRaftMember) PollRequest(io.atomix.protocols.raft.protocol.PollRequest) RaftLogEntry(io.atomix.protocols.raft.storage.log.entry.RaftLogEntry)

Aggregations

DefaultRaftMember (io.atomix.protocols.raft.cluster.impl.DefaultRaftMember)1 PollRequest (io.atomix.protocols.raft.protocol.PollRequest)1 RaftLogEntry (io.atomix.protocols.raft.storage.log.entry.RaftLogEntry)1 Quorum (io.atomix.protocols.raft.utils.Quorum)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1