Search in sources :

Example 1 with Snapshot

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();
    }
}
Also used : ApplySnapshot(org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot) Snapshot(org.opendaylight.controller.cluster.raft.persisted.Snapshot) InstallSnapshot(org.opendaylight.controller.cluster.raft.messages.InstallSnapshot) InstallSnapshotReply(org.opendaylight.controller.cluster.raft.messages.InstallSnapshotReply) ApplySnapshot(org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot) IOException(java.io.IOException)

Example 2 with Snapshot

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());
    }
}
Also used : CaptureSnapshot(org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot) Snapshot(org.opendaylight.controller.cluster.raft.persisted.Snapshot) ApplySnapshot(org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot) GetSnapshot(org.opendaylight.controller.cluster.raft.client.messages.GetSnapshot) ActorRef(akka.actor.ActorRef) CaptureSnapshot(org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot) GetSnapshotReply(org.opendaylight.controller.cluster.raft.client.messages.GetSnapshotReply)

Example 3 with Snapshot

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()));
}
Also used : Builder(org.opendaylight.controller.cluster.raft.MockRaftActor.Builder) DefaultConfigParamsImpl(org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl) AtomicReference(java.util.concurrent.atomic.AtomicReference) ByteString(com.google.protobuf.ByteString) AppendEntries(org.opendaylight.controller.cluster.raft.messages.AppendEntries) MockRaftActor(org.opendaylight.controller.cluster.raft.MockRaftActor) ApplySnapshot(org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot) Snapshot(org.opendaylight.controller.cluster.raft.persisted.Snapshot) InstallSnapshot(org.opendaylight.controller.cluster.raft.messages.InstallSnapshot) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ReplicatedLogEntry(org.opendaylight.controller.cluster.raft.ReplicatedLogEntry) RaftActorSnapshotCohort(org.opendaylight.controller.cluster.raft.RaftActorSnapshotCohort) AppendEntriesReply(org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply) DisableElectionsRaftPolicy(org.opendaylight.controller.cluster.raft.policy.DisableElectionsRaftPolicy) UpdateElectionTerm(org.opendaylight.controller.cluster.raft.persisted.UpdateElectionTerm) Test(org.junit.Test)

Example 4 with Snapshot

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());
}
Also used : ApplySnapshot(org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot) Snapshot(org.opendaylight.controller.cluster.raft.persisted.Snapshot) InstallSnapshot(org.opendaylight.controller.cluster.raft.messages.InstallSnapshot) InstallSnapshotReply(org.opendaylight.controller.cluster.raft.messages.InstallSnapshotReply) ByteString(com.google.protobuf.ByteString) ApplySnapshot(org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot) MockRaftActorContext(org.opendaylight.controller.cluster.raft.MockRaftActorContext) InstallSnapshot(org.opendaylight.controller.cluster.raft.messages.InstallSnapshot) Test(org.junit.Test)

Example 5 with Snapshot

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());
}
Also used : SendInstallSnapshot(org.opendaylight.controller.cluster.raft.base.messages.SendInstallSnapshot) HashMap(java.util.HashMap) InstallSnapshotReply(org.opendaylight.controller.cluster.raft.messages.InstallSnapshotReply) ByteString(com.google.protobuf.ByteString) MockRaftActorContext(org.opendaylight.controller.cluster.raft.MockRaftActorContext) DefaultConfigParamsImpl(org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl) ByteString(com.google.protobuf.ByteString) InstallSnapshot(org.opendaylight.controller.cluster.raft.messages.InstallSnapshot) SendInstallSnapshot(org.opendaylight.controller.cluster.raft.base.messages.SendInstallSnapshot) Snapshot(org.opendaylight.controller.cluster.raft.persisted.Snapshot) InstallSnapshot(org.opendaylight.controller.cluster.raft.messages.InstallSnapshot) CaptureSnapshot(org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot) SendInstallSnapshot(org.opendaylight.controller.cluster.raft.base.messages.SendInstallSnapshot) Test(org.junit.Test)

Aggregations

Snapshot (org.opendaylight.controller.cluster.raft.persisted.Snapshot)42 Test (org.junit.Test)28 ApplySnapshot (org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot)23 SimpleReplicatedLogEntry (org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry)21 InstallSnapshot (org.opendaylight.controller.cluster.raft.messages.InstallSnapshot)16 ByteString (com.google.protobuf.ByteString)14 CaptureSnapshot (org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot)14 MockPayload (org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload)12 ApplyState (org.opendaylight.controller.cluster.raft.base.messages.ApplyState)8 DisableElectionsRaftPolicy (org.opendaylight.controller.cluster.raft.policy.DisableElectionsRaftPolicy)8 ActorRef (akka.actor.ActorRef)7 InstallSnapshotReply (org.opendaylight.controller.cluster.raft.messages.InstallSnapshotReply)7 DefaultConfigParamsImpl (org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl)6 MockSnapshotState (org.opendaylight.controller.cluster.raft.MockRaftActor.MockSnapshotState)6 SendInstallSnapshot (org.opendaylight.controller.cluster.raft.base.messages.SendInstallSnapshot)6 GetSnapshot (org.opendaylight.controller.cluster.raft.client.messages.GetSnapshot)6 ApplyJournalEntries (org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries)6 ByteState (org.opendaylight.controller.cluster.raft.persisted.ByteState)6 UpdateElectionTerm (org.opendaylight.controller.cluster.raft.persisted.UpdateElectionTerm)6 TestActorRef (akka.testkit.TestActorRef)5