Search in sources :

Example 6 with RaftLog

use of com.hazelcast.cp.internal.raft.impl.log.RaftLog in project hazelcast by hazelcast.

the class RaftNodeImpl method canReplicateNewEntry.

/**
 * Returns true if a new entry with the operation is currently allowed to
 * be replicated. This method can be invoked only when the local Raft node
 * is the leader.
 * <p>
 * Replication is not allowed, when;
 * <ul>
 * <li>Node is terminating, terminated or stepped down. See {@link RaftNodeStatus}.</li>
 * <li>Raft log contains max allowed uncommitted entry count.
 * See {@link RaftAlgorithmConfig#getUncommittedEntryCountToRejectNewAppends()}.</li>
 * <li>The operation is a {@link RaftGroupCmd} and there's an ongoing membership change in group.</li>
 * <li>The operation is a membership change operation and there's no committed entry in this term yet.
 * See {@link RaftIntegration#getAppendedEntryOnLeaderElection()}.</li>
 * <li>There is an ongoing leadership transfer.</li>
 * </ul>
 */
public boolean canReplicateNewEntry(Object operation) {
    if (isTerminatedOrSteppedDown()) {
        return false;
    }
    RaftLog log = state.log();
    long lastLogIndex = log.lastLogOrSnapshotIndex();
    long commitIndex = state.commitIndex();
    if (lastLogIndex - commitIndex >= maxUncommittedEntryCount) {
        return false;
    }
    if (status == TERMINATING) {
        return false;
    } else if (status == UPDATING_GROUP_MEMBER_LIST) {
        return state.lastGroupMembers().isKnownMember(getLocalMember()) && !(operation instanceof RaftGroupCmd);
    }
    if (operation instanceof UpdateRaftGroupMembersCmd) {
        // the leader must have committed an entry in its term to make a membership change
        // https://groups.google.com/forum/#!msg/raft-dev/t4xj6dJTP6E/d2D9LrWRza8J
        // last committed entry is either in the last snapshot or still in the log
        LogEntry lastCommittedEntry = commitIndex == log.snapshotIndex() ? log.snapshot() : log.getLogEntry(commitIndex);
        assert lastCommittedEntry != null;
        return lastCommittedEntry.term() == state.term();
    }
    return state.leadershipTransferState() == null;
}
Also used : UpdateRaftGroupMembersCmd(com.hazelcast.cp.internal.raft.impl.command.UpdateRaftGroupMembersCmd) RaftGroupCmd(com.hazelcast.cp.internal.raft.command.RaftGroupCmd) DestroyRaftGroupCmd(com.hazelcast.cp.internal.raft.command.DestroyRaftGroupCmd) LogEntry(com.hazelcast.cp.internal.raft.impl.log.LogEntry) RaftLog(com.hazelcast.cp.internal.raft.impl.log.RaftLog)

Example 7 with RaftLog

use of com.hazelcast.cp.internal.raft.impl.log.RaftLog in project hazelcast by hazelcast.

the class RaftNodeImpl method applyLogEntries.

/**
 * Applies committed log entries between {@code lastApplied} and {@code commitIndex}, if there's any available.
 * If new entries are applied, {@link RaftState}'s {@code lastApplied} field is updated.
 *
 * @see RaftState#lastApplied()
 * @see RaftState#commitIndex()
 */
public void applyLogEntries() {
    // Reject logs we've applied already
    long commitIndex = state.commitIndex();
    long lastApplied = state.lastApplied();
    if (commitIndex == lastApplied) {
        return;
    }
    // If commitIndex > lastApplied: increment lastApplied, apply log[lastApplied] to state machine (§5.3)
    assert commitIndex > lastApplied : "commit index: " + commitIndex + " cannot be smaller than last applied: " + lastApplied;
    // Apply all the preceding logs
    RaftLog raftLog = state.log();
    for (long idx = state.lastApplied() + 1; idx <= commitIndex; idx++) {
        LogEntry entry = raftLog.getLogEntry(idx);
        if (entry == null) {
            String msg = "Failed to get log entry at index: " + idx;
            logger.severe(msg);
            throw new AssertionError(msg);
        }
        applyLogEntry(entry);
        // Update the lastApplied index
        state.lastApplied(idx);
    }
    assert status != TERMINATED || commitIndex == raftLog.lastLogOrSnapshotIndex() : "commit index: " + commitIndex + " must be equal to " + raftLog.lastLogOrSnapshotIndex() + " on termination.";
    if (state.role() == LEADER || state.role() == FOLLOWER) {
        takeSnapshotIfCommitIndexAdvanced();
    }
}
Also used : LogEntry(com.hazelcast.cp.internal.raft.impl.log.LogEntry) RaftLog(com.hazelcast.cp.internal.raft.impl.log.RaftLog)

Example 8 with RaftLog

use of com.hazelcast.cp.internal.raft.impl.log.RaftLog in project hazelcast by hazelcast.

the class RaftNodeImpl method tryAdvanceCommitIndex.

public boolean tryAdvanceCommitIndex() {
    // If there exists an N such that N > commitIndex, a majority of matchIndex[i] ≥ N, and log[N].term == currentTerm:
    // set commitIndex = N (§5.3, §5.4)
    long quorumMatchIndex = findQuorumMatchIndex();
    long commitIndex = state.commitIndex();
    RaftLog raftLog = state.log();
    for (; quorumMatchIndex > commitIndex; quorumMatchIndex--) {
        // Only log entries from the leader’s current term are committed by counting replicas; once an entry
        // from the current term has been committed in this way, then all prior entries are committed indirectly
        // because of the Log Matching Property.
        LogEntry entry = raftLog.getLogEntry(quorumMatchIndex);
        if (entry.term() == state.term()) {
            commitEntries(quorumMatchIndex);
            return true;
        } else if (logger.isFineEnabled()) {
            logger.fine("Cannot commit " + entry + " since an entry from the current term: " + state.term() + " is needed.");
        }
    }
    return false;
}
Also used : LogEntry(com.hazelcast.cp.internal.raft.impl.log.LogEntry) RaftLog(com.hazelcast.cp.internal.raft.impl.log.RaftLog)

Example 9 with RaftLog

use of com.hazelcast.cp.internal.raft.impl.log.RaftLog in project hazelcast by hazelcast.

the class RaftStateTest method toLeader_fromCandidate.

@Test
public void toLeader_fromCandidate() {
    state.toCandidate(false);
    int term = state.term();
    RaftLog log = state.log();
    log.appendEntries(new LogEntry(term, 1, null), new LogEntry(term, 2, null), new LogEntry(term, 3, null));
    long lastLogIndex = log.lastLogOrSnapshotIndex();
    state.toLeader();
    assertEquals(RaftRole.LEADER, state.role());
    assertEquals(localMember, state.leader());
    assertNull(state.candidateState());
    LeaderState leaderState = state.leaderState();
    assertNotNull(leaderState);
    for (RaftEndpoint endpoint : state.remoteMembers()) {
        FollowerState followerState = leaderState.getFollowerState(endpoint);
        assertEquals(0, followerState.matchIndex());
        assertEquals(lastLogIndex + 1, followerState.nextIndex());
    }
    long[] matchIndices = leaderState.matchIndices();
    assertEquals(state.remoteMembers().size() + 1, matchIndices.length);
    for (long index : matchIndices) {
        assertEquals(0, index);
    }
}
Also used : TestRaftEndpoint(com.hazelcast.cp.internal.raft.impl.testing.TestRaftEndpoint) RaftEndpoint(com.hazelcast.cp.internal.raft.impl.RaftEndpoint) TestRaftEndpoint(com.hazelcast.cp.internal.raft.impl.testing.TestRaftEndpoint) RaftEndpoint(com.hazelcast.cp.internal.raft.impl.RaftEndpoint) LogEntry(com.hazelcast.cp.internal.raft.impl.log.LogEntry) RaftLog(com.hazelcast.cp.internal.raft.impl.log.RaftLog) ParallelJVMTest(com.hazelcast.test.annotation.ParallelJVMTest) QuickTest(com.hazelcast.test.annotation.QuickTest) Test(org.junit.Test)

Example 10 with RaftLog

use of com.hazelcast.cp.internal.raft.impl.log.RaftLog in project hazelcast by hazelcast.

the class RaftNodeImpl method takeSnapshotIfCommitIndexAdvanced.

/**
 * Takes a snapshot if the advance in {@code commitIndex} is equal to
 * {@link RaftAlgorithmConfig#getCommitIndexAdvanceCountToSnapshot()}.
 * <p>
 * Snapshot is not created if the Raft group is being destroyed.
 */
@SuppressWarnings("checkstyle:npathcomplexity")
private void takeSnapshotIfCommitIndexAdvanced() {
    long commitIndex = state.commitIndex();
    if ((commitIndex - state.log().snapshotIndex()) < commitIndexAdvanceCountToSnapshot) {
        return;
    }
    if (isTerminatedOrSteppedDown()) {
        // If the status is TERMINATED or STEPPED_DOWN, then there will not be any new appends.
        return;
    }
    RaftLog log = state.log();
    Object snapshot = raftIntegration.takeSnapshot(commitIndex);
    if (snapshot instanceof Throwable) {
        Throwable t = (Throwable) snapshot;
        logger.severe("Could not take snapshot at commit index: " + commitIndex, t);
        return;
    }
    int snapshotTerm = log.getLogEntry(commitIndex).term();
    RaftGroupMembers members = state.committedGroupMembers();
    SnapshotEntry snapshotEntry = new SnapshotEntry(snapshotTerm, commitIndex, snapshot, members.index(), members.members());
    long highestLogIndexToTruncate = commitIndex - maxNumberOfLogsToKeepAfterSnapshot;
    LeaderState leaderState = state.leaderState();
    if (leaderState != null) {
        long[] matchIndices = leaderState.matchIndices();
        // Last slot is reserved for leader index and always zero.
        // If there is at least one follower with unknown match index,
        // its log can be close to the leader's log so we are keeping the old log entries.
        boolean allMatchIndicesKnown = Arrays.stream(matchIndices, 0, matchIndices.length - 1).noneMatch(i -> i == 0);
        if (allMatchIndicesKnown) {
            // Otherwise, we will keep the log entries until the minimum match index
            // that is bigger than (commitIndex - maxNumberOfLogsToKeepAfterSnapshot).
            // If there is no such follower (all of the minority followers are far behind),
            // then there is no need to keep the old log entries.
            highestLogIndexToTruncate = Arrays.stream(matchIndices).filter(i -> i < commitIndex).filter(i -> i > commitIndex - maxNumberOfLogsToKeepAfterSnapshot).map(i -> i - 1).sorted().findFirst().orElse(commitIndex);
        }
    }
    int truncatedEntryCount = log.setSnapshot(snapshotEntry, highestLogIndexToTruncate);
    if (logger.isFineEnabled()) {
        logger.fine(snapshotEntry + " is taken, " + truncatedEntryCount + " entries are truncated.");
    }
}
Also used : RaftStateStore(com.hazelcast.cp.internal.raft.impl.persistence.RaftStateStore) AppendSuccessResponse(com.hazelcast.cp.internal.raft.impl.dto.AppendSuccessResponse) QueryTask(com.hazelcast.cp.internal.raft.impl.task.QueryTask) Arrays(java.util.Arrays) StaleAppendRequestException(com.hazelcast.cp.exception.StaleAppendRequestException) Clock(com.hazelcast.internal.util.Clock) MembershipChangeTask(com.hazelcast.cp.internal.raft.impl.task.MembershipChangeTask) PreVoteRequest(com.hazelcast.cp.internal.raft.impl.dto.PreVoteRequest) InitLeadershipTransferTask(com.hazelcast.cp.internal.raft.impl.task.InitLeadershipTransferTask) InstallSnapshot(com.hazelcast.cp.internal.raft.impl.dto.InstallSnapshot) LeaderDemotedException(com.hazelcast.cp.exception.LeaderDemotedException) Arrays.sort(java.util.Arrays.sort) VoteResponse(com.hazelcast.cp.internal.raft.impl.dto.VoteResponse) RaftState.restoreRaftState(com.hazelcast.cp.internal.raft.impl.state.RaftState.restoreRaftState) InternalCompletableFuture(com.hazelcast.spi.impl.InternalCompletableFuture) AppendFailureResponse(com.hazelcast.cp.internal.raft.impl.dto.AppendFailureResponse) Map(java.util.Map) UPDATING_GROUP_MEMBER_LIST(com.hazelcast.cp.internal.raft.impl.RaftNodeStatus.UPDATING_GROUP_MEMBER_LIST) RaftAlgorithmConfig(com.hazelcast.config.cp.RaftAlgorithmConfig) PreVoteRequestHandlerTask(com.hazelcast.cp.internal.raft.impl.handler.PreVoteRequestHandlerTask) SnapshotEntry.isNonInitial(com.hazelcast.cp.internal.raft.impl.log.SnapshotEntry.isNonInitial) VoteRequestHandlerTask(com.hazelcast.cp.internal.raft.impl.handler.VoteRequestHandlerTask) Collection(java.util.Collection) TriggerLeaderElection(com.hazelcast.cp.internal.raft.impl.dto.TriggerLeaderElection) RandomPicker(com.hazelcast.internal.util.RandomPicker) Math.min(java.lang.Math.min) MILLISECONDS(java.util.concurrent.TimeUnit.MILLISECONDS) TERMINATING(com.hazelcast.cp.internal.raft.impl.RaftNodeStatus.TERMINATING) VoteResponseHandlerTask(com.hazelcast.cp.internal.raft.impl.handler.VoteResponseHandlerTask) NopRaftStateStore(com.hazelcast.cp.internal.raft.impl.persistence.NopRaftStateStore) QueryState(com.hazelcast.cp.internal.raft.impl.state.QueryState) CPMember(com.hazelcast.cp.CPMember) RaftGroupCmd(com.hazelcast.cp.internal.raft.command.RaftGroupCmd) Long2ObjectHashMap(com.hazelcast.internal.util.collection.Long2ObjectHashMap) Entry(java.util.Map.Entry) LogEntry(com.hazelcast.cp.internal.raft.impl.log.LogEntry) STEPPED_DOWN(com.hazelcast.cp.internal.raft.impl.RaftNodeStatus.STEPPED_DOWN) SnapshotEntry(com.hazelcast.cp.internal.raft.impl.log.SnapshotEntry) PreVoteResponseHandlerTask(com.hazelcast.cp.internal.raft.impl.handler.PreVoteResponseHandlerTask) MembershipChangeMode(com.hazelcast.cp.internal.raft.MembershipChangeMode) VoteRequest(com.hazelcast.cp.internal.raft.impl.dto.VoteRequest) InstallSnapshotHandlerTask(com.hazelcast.cp.internal.raft.impl.handler.InstallSnapshotHandlerTask) LEADER(com.hazelcast.cp.internal.raft.impl.RaftRole.LEADER) RaftState.newRaftState(com.hazelcast.cp.internal.raft.impl.state.RaftState.newRaftState) Level(java.util.logging.Level) AppendRequest(com.hazelcast.cp.internal.raft.impl.dto.AppendRequest) FollowerState(com.hazelcast.cp.internal.raft.impl.state.FollowerState) TriggerLeaderElectionHandlerTask(com.hazelcast.cp.internal.raft.impl.handler.TriggerLeaderElectionHandlerTask) RestoredRaftState(com.hazelcast.cp.internal.raft.impl.persistence.RestoredRaftState) TERMINATED(com.hazelcast.cp.internal.raft.impl.RaftNodeStatus.TERMINATED) DestroyRaftGroupCmd(com.hazelcast.cp.internal.raft.command.DestroyRaftGroupCmd) BiTuple(com.hazelcast.internal.util.BiTuple) ILogger(com.hazelcast.logging.ILogger) RaftGroupMembers(com.hazelcast.cp.internal.raft.impl.state.RaftGroupMembers) CPGroupId(com.hazelcast.cp.CPGroupId) ACTIVE(com.hazelcast.cp.internal.raft.impl.RaftNodeStatus.ACTIVE) RaftState(com.hazelcast.cp.internal.raft.impl.state.RaftState) LeaderState(com.hazelcast.cp.internal.raft.impl.state.LeaderState) Iterator(java.util.Iterator) RaftLog(com.hazelcast.cp.internal.raft.impl.log.RaftLog) AppendRequestHandlerTask(com.hazelcast.cp.internal.raft.impl.handler.AppendRequestHandlerTask) PreVoteTask(com.hazelcast.cp.internal.raft.impl.task.PreVoteTask) IOException(java.io.IOException) QueryPolicy(com.hazelcast.cp.internal.raft.QueryPolicy) AppendFailureResponseHandlerTask(com.hazelcast.cp.internal.raft.impl.handler.AppendFailureResponseHandlerTask) Preconditions.checkNotNull(com.hazelcast.internal.util.Preconditions.checkNotNull) AppendSuccessResponseHandlerTask(com.hazelcast.cp.internal.raft.impl.handler.AppendSuccessResponseHandlerTask) FOLLOWER(com.hazelcast.cp.internal.raft.impl.RaftRole.FOLLOWER) UpdateRaftGroupMembersCmd(com.hazelcast.cp.internal.raft.impl.command.UpdateRaftGroupMembersCmd) TimeUnit(java.util.concurrent.TimeUnit) PreVoteResponse(com.hazelcast.cp.internal.raft.impl.dto.PreVoteResponse) RaftNodeStatusAwareTask(com.hazelcast.cp.internal.raft.impl.task.RaftNodeStatusAwareTask) PostponedResponse(com.hazelcast.cp.internal.raft.impl.util.PostponedResponse) ReplicateTask(com.hazelcast.cp.internal.raft.impl.task.ReplicateTask) INITIAL(com.hazelcast.cp.internal.raft.impl.RaftNodeStatus.INITIAL) RaftGroupMembers(com.hazelcast.cp.internal.raft.impl.state.RaftGroupMembers) SnapshotEntry(com.hazelcast.cp.internal.raft.impl.log.SnapshotEntry) RaftLog(com.hazelcast.cp.internal.raft.impl.log.RaftLog) LeaderState(com.hazelcast.cp.internal.raft.impl.state.LeaderState)

Aggregations

RaftLog (com.hazelcast.cp.internal.raft.impl.log.RaftLog)16 LogEntry (com.hazelcast.cp.internal.raft.impl.log.LogEntry)11 RaftEndpoint (com.hazelcast.cp.internal.raft.impl.RaftEndpoint)6 RaftState (com.hazelcast.cp.internal.raft.impl.state.RaftState)6 DestroyRaftGroupCmd (com.hazelcast.cp.internal.raft.command.DestroyRaftGroupCmd)3 RaftGroupCmd (com.hazelcast.cp.internal.raft.command.RaftGroupCmd)3 UpdateRaftGroupMembersCmd (com.hazelcast.cp.internal.raft.impl.command.UpdateRaftGroupMembersCmd)3 StaleAppendRequestException (com.hazelcast.cp.exception.StaleAppendRequestException)2 AppendRequest (com.hazelcast.cp.internal.raft.impl.dto.AppendRequest)2 AppendSuccessResponse (com.hazelcast.cp.internal.raft.impl.dto.AppendSuccessResponse)2 InstallSnapshot (com.hazelcast.cp.internal.raft.impl.dto.InstallSnapshot)2 PreVoteRequest (com.hazelcast.cp.internal.raft.impl.dto.PreVoteRequest)2 PreVoteResponse (com.hazelcast.cp.internal.raft.impl.dto.PreVoteResponse)2 VoteResponse (com.hazelcast.cp.internal.raft.impl.dto.VoteResponse)2 FollowerState (com.hazelcast.cp.internal.raft.impl.state.FollowerState)2 LeaderState (com.hazelcast.cp.internal.raft.impl.state.LeaderState)2 QueryState (com.hazelcast.cp.internal.raft.impl.state.QueryState)2 RaftAlgorithmConfig (com.hazelcast.config.cp.RaftAlgorithmConfig)1 CPGroupId (com.hazelcast.cp.CPGroupId)1 CPMember (com.hazelcast.cp.CPMember)1