use of com.hazelcast.cp.internal.raft.impl.log.SnapshotEntry in project hazelcast by hazelcast.
the class PersistenceTest method testSnapshotIsPersisted.
@Test
public void testSnapshotIsPersisted() throws ExecutionException, InterruptedException {
final int committedEntryCountToSnapshot = 50;
RaftAlgorithmConfig config = new RaftAlgorithmConfig().setCommitIndexAdvanceCountToSnapshot(committedEntryCountToSnapshot);
group = new LocalRaftGroupBuilder(3, config).setRaftStateStoreFactory(RAFT_STATE_STORE_FACTORY).build();
group.start();
final RaftNodeImpl leader = group.waitUntilLeaderElected();
for (int i = 0; i < committedEntryCountToSnapshot; i++) {
leader.replicate(new ApplyRaftRunnable("val" + i)).get();
}
assertTrueEventually(() -> {
assertEquals(committedEntryCountToSnapshot, getSnapshotEntry(leader).index());
for (RaftNodeImpl node : group.getNodes()) {
RestoredRaftState restoredState = getRestoredState(node);
SnapshotEntry snapshot = restoredState.snapshot();
assertNotNull(snapshot);
assertEquals(committedEntryCountToSnapshot, snapshot.index());
}
});
}
use of com.hazelcast.cp.internal.raft.impl.log.SnapshotEntry 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.");
}
}
use of com.hazelcast.cp.internal.raft.impl.log.SnapshotEntry in project hazelcast by hazelcast.
the class RaftNodeImpl method initRestoredState.
private void initRestoredState() {
SnapshotEntry snapshot = state.log().snapshot();
if (isNonInitial(snapshot)) {
printMemberState();
raftIntegration.restoreSnapshot(snapshot.operation(), snapshot.index());
if (logger.isFineEnabled()) {
logger.info(snapshot + " is restored.");
} else {
logger.info("Snapshot is restored at commitIndex=" + snapshot.index());
}
}
applyRestoredRaftGroupCommands(snapshot);
}
use of com.hazelcast.cp.internal.raft.impl.log.SnapshotEntry in project hazelcast by hazelcast.
the class InstallSnapshotHandlerTask method innerRun.
@Override
protected void innerRun() {
if (logger.isFineEnabled()) {
logger.fine("Received " + req);
}
RaftState state = raftNode.state();
SnapshotEntry snapshot = req.snapshot();
// Reply false if term < currentTerm (§5.1)
if (req.term() < state.term()) {
if (logger.isFineEnabled()) {
logger.warning("Stale snapshot: " + req + " received in current term: " + state.term());
}
raftNode.send(new AppendFailureResponse(localMember(), state.term(), snapshot.index() + 1), req.leader());
return;
}
// Transform into follower if a newer term is seen or another node wins the election of the current term
if (req.term() > state.term() || state.role() != FOLLOWER) {
// If RPC request or response contains term T > currentTerm: set currentTerm = T, convert to follower (§5.1)
logger.info("Demoting to FOLLOWER from current role: " + state.role() + ", term: " + state.term() + " to new term: " + req.term() + " and leader: " + req.leader());
raftNode.toFollower(req.term());
}
if (!req.leader().equals(state.leader())) {
logger.info("Setting leader: " + req.leader());
raftNode.leader(req.leader());
}
raftNode.updateLastAppendEntriesTimestamp();
if (raftNode.installSnapshot(snapshot)) {
raftNode.send(new AppendSuccessResponse(localMember(), req.term(), snapshot.index(), req.queryRound()), req.leader());
}
}
Aggregations