use of org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot in project controller by opendaylight.
the class RaftActorSnapshotMessageSupportTest method testOnApplySnapshot.
@Test
public void testOnApplySnapshot() {
long lastAppliedDuringSnapshotCapture = 1;
long lastIndexDuringSnapshotCapture = 2;
byte[] snapshotBytes = { 1, 2, 3, 4, 5 };
Snapshot snapshot = Snapshot.create(ByteState.of(snapshotBytes), Collections.<ReplicatedLogEntry>emptyList(), lastIndexDuringSnapshotCapture, 1, lastAppliedDuringSnapshotCapture, 1, -1, null, null);
ApplySnapshot applySnapshot = new ApplySnapshot(snapshot);
sendMessageToSupport(applySnapshot);
verify(mockSnapshotManager).apply(applySnapshot);
}
use of org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot in project controller by opendaylight.
the class RaftActorServerConfigurationSupportTest method testAddServerWithExistingFollower.
@Test
public void testAddServerWithExistingFollower() throws Exception {
LOG.info("testAddServerWithExistingFollower starting");
setupNewFollower();
RaftActorContextImpl followerActorContext = newFollowerContext(FOLLOWER_ID, followerActor);
followerActorContext.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
followerActorContext.setCommitIndex(2);
followerActorContext.setLastApplied(2);
Follower follower = new Follower(followerActorContext);
followerActor.underlyingActor().setBehavior(follower);
followerActorContext.setCurrentBehavior(follower);
TestActorRef<MockLeaderRaftActor> leaderActor = actorFactory.createTestActor(MockLeaderRaftActor.props(ImmutableMap.of(FOLLOWER_ID, followerActor.path().toString()), followerActorContext).withDispatcher(Dispatchers.DefaultDispatcherId()), actorFactory.generateActorId(LEADER_ID));
// Expect initial heartbeat from the leader.
expectFirstMatching(followerActor, AppendEntries.class);
clearMessages(followerActor);
MockLeaderRaftActor leaderRaftActor = leaderActor.underlyingActor();
final ActorRef leaderCollectorActor = newLeaderCollectorActor(leaderRaftActor);
leaderActor.tell(new AddServer(NEW_SERVER_ID, newFollowerRaftActor.path().toString(), true), testKit.getRef());
// Leader should install snapshot - capture and verify ApplySnapshot contents
ApplySnapshot applySnapshot = expectFirstMatching(newFollowerCollectorActor, ApplySnapshot.class);
List<Object> snapshotState = MockRaftActor.fromState(applySnapshot.getSnapshot().getState());
assertEquals("Snapshot state", snapshotState, leaderRaftActor.getState());
AddServerReply addServerReply = testKit.expectMsgClass(testKit.duration("5 seconds"), AddServerReply.class);
assertEquals("getStatus", ServerChangeStatus.OK, addServerReply.getStatus());
assertEquals("getLeaderHint", LEADER_ID, addServerReply.getLeaderHint().get());
// Verify ServerConfigurationPayload entry in leader's log
expectFirstMatching(leaderCollectorActor, ApplyState.class);
RaftActorContext leaderActorContext = leaderRaftActor.getRaftActorContext();
assertEquals("Leader journal last index", 3, leaderActorContext.getReplicatedLog().lastIndex());
assertEquals("Leader commit index", 3, leaderActorContext.getCommitIndex());
assertEquals("Leader last applied index", 3, leaderActorContext.getLastApplied());
verifyServerConfigurationPayloadEntry(leaderActorContext.getReplicatedLog(), votingServer(LEADER_ID), votingServer(FOLLOWER_ID), votingServer(NEW_SERVER_ID));
// Verify ServerConfigurationPayload entry in both followers
expectFirstMatching(followerActor, ApplyState.class);
assertEquals("Follower journal last index", 3, followerActorContext.getReplicatedLog().lastIndex());
verifyServerConfigurationPayloadEntry(followerActorContext.getReplicatedLog(), votingServer(LEADER_ID), votingServer(FOLLOWER_ID), votingServer(NEW_SERVER_ID));
expectFirstMatching(newFollowerCollectorActor, ApplyState.class);
assertEquals("New follower journal last index", 3, newFollowerActorContext.getReplicatedLog().lastIndex());
verifyServerConfigurationPayloadEntry(newFollowerActorContext.getReplicatedLog(), votingServer(LEADER_ID), votingServer(FOLLOWER_ID), votingServer(NEW_SERVER_ID));
// Verify new server config was applied in both followers
assertEquals("Follower peers", Sets.newHashSet(LEADER_ID, NEW_SERVER_ID), followerActorContext.getPeerIds());
assertEquals("New follower peers", Sets.newHashSet(LEADER_ID, FOLLOWER_ID), newFollowerActorContext.getPeerIds());
assertEquals("Follower commit index", 3, followerActorContext.getCommitIndex());
assertEquals("Follower last applied index", 3, followerActorContext.getLastApplied());
assertEquals("New follower commit index", 3, newFollowerActorContext.getCommitIndex());
assertEquals("New follower last applied index", 3, newFollowerActorContext.getLastApplied());
assertEquals("Leader persisted ReplicatedLogImplEntry entries", 0, InMemoryJournal.get(LEADER_ID, SimpleReplicatedLogEntry.class).size());
assertEquals("Leader persisted ServerConfigurationPayload entries", 1, InMemoryJournal.get(LEADER_ID, ServerConfigurationPayload.class).size());
assertEquals("New follower persisted ReplicatedLogImplEntry entries", 0, InMemoryJournal.get(NEW_SERVER_ID, SimpleReplicatedLogEntry.class).size());
assertEquals("New follower persisted ServerConfigurationPayload entries", 1, InMemoryJournal.get(NEW_SERVER_ID, ServerConfigurationPayload.class).size());
LOG.info("testAddServerWithExistingFollower ending");
}
use of org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot in project controller by opendaylight.
the class RaftActorTest method testRestoreFromSnapshotWithRecoveredData.
@Test
public void testRestoreFromSnapshotWithRecoveredData() throws Exception {
TEST_LOG.info("testRestoreFromSnapshotWithRecoveredData starting");
String persistenceId = factory.generateActorId("test-actor-");
DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
config.setCustomRaftPolicyImplementationClass(DisableElectionsRaftPolicy.class.getName());
List<MockPayload> state = Arrays.asList(new MockRaftActorContext.MockPayload("A"));
Snapshot snapshot = Snapshot.create(ByteState.of(fromObject(state).toByteArray()), Arrays.<ReplicatedLogEntry>asList(), 5, 2, 5, 2, 2, "member-1", null);
InMemoryJournal.addEntry(persistenceId, 1, new SimpleReplicatedLogEntry(0, 1, new MockRaftActorContext.MockPayload("B")));
TestActorRef<MockRaftActor> raftActorRef = factory.createTestActor(MockRaftActor.builder().id(persistenceId).config(config).restoreFromSnapshot(snapshot).props().withDispatcher(Dispatchers.DefaultDispatcherId()), persistenceId);
MockRaftActor mockRaftActor = raftActorRef.underlyingActor();
mockRaftActor.waitForRecoveryComplete();
Uninterruptibles.sleepUninterruptibly(500, TimeUnit.MILLISECONDS);
verify(mockRaftActor.snapshotCohortDelegate, never()).applySnapshot(any(Snapshot.State.class));
RaftActorContext context = mockRaftActor.getRaftActorContext();
assertEquals("Journal log size", 1, context.getReplicatedLog().size());
assertEquals("Last index", 0, context.getReplicatedLog().lastIndex());
assertEquals("Last applied", -1, context.getLastApplied());
assertEquals("Commit index", -1, context.getCommitIndex());
assertEquals("Current term", 0, context.getTermInformation().getCurrentTerm());
assertEquals("Voted for", null, context.getTermInformation().getVotedFor());
TEST_LOG.info("testRestoreFromSnapshotWithRecoveredData ending");
}
use of org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot in project controller by opendaylight.
the class ReplicationAndSnapshotsWithLaggingFollowerIntegrationTest method verifyInstallSnapshotToLaggingFollower.
/**
* Resume the lagging follower 2 and verify it receives an install snapshot from the leader.
*/
private void verifyInstallSnapshotToLaggingFollower(long lastAppliedIndex, @Nullable ServerConfigurationPayload expServerConfig) throws Exception {
testLog.info("verifyInstallSnapshotToLaggingFollower starting");
MessageCollectorActor.clearMessages(leaderCollectorActor);
// Now stop dropping AppendEntries in follower 2.
follower2Actor.underlyingActor().stopDropMessages(AppendEntries.class);
MessageCollectorActor.expectFirstMatching(leaderCollectorActor, SaveSnapshotSuccess.class);
// Verify the leader's persisted snapshot. The previous snapshot (currently) won't be deleted from
// the snapshot store because the second snapshot was initiated by the follower install snapshot and
// not because the batch count was reached so the persisted journal sequence number wasn't advanced
// far enough to cause the previous snapshot to be deleted. This is because
// RaftActor#trimPersistentData subtracts the snapshotBatchCount from the snapshot's sequence number.
// This is OK - the next snapshot should delete it. In production, even if the system restarted
// before another snapshot, they would both get applied which wouldn't hurt anything.
List<Snapshot> persistedSnapshots = InMemorySnapshotStore.getSnapshots(leaderId, Snapshot.class);
Assert.assertTrue("Expected at least 1 persisted snapshots", persistedSnapshots.size() > 0);
Snapshot persistedSnapshot = persistedSnapshots.get(persistedSnapshots.size() - 1);
verifySnapshot("Persisted", persistedSnapshot, currentTerm, lastAppliedIndex, currentTerm, lastAppliedIndex);
List<ReplicatedLogEntry> unAppliedEntry = persistedSnapshot.getUnAppliedEntries();
assertEquals("Persisted Snapshot getUnAppliedEntries size", 0, unAppliedEntry.size());
int snapshotSize = SerializationUtils.serialize(persistedSnapshot.getState()).length;
final int expTotalChunks = snapshotSize / SNAPSHOT_CHUNK_SIZE + (snapshotSize % SNAPSHOT_CHUNK_SIZE > 0 ? 1 : 0);
InstallSnapshot installSnapshot = MessageCollectorActor.expectFirstMatching(follower2CollectorActor, InstallSnapshot.class);
assertEquals("InstallSnapshot getTerm", currentTerm, installSnapshot.getTerm());
assertEquals("InstallSnapshot getLeaderId", leaderId, installSnapshot.getLeaderId());
assertEquals("InstallSnapshot getChunkIndex", 1, installSnapshot.getChunkIndex());
assertEquals("InstallSnapshot getTotalChunks", expTotalChunks, installSnapshot.getTotalChunks());
assertEquals("InstallSnapshot getLastIncludedTerm", currentTerm, installSnapshot.getLastIncludedTerm());
assertEquals("InstallSnapshot getLastIncludedIndex", lastAppliedIndex, installSnapshot.getLastIncludedIndex());
// assertArrayEquals("InstallSnapshot getData", snapshot, installSnapshot.getData().toByteArray());
List<InstallSnapshotReply> installSnapshotReplies = MessageCollectorActor.expectMatching(leaderCollectorActor, InstallSnapshotReply.class, expTotalChunks);
int index = 1;
for (InstallSnapshotReply installSnapshotReply : installSnapshotReplies) {
assertEquals("InstallSnapshotReply getTerm", currentTerm, installSnapshotReply.getTerm());
assertEquals("InstallSnapshotReply getChunkIndex", index++, installSnapshotReply.getChunkIndex());
assertEquals("InstallSnapshotReply getFollowerId", follower2Id, installSnapshotReply.getFollowerId());
assertEquals("InstallSnapshotReply isSuccess", true, installSnapshotReply.isSuccess());
}
// Verify follower 2 applies the snapshot.
ApplySnapshot applySnapshot = MessageCollectorActor.expectFirstMatching(follower2CollectorActor, ApplySnapshot.class);
verifySnapshot("Follower 2", applySnapshot.getSnapshot(), currentTerm, lastAppliedIndex, currentTerm, lastAppliedIndex);
assertEquals("Persisted Snapshot getUnAppliedEntries size", 0, applySnapshot.getSnapshot().getUnAppliedEntries().size());
// Wait for the snapshot to complete.
MessageCollectorActor.expectFirstMatching(leaderCollectorActor, SaveSnapshotSuccess.class);
// Ensure there's at least 1 more heartbeat.
MessageCollectorActor.clearMessages(leaderCollectorActor);
MessageCollectorActor.expectFirstMatching(leaderCollectorActor, AppendEntriesReply.class);
// The leader should now have performed fake snapshots to advance the snapshot index and to trim
// the log. In addition replicatedToAllIndex should've advanced.
verifyLeadersTrimmedLog(lastAppliedIndex);
if (expServerConfig != null) {
Set<ServerInfo> expServerInfo = new HashSet<>(expServerConfig.getServerConfig());
assertEquals("Leader snapshot server config", expServerInfo, new HashSet<>(persistedSnapshot.getServerConfiguration().getServerConfig()));
assertEquals("Follower 2 snapshot server config", expServerInfo, new HashSet<>(applySnapshot.getSnapshot().getServerConfiguration().getServerConfig()));
ServerConfigurationPayload follower2ServerConfig = follower2Context.getPeerServerInfo(true);
assertNotNull("Follower 2 server config is null", follower2ServerConfig);
assertEquals("Follower 2 server config", expServerInfo, new HashSet<>(follower2ServerConfig.getServerConfig()));
}
MessageCollectorActor.clearMessages(leaderCollectorActor);
MessageCollectorActor.clearMessages(follower1CollectorActor);
MessageCollectorActor.clearMessages(follower2CollectorActor);
testLog.info("verifyInstallSnapshotToLaggingFollower complete");
}
use of org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot in project controller by opendaylight.
the class RaftActorRecoverySupport method possiblyRestoreFromSnapshot.
@SuppressWarnings("checkstyle:IllegalCatch")
private void possiblyRestoreFromSnapshot() {
Snapshot restoreFromSnapshot = cohort.getRestoreFromSnapshot();
if (restoreFromSnapshot == null) {
return;
}
if (anyDataRecovered) {
log.warn("{}: The provided restore snapshot was not applied because the persistence store is not empty", context.getId());
return;
}
log.debug("{}: Restore snapshot: {}", context.getId(), restoreFromSnapshot);
context.getSnapshotManager().apply(new ApplySnapshot(restoreFromSnapshot));
}
Aggregations