Search in sources :

Example 1 with RaftLog

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

the class ReplicateTask method run.

@Override
public void run() {
    try {
        if (!verifyRaftNodeStatus()) {
            return;
        }
        RaftState state = raftNode.state();
        if (state.role() != LEADER) {
            resultFuture.completeExceptionally(new NotLeaderException(raftNode.getGroupId(), raftNode.getLocalMember(), state.leader()));
            return;
        }
        if (!raftNode.canReplicateNewEntry(operation)) {
            resultFuture.completeExceptionally(new CannotReplicateException(raftNode.getLocalMember()));
            return;
        }
        if (logger.isFineEnabled()) {
            logger.fine("Replicating: " + operation + " in term: " + state.term());
        }
        RaftLog log = state.log();
        if (!log.checkAvailableCapacity(1)) {
            resultFuture.completeExceptionally(new IllegalStateException("Not enough capacity in RaftLog!"));
            return;
        }
        long newEntryLogIndex = log.lastLogOrSnapshotIndex() + 1;
        raftNode.registerFuture(newEntryLogIndex, resultFuture);
        log.appendEntries(new LogEntry(state.term(), newEntryLogIndex, operation));
        preApplyRaftGroupCmd(newEntryLogIndex, operation);
        raftNode.broadcastAppendRequest();
    } catch (Throwable t) {
        logger.severe(operation + " could not be replicated to leader: " + raftNode.getLocalMember(), t);
        RaftEndpoint leader = raftNode.getLeader();
        UUID leaderUuid = leader != null ? leader.getUuid() : null;
        resultFuture.completeExceptionally(new CPSubsystemException("Internal failure", t, leaderUuid));
    }
}
Also used : NotLeaderException(com.hazelcast.cp.exception.NotLeaderException) RaftState(com.hazelcast.cp.internal.raft.impl.state.RaftState) RaftEndpoint(com.hazelcast.cp.internal.raft.impl.RaftEndpoint) CannotReplicateException(com.hazelcast.cp.exception.CannotReplicateException) UUID(java.util.UUID) CPSubsystemException(com.hazelcast.cp.exception.CPSubsystemException) LogEntry(com.hazelcast.cp.internal.raft.impl.log.LogEntry) RaftLog(com.hazelcast.cp.internal.raft.impl.log.RaftLog)

Example 2 with RaftLog

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

the class VoteRequestHandlerTask method innerRun.

@Override
@SuppressWarnings({ "checkstyle:npathcomplexity", "checkstyle:cyclomaticcomplexity" })
protected // Justification: It is easier to follow the RequestVoteRPC logic in a single method
void innerRun() {
    RaftState state = raftNode.state();
    RaftEndpoint localMember = localMember();
    // Reply false if last AppendEntries call was received less than election timeout ago (leader stickiness)
    // (Raft thesis - Section 4.2.3) This check conflicts with the leadership transfer mechanism,
    // in which a server legitimately starts an election without waiting an election timeout.
    // Those VoteRequest objects are marked with a special flag ("disruptive") to bypass leader stickiness.
    // Also if request comes from the current leader, then stickiness check is skipped.
    // Since current leader may have restarted by recovering its persistent state.
    long leaderElectionTimeoutDeadline = Clock.currentTimeMillis() - raftNode.getLeaderElectionTimeoutInMillis();
    if (!req.isDisruptive() && raftNode.lastAppendEntriesTimestamp() > leaderElectionTimeoutDeadline && !req.candidate().equals(state.leader())) {
        logger.info("Rejecting " + req + " since received append entries recently.");
        raftNode.send(new VoteResponse(localMember, state.term(), false), req.candidate());
        return;
    }
    // Reply false if term < currentTerm (§5.1)
    if (state.term() > req.term()) {
        logger.info("Rejecting " + req + " since current term: " + state.term() + " is bigger");
        raftNode.send(new VoteResponse(localMember, state.term(), false), req.candidate());
        return;
    }
    if (state.term() < req.term()) {
        // If RPC request or response contains term T > currentTerm: set currentTerm = T, convert to follower (§5.1)
        if (state.role() != FOLLOWER) {
            logger.info("Demoting to FOLLOWER after " + req + " since current term: " + state.term() + " is smaller");
        } else {
            logger.info("Moving to new term: " + req.term() + " from current term: " + state.term() + " after " + req);
        }
        raftNode.toFollower(req.term());
    }
    if (state.leader() != null && !req.candidate().equals(state.leader())) {
        logger.warning("Rejecting " + req + " since we have a leader: " + state.leader());
        raftNode.send(new VoteResponse(localMember, req.term(), false), req.candidate());
        return;
    }
    if (state.votedFor() != null) {
        boolean granted = (req.candidate().equals(state.votedFor()));
        if (granted) {
            logger.info("Vote granted for duplicate" + req);
        } else {
            logger.info("Duplicate " + req + ". currently voted-for: " + state.votedFor());
        }
        raftNode.send(new VoteResponse(localMember, req.term(), granted), req.candidate());
        return;
    }
    RaftLog raftLog = state.log();
    if (raftLog.lastLogOrSnapshotTerm() > req.lastLogTerm()) {
        logger.info("Rejecting " + req + " since our last log term: " + raftLog.lastLogOrSnapshotTerm() + " is greater");
        raftNode.send(new VoteResponse(localMember, req.term(), false), req.candidate());
        return;
    }
    if (raftLog.lastLogOrSnapshotTerm() == req.lastLogTerm() && raftLog.lastLogOrSnapshotIndex() > req.lastLogIndex()) {
        logger.info("Rejecting " + req + " since our last log index: " + raftLog.lastLogOrSnapshotIndex() + " is greater");
        raftNode.send(new VoteResponse(localMember, req.term(), false), req.candidate());
        return;
    }
    logger.info("Granted vote for " + req);
    state.persistVote(req.term(), req.candidate());
    raftNode.send(new VoteResponse(localMember, req.term(), true), req.candidate());
}
Also used : VoteResponse(com.hazelcast.cp.internal.raft.impl.dto.VoteResponse) RaftState(com.hazelcast.cp.internal.raft.impl.state.RaftState) RaftEndpoint(com.hazelcast.cp.internal.raft.impl.RaftEndpoint) RaftLog(com.hazelcast.cp.internal.raft.impl.log.RaftLog)

Example 3 with RaftLog

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

the class RaftNodeImpl method applyRestoredRaftGroupCommands.

private void applyRestoredRaftGroupCommands(SnapshotEntry snapshot) {
    // If there is a single Raft group command after the last snapshot,
    // here we cannot know if the that command is committed or not so we
    // just "pre-apply" that command without committing it.
    // If there are multiple Raft group commands, it is definitely known
    // that all the command up to the last command are committed,
    // but the last command may not be committed.
    // This conclusion boils down to the fact that once you append a Raft
    // group command, you cannot append a new one before committing it.
    RaftLog log = state.log();
    LogEntry committedEntry = null;
    LogEntry lastAppliedEntry = null;
    for (long i = snapshot != null ? snapshot.index() + 1 : 1; i <= log.lastLogOrSnapshotIndex(); i++) {
        LogEntry entry = log.getLogEntry(i);
        assert entry != null : "index: " + i;
        if (entry.operation() instanceof RaftGroupCmd) {
            committedEntry = lastAppliedEntry;
            lastAppliedEntry = entry;
        }
    }
    if (committedEntry != null) {
        state.commitIndex(committedEntry.index());
        applyLogEntries();
    }
    if (lastAppliedEntry != null) {
        if (lastAppliedEntry.operation() instanceof UpdateRaftGroupMembersCmd) {
            setStatus(UPDATING_GROUP_MEMBER_LIST);
            Collection<RaftEndpoint> members = ((UpdateRaftGroupMembersCmd) lastAppliedEntry.operation()).getMembers();
            updateGroupMembers(lastAppliedEntry.index(), members);
        } else if (lastAppliedEntry.operation() instanceof DestroyRaftGroupCmd) {
            setStatus(TERMINATING);
        } else {
            throw new IllegalStateException("Invalid group command for restore: " + lastAppliedEntry);
        }
    }
}
Also used : UpdateRaftGroupMembersCmd(com.hazelcast.cp.internal.raft.impl.command.UpdateRaftGroupMembersCmd) DestroyRaftGroupCmd(com.hazelcast.cp.internal.raft.command.DestroyRaftGroupCmd) 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 4 with RaftLog

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

the class RaftNodeImpl method installSnapshot.

/**
 * Restores the snapshot sent by the leader if it's not applied before.
 *
 * @return true if snapshot is restored, false otherwise.
 */
public boolean installSnapshot(SnapshotEntry snapshot) {
    long commitIndex = state.commitIndex();
    if (commitIndex > snapshot.index()) {
        logger.info("Ignored stale " + snapshot + ", commit index at: " + commitIndex);
        return false;
    } else if (commitIndex == snapshot.index()) {
        logger.info("Ignored " + snapshot + " since commit index is same.");
        return true;
    }
    state.commitIndex(snapshot.index());
    RaftLog raftLog = state.log();
    int truncated = raftLog.setSnapshot(snapshot);
    raftLog.flush();
    if (truncated > 0) {
        logger.info(truncated + " entries are truncated to install " + snapshot);
    }
    raftIntegration.restoreSnapshot(snapshot.operation(), snapshot.index());
    // If I am installing a snapshot, it means I am still present in the last member list,
    // but it is possible that the last entry I appended before the snapshot could be a membership change.
    // Because of this, I need to update my status.
    // Nevertheless, I may not be present in the restored member list, which is ok.
    setStatus(ACTIVE);
    state.restoreGroupMembers(snapshot.groupMembersLogIndex(), snapshot.groupMembers());
    printMemberState();
    state.lastApplied(snapshot.index());
    invalidateFuturesUntil(snapshot.index(), new StaleAppendRequestException(state.leader()));
    logger.info(snapshot + " is installed.");
    return true;
}
Also used : StaleAppendRequestException(com.hazelcast.cp.exception.StaleAppendRequestException) RaftLog(com.hazelcast.cp.internal.raft.impl.log.RaftLog)

Example 5 with RaftLog

use of com.hazelcast.cp.internal.raft.impl.log.RaftLog 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)

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