Search in sources :

Example 16 with MockPayload

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

the class AbstractRaftActorIntegrationTest method sendPayloadData.

protected MockPayload sendPayloadData(final ActorRef actor, final String data, final int size) {
    MockPayload payload;
    if (size > 0) {
        payload = new MockPayload(data, size);
    } else {
        payload = new MockPayload(data);
    }
    actor.tell(payload, ActorRef.noSender());
    return payload;
}
Also used : MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload)

Example 17 with MockPayload

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

the class AbstractReplicatedLogImplTest method testRemoveFrom.

@Test
public void testRemoveFrom() {
    replicatedLogImpl.append(new SimpleReplicatedLogEntry(4, 2, new MockPayload("E", 2)));
    replicatedLogImpl.append(new SimpleReplicatedLogEntry(5, 2, new MockPayload("F", 3)));
    assertEquals("dataSize", 9, replicatedLogImpl.dataSize());
    long adjusted = replicatedLogImpl.removeFrom(4);
    assertEquals("removeFrom - adjusted", 4, adjusted);
    assertEquals("size", 4, replicatedLogImpl.size());
    assertEquals("dataSize", 4, replicatedLogImpl.dataSize());
    takeSnapshot(1);
    adjusted = replicatedLogImpl.removeFrom(2);
    assertEquals("removeFrom - adjusted", 1, adjusted);
    assertEquals("size", 1, replicatedLogImpl.size());
    assertEquals("dataSize", 1, replicatedLogImpl.dataSize());
    assertEquals("removeFrom - adjusted", -1, replicatedLogImpl.removeFrom(0));
    assertEquals("removeFrom - adjusted", -1, replicatedLogImpl.removeFrom(100));
}
Also used : SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) Test(org.junit.Test)

Example 18 with MockPayload

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

the class AbstractReplicatedLogImplTest method testSnapshotPreCommit.

@Test
public void testSnapshotPreCommit() {
    // add 4 more entries
    replicatedLogImpl.append(new SimpleReplicatedLogEntry(4, 2, new MockPayload("E")));
    replicatedLogImpl.append(new SimpleReplicatedLogEntry(5, 2, new MockPayload("F")));
    replicatedLogImpl.append(new SimpleReplicatedLogEntry(6, 3, new MockPayload("G")));
    replicatedLogImpl.append(new SimpleReplicatedLogEntry(7, 3, new MockPayload("H")));
    // sending negative values should not cause any changes
    replicatedLogImpl.snapshotPreCommit(-1, -1);
    assertEquals(8, replicatedLogImpl.size());
    assertEquals(-1, replicatedLogImpl.getSnapshotIndex());
    assertEquals(-1, replicatedLogImpl.getSnapshotTerm());
    replicatedLogImpl.snapshotPreCommit(4, 2);
    assertEquals(3, replicatedLogImpl.size());
    assertEquals(4, replicatedLogImpl.getSnapshotIndex());
    assertEquals(2, replicatedLogImpl.getSnapshotTerm());
    replicatedLogImpl.snapshotPreCommit(6, 3);
    assertEquals(1, replicatedLogImpl.size());
    assertEquals(6, replicatedLogImpl.getSnapshotIndex());
    assertEquals(3, replicatedLogImpl.getSnapshotTerm());
    replicatedLogImpl.snapshotPreCommit(7, 3);
    assertEquals(0, replicatedLogImpl.size());
    assertEquals(7, replicatedLogImpl.getSnapshotIndex());
    assertEquals(3, replicatedLogImpl.getSnapshotTerm());
    // running it again on an empty list should not throw exception
    replicatedLogImpl.snapshotPreCommit(7, 3);
    assertEquals(0, replicatedLogImpl.size());
    assertEquals(7, replicatedLogImpl.getSnapshotIndex());
    assertEquals(3, replicatedLogImpl.getSnapshotTerm());
}
Also used : SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) Test(org.junit.Test)

Example 19 with MockPayload

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

the class AbstractReplicatedLogImplTest method setUp.

@Before
public void setUp() {
    replicatedLogImpl = new MockAbstractReplicatedLogImpl();
    // create a set of initial entries in the in-memory log
    replicatedLogImpl.append(new SimpleReplicatedLogEntry(0, 1, new MockPayload("A")));
    replicatedLogImpl.append(new SimpleReplicatedLogEntry(1, 1, new MockPayload("B")));
    replicatedLogImpl.append(new SimpleReplicatedLogEntry(2, 1, new MockPayload("C")));
    replicatedLogImpl.append(new SimpleReplicatedLogEntry(3, 2, new MockPayload("D")));
}
Also used : SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) Before(org.junit.Before)

Example 20 with MockPayload

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

the class IsolationScenarioTest method testLeaderIsolationWithPriorUncommittedEntryAndOneConflictingEntry.

/**
 * 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 one entry independently. After isolation is removed, the entry will conflict and both
 * sides should reconcile their logs appropriately.
 */
@Test
public void testLeaderIsolationWithPriorUncommittedEntryAndOneConflictingEntry() throws Exception {
    testLog.info("testLeaderIsolationWithPriorUncommittedEntryAndOneConflictingEntry 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 a payload to the isolated leader so it has an uncommitted log entry with index 2.
    testLog.info("Sending payload to isolated leader");
    final MockPayload isolatedLeaderPayload2 = sendPayloadData(leaderActor, "two");
    // Wait for the isolated leader to send AppendEntries to follower1 with the entry at index 2. Note the message
    // is collected but not forwarded to the follower RaftActor.
    AppendEntries appendEntries = expectFirstMatching(follower1CollectorActor, AppendEntries.class);
    assertEquals("getTerm", currentTerm, appendEntries.getTerm());
    assertEquals("getLeaderId", leaderId, appendEntries.getLeaderId());
    assertEquals("getEntries().size()", 1, appendEntries.getEntries().size());
    verifyReplicatedLogEntry(appendEntries.getEntries().get(0), currentTerm, 2, isolatedLeaderPayload2);
    // The leader should transition to IsolatedLeader.
    expectFirstMatching(leaderNotifierActor, RoleChanged.class, rc -> rc.getNewRole().equals(RaftState.IsolatedLeader.name()));
    forceElectionOnFollower1();
    // Send a payload to the new leader follower1 and verify it's 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 will have index 3.
    testLog.info("Sending payload to new leader");
    final MockPayload newLeaderPayload2 = sendPayloadData(follower1Actor, "two-new");
    verifyApplyJournalEntries(follower1CollectorActor, 3);
    verifyApplyJournalEntries(follower2CollectorActor, 3);
    assertEquals("Follower 1 journal last term", currentTerm, follower1Context.getReplicatedLog().lastTerm());
    assertEquals("Follower 1 journal last index", 3, follower1Context.getReplicatedLog().lastIndex());
    assertEquals("Follower 1 commit index", 3, follower1Context.getCommitIndex());
    verifyReplicatedLogEntry(follower1Context.getReplicatedLog().get(3), currentTerm, 3, newLeaderPayload2);
    assertEquals("Follower 1 state", Lists.newArrayList(payload0, payload1, newLeaderPayload2), 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 a conflicting log entry at index 2 with a different term which should get
    // replaced by the new leader's entry.
    verifyApplyJournalEntries(leaderCollectorActor, 3);
    verifyRaftState(leaderActor, raftState -> {
        assertEquals("Prior leader journal last term", currentTerm, leaderContext.getReplicatedLog().lastTerm());
        assertEquals("Prior leader journal last index", 3, leaderContext.getReplicatedLog().lastIndex());
        assertEquals("Prior leader commit index", 3, leaderContext.getCommitIndex());
    });
    assertEquals("Prior leader state", Lists.newArrayList(payload0, payload1, newLeaderPayload2), leaderActor.underlyingActor().getState());
    // Ensure the prior leader didn't apply its conflicting entry with index 2, term 1.
    List<ApplyState> applyState = getAllMatching(leaderCollectorActor, ApplyState.class);
    for (ApplyState as : applyState) {
        if (as.getReplicatedLogEntry().getIndex() == 2 && 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("testLeaderIsolationWithPriorUncommittedEntryAndOneConflictingEntry ending");
}
Also used : AppendEntries(org.opendaylight.controller.cluster.raft.messages.AppendEntries) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) ApplyState(org.opendaylight.controller.cluster.raft.base.messages.ApplyState) 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