use of org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries in project controller by opendaylight.
the class RaftActor method persistData.
/**
* Persists the given Payload in the journal and replicates to any followers. After successful completion,
* {@link #applyState(ActorRef, Identifier, Object)} is notified.
*
* @param clientActor optional ActorRef that is provided via the applyState callback
* @param identifier the payload identifier
* @param data the payload data to persist
* @param batchHint if true, an attempt is made to delay immediate replication and batch the payload with
* subsequent payloads for efficiency. Otherwise the payload is immediately replicated.
*/
protected final void persistData(final ActorRef clientActor, final Identifier identifier, final Payload data, final boolean batchHint) {
ReplicatedLogEntry replicatedLogEntry = new SimpleReplicatedLogEntry(context.getReplicatedLog().lastIndex() + 1, context.getTermInformation().getCurrentTerm(), data);
replicatedLogEntry.setPersistencePending(true);
LOG.debug("{}: Persist data {}", persistenceId(), replicatedLogEntry);
final RaftActorContext raftContext = getRaftActorContext();
boolean wasAppended = replicatedLog().appendAndPersist(replicatedLogEntry, persistedLogEntry -> {
// Clear the persistence pending flag in the log entry.
persistedLogEntry.setPersistencePending(false);
if (!hasFollowers()) {
// Increment the Commit Index and the Last Applied values
raftContext.setCommitIndex(persistedLogEntry.getIndex());
raftContext.setLastApplied(persistedLogEntry.getIndex());
// Apply the state immediately.
handleApplyState(new ApplyState(clientActor, identifier, persistedLogEntry));
// Send a ApplyJournalEntries message so that we write the fact that we applied
// the state to durable storage
self().tell(new ApplyJournalEntries(persistedLogEntry.getIndex()), self());
} else {
context.getReplicatedLog().captureSnapshotIfReady(replicatedLogEntry);
// Local persistence is complete so send the CheckConsensusReached message to the behavior (which
// normally should still be the leader) to check if consensus has now been reached in conjunction with
// follower replication.
getCurrentBehavior().handleMessage(getSelf(), CheckConsensusReached.INSTANCE);
}
}, true);
if (wasAppended && hasFollowers()) {
// Send log entry for replication.
getCurrentBehavior().handleMessage(getSelf(), new Replicate(clientActor, identifier, replicatedLogEntry, !batchHint));
}
}
use of org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries in project controller by opendaylight.
the class ShardTest method testDataTreeCandidateRecovery.
@Test
public void testDataTreeCandidateRecovery() throws Exception {
// Set up the InMemorySnapshotStore.
final DataTree source = setupInMemorySnapshotStore();
final DataTreeModification writeMod = source.takeSnapshot().newModification();
writeMod.write(TestModel.OUTER_LIST_PATH, ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build());
writeMod.ready();
InMemoryJournal.addEntry(shardID.toString(), 0, DUMMY_DATA);
// Set up the InMemoryJournal.
InMemoryJournal.addEntry(shardID.toString(), 1, new SimpleReplicatedLogEntry(0, 1, payloadForModification(source, writeMod, nextTransactionId())));
final int nListEntries = 16;
final Set<Integer> listEntryKeys = new HashSet<>();
// Add some ModificationPayload entries
for (int i = 1; i <= nListEntries; i++) {
listEntryKeys.add(Integer.valueOf(i));
final YangInstanceIdentifier path = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, i).build();
final DataTreeModification mod = source.takeSnapshot().newModification();
mod.merge(path, ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, i));
mod.ready();
InMemoryJournal.addEntry(shardID.toString(), i + 1, new SimpleReplicatedLogEntry(i, 1, payloadForModification(source, mod, nextTransactionId())));
}
InMemoryJournal.addEntry(shardID.toString(), nListEntries + 2, new ApplyJournalEntries(nListEntries));
testRecovery(listEntryKeys);
}
use of org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries in project controller by opendaylight.
the class LeaderTest method testHandleAppendEntriesReplySuccess.
@Test
public void testHandleAppendEntriesReplySuccess() throws Exception {
logStart("testHandleAppendEntriesReplySuccess");
MockRaftActorContext leaderActorContext = createActorContextWithFollower();
leaderActorContext.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 3, 1).build());
leaderActorContext.setCommitIndex(1);
leaderActorContext.setLastApplied(1);
leaderActorContext.getTermInformation().update(1, "leader");
leader = new Leader(leaderActorContext);
FollowerLogInformation followerInfo = leader.getFollower(FOLLOWER_ID);
assertEquals(payloadVersion, leader.getLeaderPayloadVersion());
assertEquals(RaftVersions.HELIUM_VERSION, followerInfo.getRaftVersion());
AppendEntriesReply reply = new AppendEntriesReply(FOLLOWER_ID, 1, true, 2, 1, payloadVersion);
RaftActorBehavior raftActorBehavior = leader.handleAppendEntriesReply(followerActor, reply);
assertEquals(RaftState.Leader, raftActorBehavior.state());
assertEquals(2, leaderActorContext.getCommitIndex());
ApplyJournalEntries applyJournalEntries = MessageCollectorActor.expectFirstMatching(leaderActor, ApplyJournalEntries.class);
assertEquals(2, leaderActorContext.getLastApplied());
assertEquals(2, applyJournalEntries.getToIndex());
List<ApplyState> applyStateList = MessageCollectorActor.getAllMatching(leaderActor, ApplyState.class);
assertEquals(1, applyStateList.size());
ApplyState applyState = applyStateList.get(0);
assertEquals(2, applyState.getReplicatedLogEntry().getIndex());
assertEquals(2, followerInfo.getMatchIndex());
assertEquals(3, followerInfo.getNextIndex());
assertEquals(payloadVersion, followerInfo.getPayloadVersion());
assertEquals(RaftVersions.CURRENT_VERSION, followerInfo.getRaftVersion());
}
use of org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries in project controller by opendaylight.
the class RaftActorTest method testRaftActorForwardsToRaftActorRecoverySupport.
@Test
public void testRaftActorForwardsToRaftActorRecoverySupport() {
String persistenceId = factory.generateActorId("leader-");
DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId, Collections.<String, String>emptyMap(), config), persistenceId);
MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
// Wait for akka's recovery to complete so it doesn't interfere.
mockRaftActor.waitForRecoveryComplete();
RaftActorRecoverySupport mockSupport = mock(RaftActorRecoverySupport.class);
mockRaftActor.setRaftActorRecoverySupport(mockSupport);
Snapshot snapshot = Snapshot.create(ByteState.of(new byte[] { 1 }), Collections.<ReplicatedLogEntry>emptyList(), 3, 1, 3, 1, -1, null, null);
SnapshotOffer snapshotOffer = new SnapshotOffer(new SnapshotMetadata("test", 6, 12345), snapshot);
mockRaftActor.handleRecover(snapshotOffer);
ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(1, 1, new MockRaftActorContext.MockPayload("1", 5));
mockRaftActor.handleRecover(logEntry);
ApplyJournalEntries applyJournalEntries = new ApplyJournalEntries(2);
mockRaftActor.handleRecover(applyJournalEntries);
DeleteEntries deleteEntries = new DeleteEntries(1);
mockRaftActor.handleRecover(deleteEntries);
UpdateElectionTerm updateElectionTerm = new UpdateElectionTerm(5, "member2");
mockRaftActor.handleRecover(updateElectionTerm);
verify(mockSupport).handleRecoveryMessage(same(snapshotOffer), any(PersistentDataProvider.class));
verify(mockSupport).handleRecoveryMessage(same(logEntry), any(PersistentDataProvider.class));
verify(mockSupport).handleRecoveryMessage(same(applyJournalEntries), any(PersistentDataProvider.class));
verify(mockSupport).handleRecoveryMessage(same(deleteEntries), any(PersistentDataProvider.class));
verify(mockSupport).handleRecoveryMessage(same(updateElectionTerm), any(PersistentDataProvider.class));
}
use of org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries in project controller by opendaylight.
the class RaftActorTest method testApplyJournalEntriesCallsDataPersistence.
@SuppressWarnings("unchecked")
@Test
public void testApplyJournalEntriesCallsDataPersistence() throws Exception {
String persistenceId = factory.generateActorId("leader-");
DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId, Collections.<String, String>emptyMap(), config, dataPersistenceProvider), persistenceId);
MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
mockRaftActor.waitForInitializeBehaviorComplete();
mockRaftActor.waitUntilLeader();
mockRaftActor.onReceiveCommand(new ApplyJournalEntries(10));
verify(dataPersistenceProvider).persistAsync(any(ApplyJournalEntries.class), any(Procedure.class));
}
Aggregations