io.atomix.protocols.raft.cluster.impl.DefaultRaftMember Java Examples

The following examples show how to use io.atomix.protocols.raft.cluster.impl.DefaultRaftMember. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: RaftContext.java    From atomix with Apache License 2.0 6 votes vote down vote up
/**
 * Sets the state leader.
 *
 * @param leader The state leader.
 */
public void setLeader(MemberId 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.memberId());
        electionListeners.forEach(l -> l.accept(member));
      }
    }

    this.lastVotedFor = null;
    meta.storeVote(null);
  }
}
 
Example #2
Source File: AbstractAppender.java    From atomix with Apache License 2.0 6 votes vote down vote up
/**
 * 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.memberId() : 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();
}
 
Example #3
Source File: AbstractRole.java    From atomix with Apache License 2.0 6 votes vote down vote up
/**
 * Forwards the given request to the leader if possible.
 */
protected <T extends RaftRequest, U extends RaftResponse> CompletableFuture<U> forward(T request, BiFunction<MemberId, T, CompletableFuture<U>> function) {
  CompletableFuture<U> future = new CompletableFuture<>();
  DefaultRaftMember leader = raft.getLeader();
  if (leader == null) {
    return Futures.exceptionalFuture(new RaftException.NoLeader("No leader found"));
  }

  function.apply(leader.memberId(), request).whenCompleteAsync((response, error) -> {
    if (error == null) {
      future.complete(response);
    } else {
      future.completeExceptionally(error);
    }
  }, raft.getThreadContext());
  return future;
}
 
Example #4
Source File: RaftContext.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Sets the state last voted for candidate.
 *
 * @param candidate The candidate that was voted for.
 */
public void setLastVotedFor(MemberId candidate) {
  // If we've already voted for another candidate in this term then the last voted for candidate cannot be overridden.
  checkState(!(lastVotedFor != null && candidate != null), "Already voted for another candidate");
  DefaultRaftMember member = cluster.getMember(candidate);
  checkState(member != null, "Unknown candidate: %d", candidate);
  this.lastVotedFor = candidate;
  meta.storeVote(this.lastVotedFor);

  if (candidate != null) {
    log.debug("Voted for {}", member.memberId());
  } else {
    log.trace("Reset last voted for");
  }
}
 
Example #5
Source File: AbstractAppender.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Builds a configure request for the given member.
 */
protected ConfigureRequest buildConfigureRequest(RaftMemberContext member) {
  DefaultRaftMember leader = raft.getLeader();
  return ConfigureRequest.builder()
      .withTerm(raft.getTerm())
      .withLeader(leader != null ? leader.memberId() : null)
      .withIndex(raft.getCluster().getConfiguration().index())
      .withTime(raft.getCluster().getConfiguration().time())
      .withMembers(raft.getCluster().getConfiguration().members())
      .build();
}
 
Example #6
Source File: AbstractAppender.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * 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.memberId() : null)
          .withIndex(snapshot.index())
          .withTimestamp(snapshot.timestamp().unixTimestamp())
          .withVersion(snapshot.version())
          .withOffset(member.getNextSnapshotOffset())
          .withData(data)
          .withComplete(!reader.hasRemaining())
          .build();
    }
  }

  return request;
}
 
Example #7
Source File: RaftContext.java    From atomix with Apache License 2.0 4 votes vote down vote up
/**
 * Returns the state leader.
 *
 * @return The state leader.
 */
public DefaultRaftMember getLeader() {
  // Store in a local variable to prevent race conditions and/or multiple volatile lookups.
  MemberId leader = this.leader;
  return leader != null ? cluster.getMember(leader) : null;
}
 
Example #8
Source File: FollowerRole.java    From atomix with Apache License 2.0 4 votes vote down vote up
/**
 * 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 (raft.getLeader() == null && 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);

  // Once we got the last log term, iterate through each current member
  // 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().memberId())
        .withLastLogIndex(lastEntry != null ? lastEntry.index() : 0)
        .withLastLogTerm(lastTerm)
        .build();
    raft.getProtocol().poll(member.memberId(), 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());
  }
}