Checks the leader's term of the given AppendRequest, returning a boolean indicating whether to continue
handling the request.
773197
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;
  }
462441
public static boolean isStepOnRequest(final Request request) {
		String val = request.getParameter(Environment.STEP_VARIABLE);
		return val != null;
	}
756355
protected void appendEntries(AppendRequest request, CompletableFuture<AppendResponse> future) {
    // Compute the last entry index from the previous log index and request entry count.
    final long lastEntryIndex = request.prevLogIndex() + request.entries().size();

    // Ensure the commitIndex is not increased beyond the index of the last entry in the request.
    final long commitIndex = Math.max(raft.getCommitIndex(), Math.min(request.commitIndex(), lastEntryIndex));

    // Track the last log index while entries are appended.
    long lastLogIndex = request.prevLogIndex();

    if (!request.entries().isEmpty()) {
      final RaftLogWriter writer = raft.getLogWriter();
      final RaftLogReader reader = raft.getLogReader();

      // If the previous term is zero, that indicates the previous index represents the beginning of the log.
      // Reset the log to the previous index plus one.
      if (request.prevLogTerm() == 0) {
        log.debug("Reset first index to {}", request.prevLogIndex() + 1);
        writer.reset(request.prevLogIndex() + 1);
      }

      // Iterate through entries and append them.
      for (RaftLogEntry entry : request.entries()) {
        long index = ++lastLogIndex;

        // Get the last entry written to the log by the writer.
        Indexed<RaftLogEntry> lastEntry = writer.getLastEntry();

        if (lastEntry != null) {
          // If the last written entry index is greater than the next append entry index,
          // we need to validate that the entry that's already in the log matches this entry.
          if (lastEntry.index() > index) {
            // Reset the reader to the current entry index.
            if (reader.getNextIndex() != index) {
              reader.reset(index);
            }

            // If the reader does not have any next entry, that indicates an inconsistency between the reader and writer.
            if (!reader.hasNext()) {
              throw new IllegalStateException("Log reader inconsistent with log writer");
            }

            // Read the existing entry from the log.
            Indexed<RaftLogEntry> existingEntry = reader.next();

            // If the existing entry term doesn't match the leader's term for the same entry, truncate
            // the log and append the leader's entry.
            if (existingEntry.entry().term() != entry.term()) {
              writer.truncate(index - 1);
              if (!appendEntry(index, entry, writer, future)) {
                return;
              }
            }
          }
          // If the last written entry is equal to the append entry index, we don't need
          // to read the entry from disk and can just compare the last entry in the writer.
          else if (lastEntry.index() == index) {
            // If the last entry term doesn't match the leader's term for the same entry, truncate
            // the log and append the leader's entry.
            if (lastEntry.entry().term() != entry.term()) {
              writer.truncate(index - 1);
              if (!appendEntry(index, entry, writer, future)) {
                return;
              }
            }
          }
          // Otherwise, this entry is being appended at the end of the log.
          else {
            // If the last entry index isn't the previous index, throw an exception because something crazy happened!
            if (lastEntry.index() != index - 1) {
              throw new IllegalStateException("Log writer inconsistent with next append entry index " + index);
            }

            // Append the entry and log a message.
            if (!appendEntry(index, entry, writer, future)) {
              return;
            }
          }
        }
        // Otherwise, if the last entry is null just append the entry and log a message.
        else {
          if (!appendEntry(index, entry, writer, future)) {
            return;
          }
        }

        // If the last log index meets the commitIndex, break the append loop to avoid appending uncommitted entries.
        if (!role().active() && index == commitIndex) {
          break;
        }
      }
    }

    // Set the first commit index.
    raft.setFirstCommitIndex(request.commitIndex());

    // Update the context commit and global indices.
    long previousCommitIndex = raft.setCommitIndex(commitIndex);
    if (previousCommitIndex < commitIndex) {
      log.trace("Committed entries up to index {}", commitIndex);
      raft.getServiceManager().applyAll(commitIndex);
    }

    // Return a successful append response.
    succeedAppend(lastLogIndex, future);
  }
102313
protected void sendAppendRequest(Connection connection, MemberState member, AppendRequest request) {
    long timestamp = System.nanoTime();

    logger.trace("{} - Sending {} to {}", context.getCluster().member().address(), request, member.getMember().address());
    connection.<AppendRequest, AppendResponse>sendAndReceive(request).whenComplete((response, error) -> {
      context.checkThread();

      // Complete the append to the member.
      if (!request.entries().isEmpty()) {
        member.completeAppend(System.nanoTime() - timestamp);
      } else {
        member.completeAppend();
      }

      if (open) {
        if (error == null) {
          logger.trace("{} - Received {} from {}", context.getCluster().member().address(), response, member.getMember().address());
          handleAppendResponse(member, request, response);
        } else {
          handleAppendResponseFailure(member, request, error);
        }
      }
    });

    updateNextIndex(member, request);
    if (!request.entries().isEmpty() && hasMoreEntries(member)) {
      appendEntries(member);
    }
  }
560596
public static void if_keepAliveRequest_then_resumeReading_else_closeOnComplete(
            final HttpRequest request, final Channel channel, final ChannelFuture channelFuture
    ) {
        // TODO:
        // Add Connection: Close, or Keep-Alive?
        // res.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
        if (HttpUtil.isKeepAlive(request)) {
            channelFuture.addListener(new ChannelFutureListener() {
                public void operationComplete(ChannelFuture future) {
                    resumeReading(channel);
                }
            });
        } else {
            channelFuture.addListener(ChannelFutureListener.CLOSE);
        }
    }
436764
private boolean checkAndRespond(Request request) {
        if (!URIBean.checkUri(request.getUrl())) {
            ServerResponseBean responseBean = new ServerResponseBean();
            responseBean.setMsgId(request.getMsgId());
            responseBean.setHttpContentType(HttpContentType.APPLICATION_JSON);
            responseBean.setResponseBody(UnitResponse.createError(Group.CODE_BAD_REQUEST, null, String.format("URI %s is illegal.", request.getUrl()))
                    .toVoJSONString());
            IServerResponder.singleton.response(responseBean);
            return false;
        }
        return true;
    }
1070421
protected void endRequest() {
        int oldState, newState;
        do {
            oldState = state;
            newState = oldState - 1;
        } while (!stateUpdater.compareAndSet(this, oldState, newState));
        if (newState == CLOSED) {
            handleCompleted();
        }
    }
229318
protected void updateNextIndex(MemberState member, AppendRequest request) {
    // If the match index was set, update the next index to be greater than the match index if necessary.
    if (!request.entries().isEmpty()) {
      member.setNextIndex(request.entries().get(request.entries().size()-1).getIndex()+1);
    }
  }
1146829
protected AppendRequest buildAppendRequest(RaftMemberContext member, long lastIndex) {
    final RaftLogReader reader = member.getLogReader();

    // If the log is empty then send an empty commit.
    // If the next index hasn't yet been set then we send an empty commit first.
    // If the next index is greater than the last index then send an empty commit.
    // If the member failed to respond to recent communication send an empty commit. This
    // helps avoid doing expensive work until we can ascertain the member is back up.
    if (!reader.hasNext()) {
      return buildAppendEmptyRequest(member);
    } else if (member.getFailureCount() > 0) {
      return buildAppendEmptyRequest(member);
    } else {
      return buildAppendEntriesRequest(member, lastIndex);
    }
  }
60011
protected void handleAppendResponseOk(MemberState 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() > context.getTerm()) {
      context.setTerm(response.term()).setLeader(0);
      context.transition(CopycatServer.State.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);

      // If there are more entries to send then attempt to send another commit.
      if (hasMoreEntries(member)) {
        appendEntries(member);
      }
    }
  }
1189687
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() : "");
    }
  }
219874
public void toFollower(int term) {
        role = RaftRole.FOLLOWER;
        leader = null;
        preCandidateState = null;
        leaderState = null;
        candidateState = null;
        this.term = term;
    }
1112918
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;
  }
504756
public static boolean isAllowed(ServletContext servletContext, ServletRequest request) {
		return
			Boolean.parseBoolean(servletContext.getInitParameter(ENABLE_INIT_PARAM))
			&& isAllowedAddr(request.getRemoteAddr())
		;
	}
1228110
boolean isLogUpToDate(long lastIndex, long lastTerm, RaftRequest request) {
    // Read the last entry from the log.
    final Indexed<RaftLogEntry> lastEntry = raft.getLogWriter().getLastEntry();

    // If the log is empty then vote for the candidate.
    if (lastEntry == null) {
      log.debug("Accepted {}: candidate's log is up-to-date", request);
      return true;
    }

    // If the candidate's last log term is lower than the local log's last entry term, reject the request.
    if (lastTerm < lastEntry.entry().term()) {
      log.debug("Rejected {}: candidate's last log entry ({}) is at a lower term than the local log ({})", request, lastTerm, lastEntry.entry().term());
      return false;
    }

    // If the candidate's last term is equal to the local log's last entry term, reject the request if the
    // candidate's last index is less than the local log's last index. If the candidate's last log term is
    // greater than the local log's last term then it's considered up to date, and if both have the same term
    // then the candidate's last index must be greater than the local log's last index.
    if (lastTerm == lastEntry.entry().term() && lastIndex < lastEntry.index()) {
      log.debug("Rejected {}: candidate's last log entry ({}) is at a lower index than the local log ({})", request, lastIndex, lastEntry.index());
      return false;
    }

    // If we made it this far, the candidate's last term is greater than or equal to the local log's last
    // term, and if equal to the local log's last term, the candidate's last index is equal to or greater
    // than the local log's last index.
    log.debug("Accepted {}: candidate's log is up-to-date", request);
    return true;
  }
92025
@Override
	public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
		if (!Constants.PARAM_HISTORY.equals(theRequest.getOperation())) {
			return false;
		}
		if (theRequest.getResourceName() == null) {
			return myResourceOperationType == RestOperationTypeEnum.HISTORY_SYSTEM;
		}
		if (!StringUtils.equals(theRequest.getResourceName(), myResourceName)) {
			return false;
		}

		boolean haveIdParam = theRequest.getId() != null && !theRequest.getId().isEmpty();
		boolean wantIdParam = myIdParamIndex != null;
		if (haveIdParam != wantIdParam) {
			return false;
		}

		if (theRequest.getId() == null) {
			return myResourceOperationType == RestOperationTypeEnum.HISTORY_TYPE;
		} else if (theRequest.getId().hasVersionIdPart()) {
			return false;
		}

		return true;
	}
1006112
@Override
	protected boolean doHandleRequest(final Request request) {
		boolean selected = getRequestValue(request);
		boolean current = getValue();

		boolean changed = current != selected;

		if (changed) {
			setData(selected);
		}

		return changed;
	}