Search in sources :

Example 1 with ApplyJournalEntries

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));
    }
}
Also used : SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) Replicate(org.opendaylight.controller.cluster.raft.base.messages.Replicate) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ApplyJournalEntries(org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries) ApplyState(org.opendaylight.controller.cluster.raft.base.messages.ApplyState)

Example 2 with ApplyJournalEntries

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);
}
Also used : DataTreeModification(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification) DataTree(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ApplyJournalEntries(org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries) YangInstanceIdentifier(org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier) HashSet(java.util.HashSet) Test(org.junit.Test)

Example 3 with ApplyJournalEntries

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());
}
Also used : FollowerLogInformation(org.opendaylight.controller.cluster.raft.FollowerLogInformation) AppendEntriesReply(org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply) MockRaftActorContext(org.opendaylight.controller.cluster.raft.MockRaftActorContext) ApplyJournalEntries(org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries) ApplyState(org.opendaylight.controller.cluster.raft.base.messages.ApplyState) Test(org.junit.Test)

Example 4 with ApplyJournalEntries

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));
}
Also used : DeleteEntries(org.opendaylight.controller.cluster.raft.persisted.DeleteEntries) FiniteDuration(scala.concurrent.duration.FiniteDuration) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) ByteString(com.google.protobuf.ByteString) ApplySnapshot(org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot) Snapshot(org.opendaylight.controller.cluster.raft.persisted.Snapshot) GetSnapshot(org.opendaylight.controller.cluster.raft.client.messages.GetSnapshot) PersistentDataProvider(org.opendaylight.controller.cluster.PersistentDataProvider) NonPersistentDataProvider(org.opendaylight.controller.cluster.NonPersistentDataProvider) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) SnapshotMetadata(akka.persistence.SnapshotMetadata) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ApplyJournalEntries(org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries) SnapshotOffer(akka.persistence.SnapshotOffer) UpdateElectionTerm(org.opendaylight.controller.cluster.raft.persisted.UpdateElectionTerm) Test(org.junit.Test)

Example 5 with ApplyJournalEntries

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));
}
Also used : DataPersistenceProvider(org.opendaylight.controller.cluster.DataPersistenceProvider) ApplyJournalEntries(org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries) FiniteDuration(scala.concurrent.duration.FiniteDuration) Procedure(akka.japi.Procedure) ByteString(com.google.protobuf.ByteString) Test(org.junit.Test)

Aggregations

ApplyJournalEntries (org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries)19 Test (org.junit.Test)15 SimpleReplicatedLogEntry (org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry)14 MockPayload (org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload)9 UpdateElectionTerm (org.opendaylight.controller.cluster.raft.persisted.UpdateElectionTerm)7 ApplyState (org.opendaylight.controller.cluster.raft.base.messages.ApplyState)6 Snapshot (org.opendaylight.controller.cluster.raft.persisted.Snapshot)6 ActorRef (akka.actor.ActorRef)5 TestActorRef (akka.testkit.TestActorRef)5 ApplySnapshot (org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot)5 FiniteDuration (scala.concurrent.duration.FiniteDuration)5 ByteString (com.google.protobuf.ByteString)4 TestKit (akka.testkit.javadsl.TestKit)3 ServerConfigurationPayload (org.opendaylight.controller.cluster.raft.persisted.ServerConfigurationPayload)3 ServerInfo (org.opendaylight.controller.cluster.raft.persisted.ServerInfo)3 SnapshotMetadata (akka.persistence.SnapshotMetadata)2 SnapshotOffer (akka.persistence.SnapshotOffer)2 Optional (com.google.common.base.Optional)2 Stopwatch (com.google.common.base.Stopwatch)2 ByteSource (com.google.common.io.ByteSource)2