use of org.opendaylight.controller.cluster.raft.persisted.Snapshot in project controller by opendaylight.
the class RaftActorRecoverySupport method onRecoveryCompletedMessage.
private void onRecoveryCompletedMessage(PersistentDataProvider persistentProvider) {
if (currentRecoveryBatchCount > 0) {
endCurrentLogRecoveryBatch();
}
String recoveryTime = "";
if (recoveryTimer != null) {
recoveryTimer.stop();
recoveryTime = " in " + recoveryTimer.toString();
recoveryTimer = null;
}
log.info("Recovery completed" + recoveryTime + " - Switching actor to Follower - " + "Persistence Id = " + context.getId() + " Last index in log = {}, snapshotIndex = {}, snapshotTerm = {}, " + "journal-size = {}", replicatedLog().lastIndex(), replicatedLog().getSnapshotIndex(), replicatedLog().getSnapshotTerm(), replicatedLog().size());
if (dataRecoveredWithPersistenceDisabled || hasMigratedDataRecovered && !context.getPersistenceProvider().isRecoveryApplicable()) {
if (hasMigratedDataRecovered) {
log.info("{}: Saving snapshot after recovery due to migrated messages", context.getId());
} else {
log.info("{}: Saving snapshot after recovery due to data persistence disabled", context.getId());
}
// Either data persistence is disabled and we recovered some data entries (ie we must have just
// transitioned to disabled or a persistence backup was restored) or we recovered migrated
// messages. Either way, we persist a snapshot and delete all the messages from the akka journal
// to clean out unwanted messages.
Snapshot snapshot = Snapshot.create(EmptyState.INSTANCE, Collections.<ReplicatedLogEntry>emptyList(), -1, -1, -1, -1, context.getTermInformation().getCurrentTerm(), context.getTermInformation().getVotedFor(), context.getPeerServerInfo(true));
persistentProvider.saveSnapshot(snapshot);
persistentProvider.deleteMessages(persistentProvider.getLastSequenceNumber());
} else if (hasMigratedDataRecovered) {
log.info("{}: Snapshot capture initiated after recovery due to migrated messages", context.getId());
context.getSnapshotManager().capture(replicatedLog().last(), -1);
} else {
possiblyRestoreFromSnapshot();
}
}
use of org.opendaylight.controller.cluster.raft.persisted.Snapshot in project controller by opendaylight.
the class RaftActorRecoverySupport method onRecoveredSnapshot.
private void onRecoveredSnapshot(SnapshotOffer offer) {
log.debug("{}: SnapshotOffer called.", context.getId());
initRecoveryTimer();
Snapshot snapshot = (Snapshot) offer.snapshot();
for (ReplicatedLogEntry entry : snapshot.getUnAppliedEntries()) {
if (isMigratedPayload(entry)) {
hasMigratedDataRecovered = true;
}
}
if (!context.getPersistenceProvider().isRecoveryApplicable()) {
// We may have just transitioned to disabled and have a snapshot containing state data and/or log
// entries - we don't want to preserve these, only the server config and election term info.
snapshot = Snapshot.create(EmptyState.INSTANCE, Collections.emptyList(), -1, -1, -1, -1, snapshot.getElectionTerm(), snapshot.getElectionVotedFor(), snapshot.getServerConfiguration());
}
// Create a replicated log with the snapshot information
// The replicated log can be used later on to retrieve this snapshot
// when we need to install it on a peer
context.setReplicatedLog(ReplicatedLogImpl.newInstance(snapshot, context));
context.setLastApplied(snapshot.getLastAppliedIndex());
context.setCommitIndex(snapshot.getLastAppliedIndex());
context.getTermInformation().update(snapshot.getElectionTerm(), snapshot.getElectionVotedFor());
Stopwatch timer = Stopwatch.createStarted();
// Apply the snapshot to the actors state
if (!(snapshot.getState() instanceof EmptyState)) {
cohort.applyRecoverySnapshot(snapshot.getState());
}
if (snapshot.getServerConfiguration() != null) {
context.updatePeerIds(snapshot.getServerConfiguration());
}
timer.stop();
log.info("Recovery snapshot applied for {} in {}: snapshotIndex={}, snapshotTerm={}, journal-size={}", context.getId(), timer.toString(), replicatedLog().getSnapshotIndex(), replicatedLog().getSnapshotTerm(), replicatedLog().size());
}
use of org.opendaylight.controller.cluster.raft.persisted.Snapshot in project controller by opendaylight.
the class GetSnapshotReplyActor method onReceive.
@Override
public void onReceive(final Object message) {
if (message instanceof CaptureSnapshotReply) {
Snapshot snapshot = Snapshot.create(((CaptureSnapshotReply) message).getSnapshotState(), params.captureSnapshot.getUnAppliedEntries(), params.captureSnapshot.getLastIndex(), params.captureSnapshot.getLastTerm(), params.captureSnapshot.getLastAppliedIndex(), params.captureSnapshot.getLastAppliedTerm(), params.electionTerm.getCurrentTerm(), params.electionTerm.getVotedFor(), params.peerInformation);
LOG.debug("{}: Received CaptureSnapshotReply, sending {}", params.id, snapshot);
params.replyToActor.tell(new GetSnapshotReply(params.id, snapshot), getSelf());
getSelf().tell(PoisonPill.getInstance(), getSelf());
} else if (message instanceof ReceiveTimeout) {
LOG.warn("{}: Got ReceiveTimeout for inactivity - did not receive CaptureSnapshotReply within {} ms", params.id, params.receiveTimeout.toMillis());
params.replyToActor.tell(new akka.actor.Status.Failure(new TimeoutException(String.format("Timed out after %d ms while waiting for CaptureSnapshotReply", params.receiveTimeout.toMillis()))), getSelf());
getSelf().tell(PoisonPill.getInstance(), getSelf());
}
}
use of org.opendaylight.controller.cluster.raft.persisted.Snapshot in project controller by opendaylight.
the class ShardTest method testCreateSnapshot.
private void testCreateSnapshot(final boolean persistent, final String shardActorName) throws Exception {
final AtomicReference<CountDownLatch> latch = new AtomicReference<>(new CountDownLatch(1));
final AtomicReference<Object> savedSnapshot = new AtomicReference<>();
class TestPersistentDataProvider extends DelegatingPersistentDataProvider {
TestPersistentDataProvider(final DataPersistenceProvider delegate) {
super(delegate);
}
@Override
public void saveSnapshot(final Object obj) {
savedSnapshot.set(obj);
super.saveSnapshot(obj);
}
}
dataStoreContextBuilder.persistent(persistent);
class TestShard extends Shard {
protected TestShard(final AbstractBuilder<?, ?> builder) {
super(builder);
setPersistence(new TestPersistentDataProvider(super.persistence()));
}
@Override
public void handleCommand(final Object message) {
super.handleCommand(message);
// XXX: commit_snapshot equality check references RaftActorSnapshotMessageSupport.COMMIT_SNAPSHOT
if (message instanceof SaveSnapshotSuccess || "commit_snapshot".equals(message.toString())) {
latch.get().countDown();
}
}
@Override
public RaftActorContext getRaftActorContext() {
return super.getRaftActorContext();
}
}
new ShardTestKit(getSystem()) {
{
final Creator<Shard> creator = () -> new TestShard(newShardBuilder());
final TestActorRef<Shard> shard = actorFactory.createTestActor(Props.create(new DelegatingShardCreator(creator)).withDispatcher(Dispatchers.DefaultDispatcherId()), shardActorName);
waitUntilLeader(shard);
writeToStore(shard, TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
final NormalizedNode<?, ?> expectedRoot = readStore(shard, YangInstanceIdentifier.EMPTY);
// Trigger creation of a snapshot by ensuring
final RaftActorContext raftActorContext = ((TestShard) shard.underlyingActor()).getRaftActorContext();
raftActorContext.getSnapshotManager().capture(mock(ReplicatedLogEntry.class), -1);
awaitAndValidateSnapshot(expectedRoot);
raftActorContext.getSnapshotManager().capture(mock(ReplicatedLogEntry.class), -1);
awaitAndValidateSnapshot(expectedRoot);
}
private void awaitAndValidateSnapshot(final NormalizedNode<?, ?> expectedRoot) throws InterruptedException, IOException {
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);
}
private void verifySnapshot(final Snapshot snapshot, final NormalizedNode<?, ?> expectedRoot) throws IOException {
final NormalizedNode<?, ?> actual = ((ShardSnapshotState) snapshot.getState()).getSnapshot().getRootNode().get();
assertEquals("Root node", expectedRoot, actual);
}
};
}
use of org.opendaylight.controller.cluster.raft.persisted.Snapshot in project controller by opendaylight.
the class ShardTest method testApplySnapshot.
@Test
public void testApplySnapshot() throws Exception {
final TestActorRef<Shard> shard = actorFactory.createTestActor(newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()), "testApplySnapshot");
ShardTestKit.waitUntilLeader(shard);
final DataTree store = new InMemoryDataTreeFactory().create(DataTreeConfiguration.DEFAULT_OPERATIONAL, SCHEMA_CONTEXT);
final ContainerNode container = ImmutableContainerNodeBuilder.create().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME)).withChild(ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).addChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)).build()).build();
writeToStore(store, TestModel.TEST_PATH, container);
final YangInstanceIdentifier root = YangInstanceIdentifier.EMPTY;
final NormalizedNode<?, ?> expected = readStore(store, root);
final Snapshot snapshot = Snapshot.create(new ShardSnapshotState(new MetadataShardDataTreeSnapshot(expected)), Collections.<ReplicatedLogEntry>emptyList(), 1, 2, 3, 4, -1, null, null);
shard.tell(new ApplySnapshot(snapshot), ActorRef.noSender());
final Stopwatch sw = Stopwatch.createStarted();
while (sw.elapsed(TimeUnit.SECONDS) <= 5) {
Uninterruptibles.sleepUninterruptibly(75, TimeUnit.MILLISECONDS);
try {
assertEquals("Root node", expected, readStore(shard, root));
return;
} catch (final AssertionError e) {
// try again
}
}
fail("Snapshot was not applied");
}
Aggregations