use of org.opendaylight.controller.cluster.raft.persisted.Snapshot in project controller by opendaylight.
the class Follower method handleInstallSnapshot.
private void handleInstallSnapshot(final ActorRef sender, final InstallSnapshot installSnapshot) {
log.debug("{}: handleInstallSnapshot: {}", logName(), installSnapshot);
leaderId = installSnapshot.getLeaderId();
if (snapshotTracker == null) {
snapshotTracker = new SnapshotTracker(log, installSnapshot.getTotalChunks(), installSnapshot.getLeaderId(), context);
}
updateInitialSyncStatus(installSnapshot.getLastIncludedIndex(), installSnapshot.getLeaderId());
try {
final InstallSnapshotReply reply = new InstallSnapshotReply(currentTerm(), context.getId(), installSnapshot.getChunkIndex(), true);
if (snapshotTracker.addChunk(installSnapshot.getChunkIndex(), installSnapshot.getData(), installSnapshot.getLastChunkHashCode())) {
log.info("{}: Snapshot installed from leader: {}", logName(), installSnapshot.getLeaderId());
Snapshot snapshot = Snapshot.create(context.getSnapshotManager().convertSnapshot(snapshotTracker.getSnapshotBytes()), new ArrayList<>(), installSnapshot.getLastIncludedIndex(), installSnapshot.getLastIncludedTerm(), installSnapshot.getLastIncludedIndex(), installSnapshot.getLastIncludedTerm(), context.getTermInformation().getCurrentTerm(), context.getTermInformation().getVotedFor(), installSnapshot.getServerConfig().orNull());
ApplySnapshot.Callback applySnapshotCallback = new ApplySnapshot.Callback() {
@Override
public void onSuccess() {
log.debug("{}: handleInstallSnapshot returning: {}", logName(), reply);
sender.tell(reply, actor());
}
@Override
public void onFailure() {
sender.tell(new InstallSnapshotReply(currentTerm(), context.getId(), -1, false), actor());
}
};
actor().tell(new ApplySnapshot(snapshot, applySnapshotCallback), actor());
closeSnapshotTracker();
} else {
log.debug("{}: handleInstallSnapshot returning: {}", logName(), reply);
sender.tell(reply, actor());
}
} catch (IOException e) {
log.debug("{}: Exception in InstallSnapshot of follower", logName(), e);
sender.tell(new InstallSnapshotReply(currentTerm(), context.getId(), -1, false), actor());
closeSnapshotTracker();
}
}
use of org.opendaylight.controller.cluster.raft.persisted.Snapshot in project controller by opendaylight.
the class RaftActorSnapshotMessageSupport method onGetSnapshot.
private void onGetSnapshot(ActorRef sender) {
log.debug("{}: onGetSnapshot", context.getId());
if (context.getPersistenceProvider().isRecoveryApplicable()) {
CaptureSnapshot captureSnapshot = context.getSnapshotManager().newCaptureSnapshot(context.getReplicatedLog().last(), -1);
ActorRef snapshotReplyActor = context.actorOf(GetSnapshotReplyActor.props(captureSnapshot, ImmutableElectionTerm.copyOf(context.getTermInformation()), sender, snapshotReplyActorTimeout, context.getId(), context.getPeerServerInfo(true)));
cohort.createSnapshot(snapshotReplyActor, Optional.empty());
} else {
Snapshot snapshot = Snapshot.create(EmptyState.INSTANCE, Collections.<ReplicatedLogEntry>emptyList(), -1, -1, -1, -1, context.getTermInformation().getCurrentTerm(), context.getTermInformation().getVotedFor(), context.getPeerServerInfo(true));
sender.tell(new GetSnapshotReply(context.getId(), snapshot), context.getActor());
}
}
use of org.opendaylight.controller.cluster.raft.persisted.Snapshot in project controller by opendaylight.
the class FollowerTest method testCaptureSnapshotOnAppendEntriesWithUnapplied.
@Test
public void testCaptureSnapshotOnAppendEntriesWithUnapplied() {
String id = "testCaptureSnapshotOnAppendEntriesWithUnapplied";
logStart(id);
InMemoryJournal.addEntry(id, 1, new UpdateElectionTerm(1, null));
DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
config.setSnapshotBatchCount(1);
config.setCustomRaftPolicyImplementationClass(DisableElectionsRaftPolicy.class.getName());
final AtomicReference<MockRaftActor> followerRaftActor = new AtomicReference<>();
RaftActorSnapshotCohort snapshotCohort = newRaftActorSnapshotCohort(followerRaftActor);
Builder builder = MockRaftActor.builder().persistent(Optional.of(true)).id(id).peerAddresses(ImmutableMap.of("leader", "")).config(config).snapshotCohort(snapshotCohort);
TestActorRef<MockRaftActor> followerActorRef = actorFactory.createTestActor(builder.props().withDispatcher(Dispatchers.DefaultDispatcherId()), id);
followerRaftActor.set(followerActorRef.underlyingActor());
followerRaftActor.get().waitForInitializeBehaviorComplete();
InMemorySnapshotStore.addSnapshotSavedLatch(id);
InMemoryJournal.addDeleteMessagesCompleteLatch(id);
InMemoryJournal.addWriteMessagesCompleteLatch(id, 1, ApplyJournalEntries.class);
List<ReplicatedLogEntry> entries = Arrays.asList(newReplicatedLogEntry(1, 0, "one"), newReplicatedLogEntry(1, 1, "two"), newReplicatedLogEntry(1, 2, "three"));
AppendEntries appendEntries = new AppendEntries(1, "leader", -1, -1, entries, 0, -1, (short) 0);
followerActorRef.tell(appendEntries, leaderActor);
AppendEntriesReply reply = MessageCollectorActor.expectFirstMatching(leaderActor, AppendEntriesReply.class);
assertEquals("isSuccess", true, reply.isSuccess());
final Snapshot snapshot = InMemorySnapshotStore.waitForSavedSnapshot(id, Snapshot.class);
InMemoryJournal.waitForDeleteMessagesComplete(id);
InMemoryJournal.waitForWriteMessagesComplete(id);
// We expect the ApplyJournalEntries for index 0 to remain in the persisted log b/c it's still queued for
// persistence by the time we initiate capture so the last persisted journal sequence number doesn't include it.
// This is OK - on recovery it will be a no-op since index 0 has already been applied.
List<Object> journalEntries = InMemoryJournal.get(id, Object.class);
assertEquals("Persisted journal entries size: " + journalEntries, 1, journalEntries.size());
assertEquals("Persisted journal entry type", ApplyJournalEntries.class, journalEntries.get(0).getClass());
assertEquals("ApplyJournalEntries index", 0, ((ApplyJournalEntries) journalEntries.get(0)).getToIndex());
assertEquals("Snapshot unapplied size", 2, snapshot.getUnAppliedEntries().size());
assertEquals("Snapshot unapplied entry index", 1, snapshot.getUnAppliedEntries().get(0).getIndex());
assertEquals("Snapshot unapplied entry index", 2, snapshot.getUnAppliedEntries().get(1).getIndex());
assertEquals("Snapshot getLastAppliedTerm", 1, snapshot.getLastAppliedTerm());
assertEquals("Snapshot getLastAppliedIndex", 0, snapshot.getLastAppliedIndex());
assertEquals("Snapshot getLastTerm", 1, snapshot.getLastTerm());
assertEquals("Snapshot getLastIndex", 2, snapshot.getLastIndex());
assertEquals("Snapshot state", ImmutableList.of(entries.get(0).getData()), MockRaftActor.fromState(snapshot.getState()));
}
use of org.opendaylight.controller.cluster.raft.persisted.Snapshot in project controller by opendaylight.
the class FollowerTest method testHandleInstallSnapshot.
/**
* This test verifies that when InstallSnapshot is received by
* the follower its applied correctly.
*/
@Test
public void testHandleInstallSnapshot() {
logStart("testHandleInstallSnapshot");
MockRaftActorContext context = createActorContext();
context.getTermInformation().update(1, "leader");
follower = createBehavior(context);
ByteString bsSnapshot = createSnapshot();
int offset = 0;
int snapshotLength = bsSnapshot.size();
int chunkSize = 50;
int totalChunks = snapshotLength / chunkSize + (snapshotLength % chunkSize > 0 ? 1 : 0);
int lastIncludedIndex = 1;
int chunkIndex = 1;
InstallSnapshot lastInstallSnapshot = null;
for (int i = 0; i < totalChunks; i++) {
byte[] chunkData = getNextChunk(bsSnapshot, offset, chunkSize);
lastInstallSnapshot = new InstallSnapshot(1, "leader", lastIncludedIndex, 1, chunkData, chunkIndex, totalChunks);
follower.handleMessage(leaderActor, lastInstallSnapshot);
offset = offset + 50;
lastIncludedIndex++;
chunkIndex++;
}
ApplySnapshot applySnapshot = MessageCollectorActor.expectFirstMatching(followerActor, ApplySnapshot.class);
Snapshot snapshot = applySnapshot.getSnapshot();
assertNotNull(lastInstallSnapshot);
assertEquals("getLastIndex", lastInstallSnapshot.getLastIncludedIndex(), snapshot.getLastIndex());
assertEquals("getLastIncludedTerm", lastInstallSnapshot.getLastIncludedTerm(), snapshot.getLastAppliedTerm());
assertEquals("getLastAppliedIndex", lastInstallSnapshot.getLastIncludedIndex(), snapshot.getLastAppliedIndex());
assertEquals("getLastTerm", lastInstallSnapshot.getLastIncludedTerm(), snapshot.getLastTerm());
assertEquals("getState type", ByteState.class, snapshot.getState().getClass());
Assert.assertArrayEquals("getState", bsSnapshot.toByteArray(), ((ByteState) snapshot.getState()).getBytes());
assertEquals("getElectionTerm", 1, snapshot.getElectionTerm());
assertEquals("getElectionVotedFor", "leader", snapshot.getElectionVotedFor());
applySnapshot.getCallback().onSuccess();
List<InstallSnapshotReply> replies = MessageCollectorActor.getAllMatching(leaderActor, InstallSnapshotReply.class);
assertEquals("InstallSnapshotReply count", totalChunks, replies.size());
chunkIndex = 1;
for (InstallSnapshotReply reply : replies) {
assertEquals("getChunkIndex", chunkIndex++, reply.getChunkIndex());
assertEquals("getTerm", 1, reply.getTerm());
assertEquals("isSuccess", true, reply.isSuccess());
assertEquals("getFollowerId", context.getId(), reply.getFollowerId());
}
assertNull("Expected null SnapshotTracker", follower.getSnapshotTracker());
}
use of org.opendaylight.controller.cluster.raft.persisted.Snapshot in project controller by opendaylight.
the class LeaderTest method testHandleInstallSnapshotReplyWithInvalidChunkIndex.
@Test
public void testHandleInstallSnapshotReplyWithInvalidChunkIndex() throws Exception {
logStart("testHandleInstallSnapshotReplyWithInvalidChunkIndex");
MockRaftActorContext actorContext = createActorContextWithFollower();
final int commitIndex = 3;
final int snapshotIndex = 2;
final int snapshotTerm = 1;
final int currentTerm = 2;
actorContext.setConfigParams(new DefaultConfigParamsImpl() {
@Override
public int getSnapshotChunkSize() {
return 50;
}
});
actorContext.setCommitIndex(commitIndex);
leader = new Leader(actorContext);
leader.getFollower(FOLLOWER_ID).setMatchIndex(-1);
leader.getFollower(FOLLOWER_ID).setNextIndex(0);
Map<String, String> leadersSnapshot = new HashMap<>();
leadersSnapshot.put("1", "A");
leadersSnapshot.put("2", "B");
leadersSnapshot.put("3", "C");
// set the snapshot variables in replicatedlog
actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
actorContext.getTermInformation().update(currentTerm, leaderActor.path().toString());
ByteString bs = toByteString(leadersSnapshot);
Snapshot snapshot = Snapshot.create(ByteState.of(bs.toByteArray()), Collections.<ReplicatedLogEntry>emptyList(), commitIndex, snapshotTerm, commitIndex, snapshotTerm, -1, null, null);
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
leader.handleMessage(leaderActor, new SendInstallSnapshot(snapshot, ByteSource.wrap(bs.toByteArray())));
InstallSnapshot installSnapshot = MessageCollectorActor.expectFirstMatching(followerActor, InstallSnapshot.class);
assertEquals(1, installSnapshot.getChunkIndex());
assertEquals(3, installSnapshot.getTotalChunks());
followerActor.underlyingActor().clear();
leader.handleMessage(followerActor, new InstallSnapshotReply(actorContext.getTermInformation().getCurrentTerm(), FOLLOWER_ID, -1, false));
Uninterruptibles.sleepUninterruptibly(actorContext.getConfigParams().getHeartBeatInterval().toMillis(), TimeUnit.MILLISECONDS);
leader.handleMessage(leaderActor, SendHeartBeat.INSTANCE);
installSnapshot = MessageCollectorActor.expectFirstMatching(followerActor, InstallSnapshot.class);
assertEquals(1, installSnapshot.getChunkIndex());
assertEquals(3, installSnapshot.getTotalChunks());
}
Aggregations