Search in sources :

Example 1 with DefaultRaftMember

use of io.atomix.protocols.raft.cluster.impl.DefaultRaftMember in project atomix by atomix.

the class LeaderRole method onJoin.

@Override
public CompletableFuture<JoinResponse> onJoin(final JoinRequest request) {
    raft.checkThread();
    logRequest(request);
    // See https://groups.google.com/forum/#!topic/raft-dev/t4xj6dJTP6E
    if (configuring() || initializing()) {
        return CompletableFuture.completedFuture(logResponse(JoinResponse.builder().withStatus(RaftResponse.Status.ERROR).build()));
    }
    // If the member is already a known member of the cluster, complete the join successfully.
    if (raft.getCluster().getMember(request.member().nodeId()) != null) {
        return CompletableFuture.completedFuture(logResponse(JoinResponse.builder().withStatus(RaftResponse.Status.OK).withIndex(raft.getCluster().getConfiguration().index()).withTerm(raft.getCluster().getConfiguration().term()).withTime(raft.getCluster().getConfiguration().time()).withMembers(raft.getCluster().getMembers()).build()));
    }
    RaftMember member = request.member();
    // Add the joining member to the members list. If the joining member's type is ACTIVE, join the member in the
    // PROMOTABLE state to allow it to get caught up without impacting the quorum size.
    Collection<RaftMember> members = raft.getCluster().getMembers();
    members.add(new DefaultRaftMember(member.nodeId(), member.getType(), Instant.now()));
    CompletableFuture<JoinResponse> future = new CompletableFuture<>();
    configure(members).whenComplete((index, error) -> {
        if (error == null) {
            future.complete(logResponse(JoinResponse.builder().withStatus(RaftResponse.Status.OK).withIndex(index).withTerm(raft.getCluster().getConfiguration().term()).withTime(raft.getCluster().getConfiguration().time()).withMembers(members).build()));
        } else {
            future.complete(logResponse(JoinResponse.builder().withStatus(RaftResponse.Status.ERROR).withError(RaftError.Type.PROTOCOL_ERROR).build()));
        }
    });
    return future;
}
Also used : JoinResponse(io.atomix.protocols.raft.protocol.JoinResponse) RaftMember(io.atomix.protocols.raft.cluster.RaftMember) DefaultRaftMember(io.atomix.protocols.raft.cluster.impl.DefaultRaftMember) CompletableFuture(java.util.concurrent.CompletableFuture) DefaultRaftMember(io.atomix.protocols.raft.cluster.impl.DefaultRaftMember)

Example 2 with DefaultRaftMember

use of io.atomix.protocols.raft.cluster.impl.DefaultRaftMember in project atomix by atomix.

the class RaftContext method setLeader.

/**
 * Sets the state leader.
 *
 * @param leader The state leader.
 */
public void setLeader(NodeId leader) {
    if (!Objects.equals(this.leader, leader)) {
        if (leader == null) {
            this.leader = null;
        } else {
            // If a valid leader ID was specified, it must be a member that's currently a member of the
            // ACTIVE members configuration. Note that we don't throw exceptions for unknown members. It's
            // possible that a failure following a configuration change could result in an unknown leader
            // sending AppendRequest to this server. Simply configure the leader if it's known.
            DefaultRaftMember member = cluster.getMember(leader);
            if (member != null) {
                this.leader = leader;
                log.info("Found leader {}", member.nodeId());
                electionListeners.forEach(l -> l.accept(member));
            }
        }
        this.lastVotedFor = null;
        meta.storeVote(null);
    }
}
Also used : DefaultRaftMember(io.atomix.protocols.raft.cluster.impl.DefaultRaftMember)

Example 3 with DefaultRaftMember

use of io.atomix.protocols.raft.cluster.impl.DefaultRaftMember in project atomix by atomix.

the class AbstractAppender method buildAppendEntriesRequest.

/**
 * Builds a populated AppendEntries request.
 */
@SuppressWarnings("unchecked")
protected AppendRequest buildAppendEntriesRequest(RaftMemberContext member, long lastIndex) {
    final RaftLogReader reader = member.getLogReader();
    final Indexed<RaftLogEntry> prevEntry = reader.getCurrentEntry();
    final DefaultRaftMember leader = raft.getLeader();
    AppendRequest.Builder builder = AppendRequest.builder().withTerm(raft.getTerm()).withLeader(leader != null ? leader.nodeId() : null).withPrevLogIndex(prevEntry != null ? prevEntry.index() : reader.getFirstIndex() - 1).withPrevLogTerm(prevEntry != null ? prevEntry.entry().term() : 0).withCommitIndex(raft.getCommitIndex());
    // Build a list of entries to send to the member.
    final List<RaftLogEntry> entries = new ArrayList<>();
    // Build a list of entries up to the MAX_BATCH_SIZE. Note that entries in the log may
    // be null if they've been compacted and the member to which we're sending entries is just
    // joining the cluster or is otherwise far behind. Null entries are simply skipped and not
    // counted towards the size of the batch.
    // If there exists an entry in the log with size >= MAX_BATCH_SIZE the logic ensures that
    // entry will be sent in a batch of size one
    int size = 0;
    // Iterate through the log until the last index or the end of the log is reached.
    while (reader.hasNext()) {
        // Otherwise, read the next entry and add it to the batch.
        Indexed<RaftLogEntry> entry = reader.next();
        entries.add(entry.entry());
        size += entry.size();
        if (entry.index() == lastIndex || size >= MAX_BATCH_SIZE) {
            break;
        }
    }
    // Add the entries to the request builder and build the request.
    return builder.withEntries(entries).build();
}
Also used : DefaultRaftMember(io.atomix.protocols.raft.cluster.impl.DefaultRaftMember) RaftLogReader(io.atomix.protocols.raft.storage.log.RaftLogReader) ArrayList(java.util.ArrayList) AppendRequest(io.atomix.protocols.raft.protocol.AppendRequest) RaftLogEntry(io.atomix.protocols.raft.storage.log.entry.RaftLogEntry)

Example 4 with DefaultRaftMember

use of io.atomix.protocols.raft.cluster.impl.DefaultRaftMember in project atomix by atomix.

the class AbstractAppender method buildInstallRequest.

/**
 * Builds an install request for the given member.
 */
protected InstallRequest buildInstallRequest(RaftMemberContext member, Snapshot snapshot) {
    if (member.getNextSnapshotIndex() != snapshot.index()) {
        member.setNextSnapshotIndex(snapshot.index());
        member.setNextSnapshotOffset(0);
    }
    InstallRequest request;
    synchronized (snapshot) {
        // Open a new snapshot reader.
        try (SnapshotReader reader = snapshot.openReader()) {
            // Skip to the next batch of bytes according to the snapshot chunk size and current offset.
            reader.skip(member.getNextSnapshotOffset() * MAX_BATCH_SIZE);
            byte[] data = new byte[Math.min(MAX_BATCH_SIZE, reader.remaining())];
            reader.read(data);
            // Create the install request, indicating whether this is the last chunk of data based on the number
            // of bytes remaining in the buffer.
            DefaultRaftMember leader = raft.getLeader();
            request = InstallRequest.builder().withTerm(raft.getTerm()).withLeader(leader != null ? leader.nodeId() : null).withIndex(snapshot.index()).withOffset(member.getNextSnapshotOffset()).withData(data).withComplete(!reader.hasRemaining()).build();
        }
    }
    return request;
}
Also used : DefaultRaftMember(io.atomix.protocols.raft.cluster.impl.DefaultRaftMember) InstallRequest(io.atomix.protocols.raft.protocol.InstallRequest) SnapshotReader(io.atomix.protocols.raft.storage.snapshot.SnapshotReader)

Example 5 with DefaultRaftMember

use of io.atomix.protocols.raft.cluster.impl.DefaultRaftMember in project atomix by atomix.

the class AbstractAppender method buildAppendEmptyRequest.

/**
 * Builds an empty AppendEntries request.
 * <p>
 * Empty append requests are used as heartbeats to followers.
 */
protected AppendRequest buildAppendEmptyRequest(RaftMemberContext member) {
    final RaftLogReader reader = member.getLogReader();
    // Read the previous entry from the reader.
    // The reader can be null for RESERVE members.
    Indexed<RaftLogEntry> prevEntry = reader != null ? reader.getCurrentEntry() : null;
    DefaultRaftMember leader = raft.getLeader();
    return AppendRequest.builder().withTerm(raft.getTerm()).withLeader(leader != null ? leader.nodeId() : null).withPrevLogIndex(prevEntry != null ? prevEntry.index() : reader != null ? reader.getFirstIndex() - 1 : 0).withPrevLogTerm(prevEntry != null ? prevEntry.entry().term() : 0).withEntries(Collections.emptyList()).withCommitIndex(raft.getCommitIndex()).build();
}
Also used : DefaultRaftMember(io.atomix.protocols.raft.cluster.impl.DefaultRaftMember) RaftLogReader(io.atomix.protocols.raft.storage.log.RaftLogReader) RaftLogEntry(io.atomix.protocols.raft.storage.log.entry.RaftLogEntry)

Aggregations

DefaultRaftMember (io.atomix.protocols.raft.cluster.impl.DefaultRaftMember)10 RaftLogEntry (io.atomix.protocols.raft.storage.log.entry.RaftLogEntry)4 CompletableFuture (java.util.concurrent.CompletableFuture)3 RaftMember (io.atomix.protocols.raft.cluster.RaftMember)2 RaftLogReader (io.atomix.protocols.raft.storage.log.RaftLogReader)2 Quorum (io.atomix.protocols.raft.utils.Quorum)2 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)2 RaftException (io.atomix.protocols.raft.RaftException)1 RaftMemberContext (io.atomix.protocols.raft.cluster.impl.RaftMemberContext)1 AppendRequest (io.atomix.protocols.raft.protocol.AppendRequest)1 InstallRequest (io.atomix.protocols.raft.protocol.InstallRequest)1 JoinResponse (io.atomix.protocols.raft.protocol.JoinResponse)1 PollRequest (io.atomix.protocols.raft.protocol.PollRequest)1 ReconfigureResponse (io.atomix.protocols.raft.protocol.ReconfigureResponse)1 VoteRequest (io.atomix.protocols.raft.protocol.VoteRequest)1 SnapshotReader (io.atomix.protocols.raft.storage.snapshot.SnapshotReader)1 Configuration (io.atomix.protocols.raft.storage.system.Configuration)1 Duration (java.time.Duration)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1