io.atomix.protocols.raft.protocol.AppendResponse Java Examples

The following examples show how to use io.atomix.protocols.raft.protocol.AppendResponse. 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: PassiveRole.java    From atomix with Apache License 2.0 6 votes vote down vote up
/**
 * Handles an AppendRequest.
 */
protected CompletableFuture<AppendResponse> handleAppend(final AppendRequest request) {
  CompletableFuture<AppendResponse> future = new CompletableFuture<>();

  // Check that the term of the given request matches the local term or update the term.
  if (!checkTerm(request, future)) {
    return future;
  }

  // Check that the previous index/term matches the local log's last entry.
  if (!checkPreviousEntry(request, future)) {
    return future;
  }

  // Append the entries to the log.
  appendEntries(request, future);
  return future;
}
 
Example #2
Source File: ActiveRole.java    From atomix with Apache License 2.0 6 votes vote down vote up
@Override
public CompletableFuture<AppendResponse> onAppend(final AppendRequest request) {
  raft.checkThread();
  logRequest(request);

  // If the request indicates a term that is greater than the current term then
  // assign that term and leader to the current context and transition to follower.
  boolean transition = updateTermAndLeader(request.term(), request.leader());

  // Handle the append request.
  CompletableFuture<AppendResponse> future = handleAppend(request);

  // If a transition is required then transition back to the follower state.
  // If the node is already a follower then the transition will be ignored.
  if (transition) {
    raft.transition(RaftServer.Role.FOLLOWER);
  }
  return future;
}
 
Example #3
Source File: LeaderRole.java    From atomix with Apache License 2.0 6 votes vote down vote up
@Override
public CompletableFuture<AppendResponse> onAppend(final AppendRequest request) {
  raft.checkThread();
  if (updateTermAndLeader(request.term(), request.leader())) {
    CompletableFuture<AppendResponse> future = super.onAppend(request);
    raft.transition(RaftServer.Role.FOLLOWER);
    return future;
  } else if (request.term() < raft.getTerm()) {
    logRequest(request);
    return CompletableFuture.completedFuture(logResponse(AppendResponse.builder()
        .withStatus(RaftResponse.Status.OK)
        .withTerm(raft.getTerm())
        .withSucceeded(false)
        .withLastLogIndex(raft.getLogWriter().getLastIndex())
        .withLastSnapshotIndex(raft.getSnapshotStore().getCurrentSnapshotIndex())
        .build()));
  } else {
    raft.setLeader(request.leader());
    raft.transition(RaftServer.Role.FOLLOWER);
    return super.onAppend(request);
  }
}
 
Example #4
Source File: AbstractAppender.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Handles a {@link RaftResponse.Status#OK} response.
 */
protected void handleAppendResponseOk(RaftMemberContext member, AppendRequest request, AppendResponse response) {
  // Reset the member failure count and update the member's availability status if necessary.
  succeedAttempt(member);

  // If replication succeeded then trigger commit futures.
  if (response.succeeded()) {
    updateMatchIndex(member, response);

    // If there are more entries to send then attempt to send another commit.
    if (request.prevLogIndex() != response.lastLogIndex() && hasMoreEntries(member)) {
      appendEntries(member);
    }
  }
  // If we've received a greater term, update the term and transition back to follower.
  else if (response.term() > raft.getTerm()) {
    raft.setTerm(response.term());
    raft.setLeader(null);
    raft.transition(RaftServer.Role.FOLLOWER);
  }
  // If the response failed, the follower should have provided the correct last index in their log. This helps
  // us converge on the matchIndex faster than by simply decrementing nextIndex one index at a time.
  else {
    resetMatchIndex(member, response);
    resetNextIndex(member, response);
    resetSnapshotIndex(member, response);

    // If there are more entries to send then attempt to send another commit.
    if (response.lastLogIndex() != request.prevLogIndex() && hasMoreEntries(member)) {
      appendEntries(member);
    }
  }
}
 
Example #5
Source File: PassiveRole.java    From atomix with Apache License 2.0 5 votes vote down vote up
@Override
public CompletableFuture<AppendResponse> onAppend(final AppendRequest request) {
  raft.checkThread();
  logRequest(request);
  updateTermAndLeader(request.term(), request.leader());
  return handleAppend(request);
}
 
Example #6
Source File: LeaderAppender.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Handles a {@link io.atomix.protocols.raft.protocol.RaftResponse.Status#ERROR} response.
 */
protected void handleAppendResponseError(RaftMemberContext member, AppendRequest request, AppendResponse response) {
  // If we've received a greater term, update the term and transition back to follower.
  if (response.term() > raft.getTerm()) {
    log.debug("Received higher term from {}", member.getMember().memberId());
    raft.setTerm(response.term());
    raft.setLeader(null);
    raft.transition(RaftServer.Role.FOLLOWER);
  } else {
    super.handleAppendResponseError(member, request, response);
  }
}
 
Example #7
Source File: LeaderAppender.java    From atomix with Apache License 2.0 5 votes vote down vote up
@Override
protected void handleAppendResponseOk(RaftMemberContext member, AppendRequest request, AppendResponse response) {
  // Reset the member failure count and update the member's availability status if necessary.
  succeedAttempt(member);

  // If replication succeeded then trigger commit futures.
  if (response.succeeded()) {
    member.appendSucceeded();
    updateMatchIndex(member, response);

    // If entries were committed to the replica then check commit indexes.
    if (!request.entries().isEmpty()) {
      commitEntries();
    }

    // If there are more entries to send then attempt to send another commit.
    if (hasMoreEntries(member)) {
      appendEntries(member);
    }
  }
  // If we've received a greater term, update the term and transition back to follower.
  else if (response.term() > raft.getTerm()) {
    raft.setTerm(response.term());
    raft.setLeader(null);
    raft.transition(RaftServer.Role.FOLLOWER);
  }
  // If the response failed, the follower should have provided the correct last index in their log. This helps
  // us converge on the matchIndex faster than by simply decrementing nextIndex one index at a time.
  else {
    member.appendFailed();
    resetMatchIndex(member, response);
    resetNextIndex(member, response);
    resetSnapshotIndex(member, response);

    // If there are more entries to send then attempt to send another commit.
    if (hasMoreEntries(member)) {
      appendEntries(member);
    }
  }
}
 
Example #8
Source File: PassiveRole.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Checks the leader's term of the given AppendRequest, returning a boolean indicating whether to continue
 * handling the request.
 */
protected boolean checkTerm(AppendRequest request, CompletableFuture<AppendResponse> future) {
  RaftLogWriter writer = raft.getLogWriter();
  if (request.term() < raft.getTerm()) {
    log.debug("Rejected {}: request term is less than the current term ({})", request, raft.getTerm());
    return failAppend(writer.getLastIndex(), future);
  }
  return true;
}
 
Example #9
Source File: AbstractAppender.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Resets the snapshot index of the member when a response fails.
 */
protected void resetSnapshotIndex(RaftMemberContext member, AppendResponse response) {
  final long snapshotIndex = response.lastSnapshotIndex();
  if (member.getSnapshotIndex() != snapshotIndex) {
    member.setSnapshotIndex(snapshotIndex);
    log.warn("Reset snapshot index for {} to {}", member, snapshotIndex);
  }
}
 
Example #10
Source File: AbstractAppender.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Resets the next index when a response fails.
 */
protected void resetNextIndex(RaftMemberContext member, AppendResponse response) {
  long nextIndex = response.lastLogIndex() + 1;
  if (member.getLogReader().getNextIndex() != nextIndex) {
    member.getLogReader().reset(nextIndex);
    log.trace("Reset next index for {} to {}", member, nextIndex);
  }
}
 
Example #11
Source File: AbstractAppender.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Resets the match index when a response fails.
 */
protected void resetMatchIndex(RaftMemberContext member, AppendResponse response) {
  if (response.lastLogIndex() < member.getMatchIndex()) {
    member.setMatchIndex(response.lastLogIndex());
    log.trace("Reset match index for {} to {}", member, member.getMatchIndex());
  }
}
 
Example #12
Source File: AbstractAppender.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Handles a {@link RaftResponse.Status#ERROR} response.
 */
protected void handleAppendResponseError(RaftMemberContext member, AppendRequest request, AppendResponse response) {
  // If any other error occurred, increment the failure count for the member. Log the first three failures,
  // and thereafter log 1% of the failures. This keeps the log from filling up with annoying error messages
  // when attempting to send entries to down followers.
  int failures = member.incrementFailureCount();
  if (failures <= 3 || failures % 100 == 0) {
    log.debug("{} to {} failed: {}", request, member.getMember().memberId(), response.error() != null ? response.error() : "");
  }
}
 
Example #13
Source File: AbstractAppender.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Handles an append response.
 */
protected void handleAppendResponse(RaftMemberContext member, AppendRequest request, AppendResponse response, long timestamp) {
  if (response.status() == RaftResponse.Status.OK) {
    handleAppendResponseOk(member, request, response);
  } else {
    handleAppendResponseError(member, request, response);
  }
}
 
Example #14
Source File: PassiveRole.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Returns a successful append response.
 *
 * @param succeeded    whether the append succeeded
 * @param lastLogIndex the last log index
 * @param future       the append response future
 * @return the append response status
 */
protected boolean completeAppend(boolean succeeded, long lastLogIndex, CompletableFuture<AppendResponse> future) {
  future.complete(logResponse(AppendResponse.builder()
      .withStatus(RaftResponse.Status.OK)
      .withTerm(raft.getTerm())
      .withSucceeded(succeeded)
      .withLastLogIndex(lastLogIndex)
      .withLastSnapshotIndex(raft.getSnapshotStore().getCurrentSnapshotIndex())
      .build()));
  return succeeded;
}
 
Example #15
Source File: CandidateRole.java    From atomix with Apache License 2.0 5 votes vote down vote up
@Override
public CompletableFuture<AppendResponse> onAppend(AppendRequest request) {
  raft.checkThread();

  // If the request indicates a term that is greater than the current term then
  // assign that term and leader to the current context and step down as a candidate.
  if (request.term() >= raft.getTerm()) {
    raft.setTerm(request.term());
    raft.transition(RaftServer.Role.FOLLOWER);
  }
  return super.onAppend(request);
}
 
Example #16
Source File: InactiveRole.java    From atomix with Apache License 2.0 5 votes vote down vote up
@Override
public CompletableFuture<AppendResponse> onAppend(AppendRequest request) {
  logRequest(request);
  return Futures.completedFuture(logResponse(AppendResponse.builder()
      .withStatus(Status.ERROR)
      .withError(RaftError.Type.UNAVAILABLE)
      .build()));
}
 
Example #17
Source File: FollowerRole.java    From atomix with Apache License 2.0 5 votes vote down vote up
@Override
public CompletableFuture<AppendResponse> onAppend(AppendRequest request) {
  CompletableFuture<AppendResponse> future = super.onAppend(request);

  // Reset the heartbeat timeout.
  resetHeartbeatTimeout();
  return future;
}
 
Example #18
Source File: RaftServerMessagingProtocol.java    From submarine with Apache License 2.0 4 votes vote down vote up
@Override
public void registerAppendHandler(Function<AppendRequest,
    CompletableFuture<AppendResponse>> handler) {
  registerHandler("append", handler);
}
 
Example #19
Source File: PassiveRole.java    From atomix with Apache License 2.0 4 votes vote down vote up
/**
 * Checks the previous index of the given AppendRequest, returning a boolean indicating whether to continue
 * handling the request.
 */
protected boolean checkPreviousEntry(AppendRequest request, CompletableFuture<AppendResponse> future) {
  RaftLogWriter writer = raft.getLogWriter();
  RaftLogReader reader = raft.getLogReader();

  // If the previous term is set, validate that it matches the local log.
  // We check the previous log term since that indicates whether any entry is present in the leader's
  // log at the previous log index. It's possible that the leader can send a non-zero previous log index
  // with a zero term in the event the leader has compacted its logs and is sending the first entry.
  if (request.prevLogTerm() != 0) {
    // Get the last entry written to the log.
    Indexed<RaftLogEntry> lastEntry = writer.getLastEntry();

    // If the local log is non-empty...
    if (lastEntry != null) {
      // If the previous log index is greater than the last entry index, fail the attempt.
      if (request.prevLogIndex() > lastEntry.index()) {
        log.debug("Rejected {}: Previous index ({}) is greater than the local log's last index ({})", request, request.prevLogIndex(), lastEntry.index());
        return failAppend(lastEntry.index(), future);
      }

      // If the previous log index is less than the last written entry index, look up the entry.
      if (request.prevLogIndex() < lastEntry.index()) {
        // Reset the reader to the previous log index.
        if (reader.getNextIndex() != request.prevLogIndex()) {
          reader.reset(request.prevLogIndex());
        }

        // The previous entry should exist in the log if we've gotten this far.
        if (!reader.hasNext()) {
          log.debug("Rejected {}: Previous entry does not exist in the local log", request);
          return failAppend(lastEntry.index(), future);
        }

        // Read the previous entry and validate that the term matches the request previous log term.
        Indexed<RaftLogEntry> previousEntry = reader.next();
        if (request.prevLogTerm() != previousEntry.entry().term()) {
          log.debug("Rejected {}: Previous entry term ({}) does not match local log's term for the same entry ({})", request, request.prevLogTerm(), previousEntry.entry().term());
          return failAppend(request.prevLogIndex() - 1, future);
        }
      }
      // If the previous log term doesn't equal the last entry term, fail the append, sending the prior entry.
      else if (request.prevLogTerm() != lastEntry.entry().term()) {
        log.debug("Rejected {}: Previous entry term ({}) does not equal the local log's last term ({})", request, request.prevLogTerm(), lastEntry.entry().term());
        return failAppend(request.prevLogIndex() - 1, future);
      }
    } else {
      // If the previous log index is set and the last entry is null, fail the append.
      if (request.prevLogIndex() > 0) {
        log.debug("Rejected {}: Previous index ({}) is greater than the local log's last index (0)", request, request.prevLogIndex());
        return failAppend(0, future);
      }
    }
  }
  return true;
}
 
Example #20
Source File: RaftServerMessagingProtocol.java    From atomix with Apache License 2.0 4 votes vote down vote up
@Override
public CompletableFuture<AppendResponse> append(MemberId memberId, AppendRequest request) {
  return sendAndReceive(memberId, "append", request);
}
 
Example #21
Source File: RaftServerMessagingProtocol.java    From atomix with Apache License 2.0 4 votes vote down vote up
@Override
public void registerAppendHandler(Function<AppendRequest, CompletableFuture<AppendResponse>> handler) {
  registerHandler("append", handler);
}
 
Example #22
Source File: LocalRaftServerProtocol.java    From atomix with Apache License 2.0 4 votes vote down vote up
@Override
public CompletableFuture<AppendResponse> append(MemberId memberId, AppendRequest request) {
  return getServer(memberId).thenCompose(listener -> listener.append(encode(request))).thenApply(this::decode);
}
 
Example #23
Source File: LocalRaftServerProtocol.java    From atomix with Apache License 2.0 4 votes vote down vote up
@Override
public void registerAppendHandler(Function<AppendRequest, CompletableFuture<AppendResponse>> handler) {
  this.appendHandler = handler;
}
 
Example #24
Source File: LeaderAppender.java    From atomix with Apache License 2.0 4 votes vote down vote up
@Override
protected void handleAppendResponse(RaftMemberContext member, AppendRequest request, AppendResponse response, long timestamp) {
  super.handleAppendResponse(member, request, response, timestamp);
  recordHeartbeat(member, timestamp);
}
 
Example #25
Source File: AbstractAppender.java    From atomix with Apache License 2.0 4 votes vote down vote up
/**
 * Updates the match index when a response is received.
 */
protected void updateMatchIndex(RaftMemberContext member, AppendResponse response) {
  // If the replica returned a valid match index then update the existing match index.
  member.setMatchIndex(response.lastLogIndex());
}
 
Example #26
Source File: RaftServerCommunicator.java    From atomix with Apache License 2.0 4 votes vote down vote up
@Override
public void registerAppendHandler(Function<AppendRequest, CompletableFuture<AppendResponse>> handler) {
  clusterCommunicator.subscribe(context.appendSubject, serializer::decode, handler, serializer::encode);
}
 
Example #27
Source File: RaftServerCommunicator.java    From atomix with Apache License 2.0 4 votes vote down vote up
@Override
public CompletableFuture<AppendResponse> append(MemberId memberId, AppendRequest request) {
  return sendAndReceive(context.appendSubject, request, memberId);
}
 
Example #28
Source File: LocalRaftServerProtocol.java    From zeppelin with Apache License 2.0 4 votes vote down vote up
@Override
public void registerAppendHandler(Function<AppendRequest,
    CompletableFuture<AppendResponse>> handler) {
  this.appendHandler = handler;
}
 
Example #29
Source File: LocalRaftServerProtocol.java    From zeppelin with Apache License 2.0 4 votes vote down vote up
@Override
public CompletableFuture<AppendResponse> append(MemberId memberId, AppendRequest request) {
  return getServer(memberId).thenCompose(listener ->
      listener.append(encode(request))).thenApply(this::decode);
}
 
Example #30
Source File: RaftServerMessagingProtocol.java    From zeppelin with Apache License 2.0 4 votes vote down vote up
@Override
public void registerAppendHandler(Function<AppendRequest,
    CompletableFuture<AppendResponse>> handler) {
  registerHandler("append", handler);
}