Search in sources :

Example 21 with MockPayload

use of org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload in project controller by opendaylight.

the class IsolationScenarioTest method testLeaderIsolationWithPriorUncommittedEntryAndMultipleConflictingEntries.

/**
 * Isolates the leader with a payload entry that's replicated to all followers and committed on the leader but
 * uncommitted on the followers. While isolated, the majority partition elects a new leader and both sides of the
 * partition attempt to commit multiple entries independently. After isolation is removed, the entries will conflict
 * and both sides should reconcile their logs appropriately.
 */
@Test
public void testLeaderIsolationWithPriorUncommittedEntryAndMultipleConflictingEntries() throws Exception {
    testLog.info("testLeaderIsolationWithPriorUncommittedEntryAndMultipleConflictingEntries starting");
    createRaftActors();
    // Submit an initial payload that is committed/applied on all nodes.
    final MockPayload payload0 = sendPayloadData(leaderActor, "zero");
    verifyApplyJournalEntries(leaderCollectorActor, 0);
    verifyApplyJournalEntries(follower1CollectorActor, 0);
    verifyApplyJournalEntries(follower2CollectorActor, 0);
    // Submit another payload that is replicated to all followers and committed on the leader but the leader is
    // isolated before the entry is committed on the followers. To accomplish this we drop the AppendEntries
    // with the updated leader commit index.
    follower1Actor.underlyingActor().startDropMessages(AppendEntries.class, ae -> ae.getLeaderCommit() == 1);
    follower2Actor.underlyingActor().startDropMessages(AppendEntries.class, ae -> ae.getLeaderCommit() == 1);
    MockPayload payload1 = sendPayloadData(leaderActor, "one");
    // Wait for the isolated leader to send AppendEntries to the followers with the new entry with index 1. This
    // message is forwarded to the followers.
    expectFirstMatching(follower1CollectorActor, AppendEntries.class, ae -> ae.getEntries().size() == 1 && ae.getEntries().get(0).getIndex() == 1 && ae.getEntries().get(0).getData().equals(payload1));
    expectFirstMatching(follower2CollectorActor, AppendEntries.class, ae -> ae.getEntries().size() == 1 && ae.getEntries().get(0).getIndex() == 1 && ae.getEntries().get(0).getData().equals(payload1));
    verifyApplyJournalEntries(leaderCollectorActor, 1);
    isolateLeader();
    // Send 3 payloads to the isolated leader so it has uncommitted log entries.
    testLog.info("Sending 3 payloads to isolated leader");
    sendPayloadData(leaderActor, "two");
    sendPayloadData(leaderActor, "three");
    sendPayloadData(leaderActor, "four");
    // Wait for the isolated leader to send AppendEntries to follower1 for each new entry. Note the messages
    // are collected but not forwarded to the follower RaftActor.
    expectFirstMatching(follower1CollectorActor, AppendEntries.class, ae -> {
        for (ReplicatedLogEntry e : ae.getEntries()) {
            if (e.getIndex() == 4) {
                return true;
            }
        }
        return false;
    });
    // The leader should transition to IsolatedLeader.
    expectFirstMatching(leaderNotifierActor, RoleChanged.class, rc -> rc.getNewRole().equals(RaftState.IsolatedLeader.name()));
    forceElectionOnFollower1();
    // Send 3 payloads to the new leader follower1 and verify they're replicated to follower2 and committed. Since
    // the entry with index 1 from the previous term was uncommitted, the new leader should've also committed a
    // NoopPayload entry with index 2 in the PreLeader state. Thus the new payload indices will start at 3.
    testLog.info("Sending 3 payloads to new leader");
    final MockPayload newLeaderPayload2 = sendPayloadData(follower1Actor, "two-new");
    final MockPayload newLeaderPayload3 = sendPayloadData(follower1Actor, "three-new");
    final MockPayload newLeaderPayload4 = sendPayloadData(follower1Actor, "four-new");
    verifyApplyJournalEntries(follower1CollectorActor, 5);
    verifyApplyJournalEntries(follower2CollectorActor, 5);
    assertEquals("Follower 1 journal last term", currentTerm, follower1Context.getReplicatedLog().lastTerm());
    assertEquals("Follower 1 journal last index", 5, follower1Context.getReplicatedLog().lastIndex());
    assertEquals("Follower 1 commit index", 5, follower1Context.getCommitIndex());
    verifyReplicatedLogEntry(follower1Context.getReplicatedLog().get(5), currentTerm, 5, newLeaderPayload4);
    assertEquals("Follower 1 state", Lists.newArrayList(payload0, payload1, newLeaderPayload2, newLeaderPayload3, newLeaderPayload4), follower1Actor.underlyingActor().getState());
    removeIsolation();
    // Previous leader should switch to follower b/c it will receive either an AppendEntries or AppendEntriesReply
    // with a higher term.
    expectFirstMatching(leaderNotifierActor, RoleChanged.class, rc -> rc.getNewRole().equals(RaftState.Follower.name()));
    // The previous leader has conflicting log entries starting at index 2 with different terms which should get
    // replaced by the new leader's entries.
    verifyApplyJournalEntries(leaderCollectorActor, 5);
    verifyRaftState(leaderActor, raftState -> {
        assertEquals("Prior leader journal last term", currentTerm, leaderContext.getReplicatedLog().lastTerm());
        assertEquals("Prior leader journal last index", 5, leaderContext.getReplicatedLog().lastIndex());
        assertEquals("Prior leader commit index", 5, leaderContext.getCommitIndex());
    });
    assertEquals("Prior leader state", Lists.newArrayList(payload0, payload1, newLeaderPayload2, newLeaderPayload3, newLeaderPayload4), leaderActor.underlyingActor().getState());
    // Ensure the prior leader didn't apply any of its conflicting entries with term 1.
    List<ApplyState> applyState = getAllMatching(leaderCollectorActor, ApplyState.class);
    for (ApplyState as : applyState) {
        if (as.getReplicatedLogEntry().getTerm() == 1) {
            fail("Got unexpected ApplyState: " + as);
        }
    }
    // The prior leader should not have needed a snapshot installed in order to get it synced.
    assertNoneMatching(leaderCollectorActor, InstallSnapshot.class);
    testLog.info("testLeaderIsolationWithPriorUncommittedEntryAndMultipleConflictingEntries ending");
}
Also used : MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) ApplyState(org.opendaylight.controller.cluster.raft.base.messages.ApplyState) Test(org.junit.Test)

Example 22 with MockPayload

use of org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload in project controller by opendaylight.

the class RaftActorRecoverySupportTest method testOnSnapshotOffer.

@Test
public void testOnSnapshotOffer() {
    ReplicatedLog replicatedLog = context.getReplicatedLog();
    replicatedLog.append(new SimpleReplicatedLogEntry(1, 1, new MockRaftActorContext.MockPayload("1")));
    replicatedLog.append(new SimpleReplicatedLogEntry(2, 1, new MockRaftActorContext.MockPayload("2")));
    replicatedLog.append(new SimpleReplicatedLogEntry(3, 1, new MockRaftActorContext.MockPayload("3")));
    ReplicatedLogEntry unAppliedEntry1 = new SimpleReplicatedLogEntry(4, 1, new MockRaftActorContext.MockPayload("4", 4));
    ReplicatedLogEntry unAppliedEntry2 = new SimpleReplicatedLogEntry(5, 1, new MockRaftActorContext.MockPayload("5", 5));
    long lastAppliedDuringSnapshotCapture = 3;
    long lastIndexDuringSnapshotCapture = 5;
    long electionTerm = 2;
    String electionVotedFor = "member-2";
    MockSnapshotState snapshotState = new MockSnapshotState(Arrays.asList(new MockPayload("1")));
    Snapshot snapshot = Snapshot.create(snapshotState, Arrays.asList(unAppliedEntry1, unAppliedEntry2), lastIndexDuringSnapshotCapture, 1, lastAppliedDuringSnapshotCapture, 1, electionTerm, electionVotedFor, null);
    SnapshotMetadata metadata = new SnapshotMetadata("test", 6, 12345);
    SnapshotOffer snapshotOffer = new SnapshotOffer(metadata, snapshot);
    sendMessageToSupport(snapshotOffer);
    assertEquals("Journal log size", 2, context.getReplicatedLog().size());
    assertEquals("Journal data size", 9, context.getReplicatedLog().dataSize());
    assertEquals("Last index", lastIndexDuringSnapshotCapture, context.getReplicatedLog().lastIndex());
    assertEquals("Last applied", lastAppliedDuringSnapshotCapture, context.getLastApplied());
    assertEquals("Commit index", lastAppliedDuringSnapshotCapture, context.getCommitIndex());
    assertEquals("Snapshot term", 1, context.getReplicatedLog().getSnapshotTerm());
    assertEquals("Snapshot index", lastAppliedDuringSnapshotCapture, context.getReplicatedLog().getSnapshotIndex());
    assertEquals("Election term", electionTerm, context.getTermInformation().getCurrentTerm());
    assertEquals("Election votedFor", electionVotedFor, context.getTermInformation().getVotedFor());
    assertFalse("Dynamic server configuration", context.isDynamicServerConfigurationInUse());
    verify(mockCohort).applyRecoverySnapshot(snapshotState);
}
Also used : MockSnapshotState(org.opendaylight.controller.cluster.raft.MockRaftActor.MockSnapshotState) Snapshot(org.opendaylight.controller.cluster.raft.persisted.Snapshot) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) SnapshotMetadata(akka.persistence.SnapshotMetadata) SnapshotOffer(akka.persistence.SnapshotOffer) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) Test(org.junit.Test)

Example 23 with MockPayload

use of org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload in project controller by opendaylight.

the class PartitionedCandidateOnStartupElectionScenarioTest method setupInitialMember1AndMember2Behaviors.

private void setupInitialMember1AndMember2Behaviors() {
    testLog.info("setupInitialMember1AndMember2Behaviors starting");
    // Initialize the ReplicatedLog and election term info for member 1 and 2. The current term
    // will be 3 and the last term will be 2.
    SimpleReplicatedLog replicatedLog = new SimpleReplicatedLog();
    replicatedLog.append(new SimpleReplicatedLogEntry(0, 2, new MockPayload("")));
    replicatedLog.append(new SimpleReplicatedLogEntry(1, 3, new MockPayload("")));
    // Create member 2's behavior as Follower.
    member2Context = newRaftActorContext("member2", member2ActorRef, ImmutableMap.<String, String>builder().put("member1", member1ActorRef.path().toString()).put("member3", member3ActorRef.path().toString()).build());
    DefaultConfigParamsImpl member2ConfigParams = newConfigParams();
    member2Context.setConfigParams(member2ConfigParams);
    member2Context.setReplicatedLog(replicatedLog);
    member2Context.setCommitIndex(replicatedLog.lastIndex());
    member2Context.setLastApplied(replicatedLog.lastIndex());
    member2Context.getTermInformation().update(3, "member1");
    member2Actor.self().tell(new SetBehavior(new Follower(member2Context), member2Context), ActorRef.noSender());
    // Create member 1's behavior as Leader.
    member1Context = newRaftActorContext("member1", member1ActorRef, ImmutableMap.<String, String>builder().put("member2", member2ActorRef.path().toString()).put("member3", member3ActorRef.path().toString()).build());
    DefaultConfigParamsImpl member1ConfigParams = newConfigParams();
    member1Context.setConfigParams(member1ConfigParams);
    member1Context.setReplicatedLog(replicatedLog);
    member1Context.setCommitIndex(replicatedLog.lastIndex());
    member1Context.setLastApplied(replicatedLog.lastIndex());
    member1Context.getTermInformation().update(3, "member1");
    initializeLeaderBehavior(member1Actor, member1Context, 1);
    member2Actor.clear();
    member3Actor.clear();
    testLog.info("setupInitialMember1AndMember2Behaviors ending");
}
Also used : SimpleReplicatedLog(org.opendaylight.controller.cluster.raft.MockRaftActorContext.SimpleReplicatedLog) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) DefaultConfigParamsImpl(org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload)

Example 24 with MockPayload

use of org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload in project controller by opendaylight.

the class RaftActorTest method testReplicateWithBatchHint.

@Test
public void testReplicateWithBatchHint() throws Exception {
    final String leaderId = factory.generateActorId("leader-");
    final String followerId = factory.generateActorId("follower-");
    final ActorRef followerActor = factory.createActor(MessageCollectorActor.props());
    DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
    config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
    config.setIsolatedLeaderCheckInterval(new FiniteDuration(1, TimeUnit.DAYS));
    TestActorRef<MockRaftActor> leaderActorRef = factory.createTestActor(MockRaftActor.props(leaderId, ImmutableMap.of(followerId, followerActor.path().toString()), config), leaderId);
    MockRaftActor leaderActor = leaderActorRef.underlyingActor();
    leaderActor.waitForInitializeBehaviorComplete();
    leaderActor.getRaftActorContext().getTermInformation().update(1, leaderId);
    Leader leader = new Leader(leaderActor.getRaftActorContext());
    leaderActor.setCurrentBehavior(leader);
    MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
    MessageCollectorActor.clearMessages(followerActor);
    leaderActor.onReceiveCommand(new AppendEntriesReply(followerId, 1, true, -1, -1, (short) 0));
    leaderActor.persistData(leaderActorRef, new MockIdentifier("1"), new MockPayload("1"), true);
    MessageCollectorActor.assertNoneMatching(followerActor, AppendEntries.class, 500);
    leaderActor.persistData(leaderActorRef, new MockIdentifier("2"), new MockPayload("2"), true);
    MessageCollectorActor.assertNoneMatching(followerActor, AppendEntries.class, 500);
    leaderActor.persistData(leaderActorRef, new MockIdentifier("3"), new MockPayload("3"), false);
    AppendEntries appendEntries = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
    assertEquals("AppendEntries size", 3, appendEntries.getEntries().size());
}
Also used : Leader(org.opendaylight.controller.cluster.raft.behaviors.Leader) AppendEntriesReply(org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply) ActorRef(akka.actor.ActorRef) TestActorRef(akka.testkit.TestActorRef) FiniteDuration(scala.concurrent.duration.FiniteDuration) ByteString(com.google.protobuf.ByteString) AppendEntries(org.opendaylight.controller.cluster.raft.messages.AppendEntries) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) Test(org.junit.Test)

Example 25 with MockPayload

use of org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload 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");
}
Also used : MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) ByteString(com.google.protobuf.ByteString) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) 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) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) EmptyState(org.opendaylight.controller.cluster.raft.persisted.EmptyState) ApplyState(org.opendaylight.controller.cluster.raft.base.messages.ApplyState) MockSnapshotState(org.opendaylight.controller.cluster.raft.MockRaftActor.MockSnapshotState) ByteState(org.opendaylight.controller.cluster.raft.persisted.ByteState) DisableElectionsRaftPolicy(org.opendaylight.controller.cluster.raft.policy.DisableElectionsRaftPolicy) Test(org.junit.Test)

Aggregations

MockPayload (org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload)37 Test (org.junit.Test)30 SimpleReplicatedLogEntry (org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry)22 ApplyState (org.opendaylight.controller.cluster.raft.base.messages.ApplyState)11 Snapshot (org.opendaylight.controller.cluster.raft.persisted.Snapshot)8 ApplySnapshot (org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot)5 CaptureSnapshot (org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot)5 InstallSnapshot (org.opendaylight.controller.cluster.raft.messages.InstallSnapshot)5 MockSnapshotState (org.opendaylight.controller.cluster.raft.MockRaftActor.MockSnapshotState)4 AppendEntries (org.opendaylight.controller.cluster.raft.messages.AppendEntries)4 SnapshotMetadata (akka.persistence.SnapshotMetadata)3 SnapshotOffer (akka.persistence.SnapshotOffer)3 ApplyJournalEntries (org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries)3 ByteString (com.google.protobuf.ByteString)2 DefaultConfigParamsImpl (org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl)2 SimpleReplicatedLog (org.opendaylight.controller.cluster.raft.MockRaftActorContext.SimpleReplicatedLog)2 DeleteEntries (org.opendaylight.controller.cluster.raft.persisted.DeleteEntries)2 ServerConfigurationPayload (org.opendaylight.controller.cluster.raft.persisted.ServerConfigurationPayload)2 ServerInfo (org.opendaylight.controller.cluster.raft.persisted.ServerInfo)2 UpdateElectionTerm (org.opendaylight.controller.cluster.raft.persisted.UpdateElectionTerm)2