Search in sources :

Example 6 with LogEntry

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

the class RaftNodeImpl method appendEntryAfterLeaderElection.

private void appendEntryAfterLeaderElection() {
    Object entry = raftIntegration.getAppendedEntryOnLeaderElection();
    if (entry != null) {
        RaftLog log = state.log();
        log.appendEntries(new LogEntry(state.term(), log.lastLogOrSnapshotIndex() + 1, entry));
    }
}
Also used : LogEntry(com.hazelcast.cp.internal.raft.impl.log.LogEntry) RaftLog(com.hazelcast.cp.internal.raft.impl.log.RaftLog)

Example 7 with LogEntry

use of com.hazelcast.cp.internal.raft.impl.log.LogEntry 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 8 with LogEntry

use of com.hazelcast.cp.internal.raft.impl.log.LogEntry 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 9 with LogEntry

use of com.hazelcast.cp.internal.raft.impl.log.LogEntry 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 10 with LogEntry

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

the class PersistenceTest method testUncommittedEntriesArePersisted.

@Test
public void testUncommittedEntriesArePersisted() {
    group = new LocalRaftGroupBuilder(3).setRaftStateStoreFactory(RAFT_STATE_STORE_FACTORY).build();
    group.start();
    final RaftNodeImpl leader = group.waitUntilLeaderElected();
    RaftNodeImpl[] followers = group.getNodesExcept(leader.getLocalMember());
    final RaftNodeImpl responsiveFollower = followers[0];
    for (int i = 1; i < followers.length; i++) {
        group.dropMessagesToMember(leader.getLocalMember(), followers[i].getLocalMember(), AppendRequest.class);
    }
    final int count = 10;
    for (int i = 0; i < count; i++) {
        leader.replicate(new ApplyRaftRunnable("val" + i));
    }
    assertTrueEventually(() -> {
        for (RaftNodeImpl node : Arrays.asList(leader, responsiveFollower)) {
            RestoredRaftState restoredState = getRestoredState(node);
            LogEntry[] entries = restoredState.entries();
            assertEquals(count, entries.length);
            for (int i = 0; i < count; i++) {
                LogEntry entry = entries[i];
                assertEquals(i + 1, entry.index());
                assertEquals("val" + i, ((ApplyRaftRunnable) entry.operation()).getVal());
            }
        }
    });
}
Also used : RestoredRaftState(com.hazelcast.cp.internal.raft.impl.persistence.RestoredRaftState) ApplyRaftRunnable(com.hazelcast.cp.internal.raft.impl.dataservice.ApplyRaftRunnable) LocalRaftGroupBuilder(com.hazelcast.cp.internal.raft.impl.testing.LocalRaftGroup.LocalRaftGroupBuilder) LogEntry(com.hazelcast.cp.internal.raft.impl.log.LogEntry) ParallelJVMTest(com.hazelcast.test.annotation.ParallelJVMTest) QuickTest(com.hazelcast.test.annotation.QuickTest) Test(org.junit.Test)

Aggregations

LogEntry (com.hazelcast.cp.internal.raft.impl.log.LogEntry)20 RaftLog (com.hazelcast.cp.internal.raft.impl.log.RaftLog)10 ParallelJVMTest (com.hazelcast.test.annotation.ParallelJVMTest)8 QuickTest (com.hazelcast.test.annotation.QuickTest)8 Test (org.junit.Test)8 ApplyRaftRunnable (com.hazelcast.cp.internal.raft.impl.dataservice.ApplyRaftRunnable)4 RaftState (com.hazelcast.cp.internal.raft.impl.state.RaftState)4 List (java.util.List)4 HazelcastInstance (com.hazelcast.core.HazelcastInstance)3 CPGroupId (com.hazelcast.cp.CPGroupId)3 ResourceRegistry (com.hazelcast.cp.internal.datastructures.spi.blocking.ResourceRegistry)3 RaftEndpoint (com.hazelcast.cp.internal.raft.impl.RaftEndpoint)3 RaftNodeImpl (com.hazelcast.cp.internal.raft.impl.RaftNodeImpl)3 UpdateRaftGroupMembersCmd (com.hazelcast.cp.internal.raft.impl.command.UpdateRaftGroupMembersCmd)3 RestoredRaftState (com.hazelcast.cp.internal.raft.impl.persistence.RestoredRaftState)3 LocalRaftGroupBuilder (com.hazelcast.cp.internal.raft.impl.testing.LocalRaftGroup.LocalRaftGroupBuilder)3 DestroyRaftGroupCmd (com.hazelcast.cp.internal.raft.command.DestroyRaftGroupCmd)2 RaftGroupCmd (com.hazelcast.cp.internal.raft.command.RaftGroupCmd)2 AppendRequest (com.hazelcast.cp.internal.raft.impl.dto.AppendRequest)2 AppendSuccessResponse (com.hazelcast.cp.internal.raft.impl.dto.AppendSuccessResponse)2