From 4fb41cb7f701690248cac7c194fb2c820d5b9697 Mon Sep 17 00:00:00 2001 From: evvy Date: Mon, 26 Oct 2015 20:36:20 +0530 Subject: [PATCH] BUG-3381: Capture Snapshot on recovery if journal is not empty Change-Id: Ib1068cb6d4848d151039887b51458399ff421178 Signed-off-by: evvy --- .../controller/cluster/raft/RaftActor.java | 7 ++++ .../cluster/raft/RaftActorTest.java | 36 ++++++++++++++++ ...eplicationAndSnapshotsIntegrationTest.java | 6 +-- .../cluster/datastore/ShardTest.java | 41 +++++++++---------- 4 files changed, 66 insertions(+), 24 deletions(-) diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java index 0154c890b6..a043c69cf7 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java @@ -173,6 +173,13 @@ public abstract class RaftActor extends AbstractUntypedPersistentActor { initializeBehavior(); raftRecovery = null; + + if (context.getReplicatedLog().size() > 0) { + self().tell(new InitiateCaptureSnapshot(), self()); + LOG.info("Snapshot capture initiated after recovery"); + } else { + LOG.info("Snapshot capture NOT initiated after recovery, journal empty"); + } } } diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java index 51d6478fd6..4b43095316 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java @@ -21,6 +21,7 @@ import static org.mockito.Matchers.same; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.timeout; import akka.actor.ActorRef; import akka.actor.PoisonPill; import akka.actor.Props; @@ -105,6 +106,7 @@ public class RaftActorTest extends AbstractActorTest { kit.waitUntilLeader(); } + @Test public void testRaftActorRecoveryWithPersistenceEnabled() throws Exception { TEST_LOG.info("testRaftActorRecoveryWithPersistenceEnabled starting"); @@ -943,6 +945,40 @@ public class RaftActorTest extends AbstractActorTest { }}; } + @Test + public void testRaftActorOnRecoverySnapshot() throws Exception { + TEST_LOG.info("testRaftActorOnRecoverySnapshot"); + + new JavaTestKit(getSystem()) {{ + String persistenceId = factory.generateActorId("follower-"); + + DefaultConfigParamsImpl config = new DefaultConfigParamsImpl(); + + // Set the heartbeat interval high to essentially disable election otherwise the test + // may fail if the actor is switched to Leader + config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS)); + + ImmutableMap peerAddresses = ImmutableMap.builder().put("member1", "address").build(); + + // Create mock ReplicatedLogEntry + ReplicatedLogEntry replLogEntry = new MockRaftActorContext.MockReplicatedLogEntry(1,1, + new MockRaftActorContext.MockPayload("F", 1)); + + InMemoryJournal.addEntry(persistenceId, 1, replLogEntry); + + TestActorRef ref = factory.createTestActor( + MockRaftActor.props(persistenceId, peerAddresses, Optional.of(config))); + + MockRaftActor mockRaftActor = ref.underlyingActor(); + + mockRaftActor.waitForRecoveryComplete(); + + mockRaftActor.waitForInitializeBehaviorComplete(); + + verify(mockRaftActor.snapshotCohortDelegate, timeout(5000)).createSnapshot(any(ActorRef.class)); + }}; + } + @Test public void testSwitchBehavior(){ String persistenceId = factory.generateActorId("leader-"); diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/ReplicationAndSnapshotsIntegrationTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/ReplicationAndSnapshotsIntegrationTest.java index f235d88944..949889a9ce 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/ReplicationAndSnapshotsIntegrationTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/ReplicationAndSnapshotsIntegrationTest.java @@ -186,9 +186,9 @@ public class ReplicationAndSnapshotsIntegrationTest extends AbstractRaftActorInt // Verify the persisted snapshot in the leader. This should reflect the advanced snapshot index as // the last applied log entry (2) even though the leader hasn't yet advanced its cached snapshot index. List persistedSnapshots = InMemorySnapshotStore.getSnapshots(leaderId, Snapshot.class); - assertEquals("Persisted snapshots size", 1, persistedSnapshots.size()); - verifySnapshot("Persisted", persistedSnapshots.get(0), initialTerm, 2, currentTerm, 3); - List unAppliedEntry = persistedSnapshots.get(0).getUnAppliedEntries(); + assertEquals("Persisted snapshots size", 2, persistedSnapshots.size()); + verifySnapshot("Persisted", persistedSnapshots.get(1), initialTerm, 2, currentTerm, 3); + List unAppliedEntry = persistedSnapshots.get(1).getUnAppliedEntries(); assertEquals("Persisted Snapshot getUnAppliedEntries size", 1, unAppliedEntry.size()); verifyReplicatedLogEntry(unAppliedEntry.get(0), currentTerm, 3, payload3); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java index 144f0f5c9f..3a7b458886 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java @@ -2329,7 +2329,6 @@ public class ShardTest extends AbstractShardTest { Props.create(new DelegatingShardCreator(creator)), shardActorName); waitUntilLeader(shard); - writeToStore(shard, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)); final NormalizedNode expectedRoot = readStore(shard, YangInstanceIdentifier.builder().build()); @@ -2337,35 +2336,35 @@ public class ShardTest extends AbstractShardTest { // Trigger creation of a snapshot by ensuring final RaftActorContext raftActorContext = ((TestShard) shard.underlyingActor()).getRaftActorContext(); raftActorContext.getSnapshotManager().capture(mock(ReplicatedLogEntry.class), -1); - - assertEquals("Snapshot saved", true, latch.get().await(5, TimeUnit.SECONDS)); - - assertTrue("Invalid saved snapshot " + savedSnapshot.get(), - savedSnapshot.get() instanceof Snapshot); - - verifySnapshot((Snapshot)savedSnapshot.get(), expectedRoot); - - latch.set(new CountDownLatch(1)); - savedSnapshot.set(null); + awaitAndValidateSnapshot(expectedRoot); raftActorContext.getSnapshotManager().capture(mock(ReplicatedLogEntry.class), -1); + awaitAndValidateSnapshot(expectedRoot); - assertEquals("Snapshot saved", true, latch.get().await(5, TimeUnit.SECONDS)); + shard.tell(PoisonPill.getInstance(), ActorRef.noSender()); + } - assertTrue("Invalid saved snapshot " + savedSnapshot.get(), - savedSnapshot.get() instanceof Snapshot); + private void awaitAndValidateSnapshot(NormalizedNode expectedRoot + ) throws InterruptedException { + System.out.println("Inside awaitAndValidateSnapshot {}" + savedSnapshot.get()); + assertEquals("Snapshot saved", true, latch.get().await(5, TimeUnit.SECONDS)); - verifySnapshot((Snapshot)savedSnapshot.get(), expectedRoot); + assertTrue("Invalid saved snapshot " + savedSnapshot.get(), + savedSnapshot.get() instanceof Snapshot); - shard.tell(PoisonPill.getInstance(), ActorRef.noSender()); - } + verifySnapshot((Snapshot)savedSnapshot.get(), expectedRoot); + + latch.set(new CountDownLatch(1)); + savedSnapshot.set(null); + } - private void verifySnapshot(final Snapshot snapshot, final NormalizedNode expectedRoot) { + private void verifySnapshot(final Snapshot snapshot, final NormalizedNode expectedRoot) { - final NormalizedNode actual = SerializationUtils.deserializeNormalizedNode(snapshot.getState()); - assertEquals("Root node", expectedRoot, actual); + final NormalizedNode actual = SerializationUtils.deserializeNormalizedNode(snapshot.getState()); + assertEquals("Root node", expectedRoot, actual); - }}; + } + }; } /** -- 2.36.6