Search in sources :

Example 51 with SimpleReplicatedLogEntry

use of org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry in project controller by opendaylight.

the class RaftActorServerConfigurationSupportTest method testOnApplyState.

@Test
public void testOnApplyState() {
    LOG.info("testOnApplyState starting");
    DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
    configParams.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
    TestActorRef<MockRaftActor> noLeaderActor = actorFactory.createTestActor(MockRaftActor.builder().id(LEADER_ID).peerAddresses(ImmutableMap.of(FOLLOWER_ID, followerActor.path().toString())).config(configParams).persistent(Optional.of(false)).props().withDispatcher(Dispatchers.DefaultDispatcherId()), actorFactory.generateActorId(LEADER_ID));
    RaftActorServerConfigurationSupport support = new RaftActorServerConfigurationSupport(noLeaderActor.underlyingActor());
    ReplicatedLogEntry serverConfigEntry = new SimpleReplicatedLogEntry(1, 1, new ServerConfigurationPayload(Collections.<ServerInfo>emptyList()));
    boolean handled = support.handleMessage(new ApplyState(null, null, serverConfigEntry), ActorRef.noSender());
    assertEquals("Message handled", true, handled);
    ReplicatedLogEntry nonServerConfigEntry = new SimpleReplicatedLogEntry(1, 1, new MockRaftActorContext.MockPayload("1"));
    handled = support.handleMessage(new ApplyState(null, null, nonServerConfigEntry), ActorRef.noSender());
    assertEquals("Message handled", false, handled);
    LOG.info("testOnApplyState ending");
}
Also used : ServerInfo(org.opendaylight.controller.cluster.raft.persisted.ServerInfo) FiniteDuration(scala.concurrent.duration.FiniteDuration) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ServerConfigurationPayload(org.opendaylight.controller.cluster.raft.persisted.ServerConfigurationPayload) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ApplyState(org.opendaylight.controller.cluster.raft.base.messages.ApplyState) Test(org.junit.Test)

Example 52 with SimpleReplicatedLogEntry

use of org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry in project controller by opendaylight.

the class RaftActorServerConfigurationSupportTest method testChangeToVotingWithNoLeader.

@Test
public void testChangeToVotingWithNoLeader() {
    LOG.info("testChangeToVotingWithNoLeader starting");
    DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
    configParams.setHeartBeatInterval(new FiniteDuration(100, TimeUnit.MILLISECONDS));
    configParams.setElectionTimeoutFactor(5);
    final String node1ID = "node1";
    final String node2ID = "node2";
    // Set up a persisted ServerConfigurationPayload. Initially node1 and node2 will come up as non-voting.
    // via the server config. The server config will also contain 2 voting peers that are down (ie no
    // actors created).
    ServerConfigurationPayload persistedServerConfig = new ServerConfigurationPayload(Arrays.asList(new ServerInfo(node1ID, false), new ServerInfo(node2ID, false), new ServerInfo("downNode1", true), new ServerInfo("downNode2", true)));
    SimpleReplicatedLogEntry persistedServerConfigEntry = new SimpleReplicatedLogEntry(0, 1, persistedServerConfig);
    InMemoryJournal.addEntry(node1ID, 1, new UpdateElectionTerm(1, "downNode1"));
    InMemoryJournal.addEntry(node1ID, 2, persistedServerConfigEntry);
    InMemoryJournal.addEntry(node1ID, 3, new ApplyJournalEntries(0));
    InMemoryJournal.addEntry(node2ID, 1, new UpdateElectionTerm(1, "downNode2"));
    InMemoryJournal.addEntry(node2ID, 2, persistedServerConfigEntry);
    InMemoryJournal.addEntry(node2ID, 3, new ApplyJournalEntries(0));
    ActorRef node1Collector = actorFactory.createActor(MessageCollectorActor.props(), actorFactory.generateActorId("collector"));
    TestActorRef<CollectingMockRaftActor> node1RaftActorRef = actorFactory.createTestActor(CollectingMockRaftActor.props(node1ID, ImmutableMap.<String, String>of(), configParams, PERSISTENT, node1Collector).withDispatcher(Dispatchers.DefaultDispatcherId()), node1ID);
    CollectingMockRaftActor node1RaftActor = node1RaftActorRef.underlyingActor();
    ActorRef node2Collector = actorFactory.createActor(MessageCollectorActor.props(), actorFactory.generateActorId("collector"));
    TestActorRef<CollectingMockRaftActor> node2RaftActorRef = actorFactory.createTestActor(CollectingMockRaftActor.props(node2ID, ImmutableMap.<String, String>of(), configParams, PERSISTENT, node2Collector).withDispatcher(Dispatchers.DefaultDispatcherId()), node2ID);
    CollectingMockRaftActor node2RaftActor = node2RaftActorRef.underlyingActor();
    node1RaftActor.waitForInitializeBehaviorComplete();
    node2RaftActor.waitForInitializeBehaviorComplete();
    // Verify the intended server config was loaded and applied.
    verifyServerConfigurationPayloadEntry(node1RaftActor.getRaftActorContext().getReplicatedLog(), nonVotingServer(node1ID), nonVotingServer(node2ID), votingServer("downNode1"), votingServer("downNode2"));
    assertEquals("isVotingMember", false, node1RaftActor.getRaftActorContext().isVotingMember());
    assertEquals("getRaftState", RaftState.Follower, node1RaftActor.getRaftState());
    assertEquals("getLeaderId", null, node1RaftActor.getLeaderId());
    verifyServerConfigurationPayloadEntry(node2RaftActor.getRaftActorContext().getReplicatedLog(), nonVotingServer(node1ID), nonVotingServer(node2ID), votingServer("downNode1"), votingServer("downNode2"));
    assertEquals("isVotingMember", false, node2RaftActor.getRaftActorContext().isVotingMember());
    // For the test, we send a ChangeServersVotingStatus message to node1 to flip the voting states for
    // each server, ie node1 and node2 to voting and the 2 down nodes to non-voting. This should cause
    // node1 to try to elect itself as leader in order to apply the new server config. Since the 2
    // down nodes are switched to non-voting, node1 should only need a vote from node2.
    // First send the message such that node1 has no peer address for node2 - should fail.
    ChangeServersVotingStatus changeServers = new ChangeServersVotingStatus(ImmutableMap.of(node1ID, true, node2ID, true, "downNode1", false, "downNode2", false));
    node1RaftActorRef.tell(changeServers, testKit.getRef());
    ServerChangeReply reply = testKit.expectMsgClass(testKit.duration("5 seconds"), ServerChangeReply.class);
    assertEquals("getStatus", ServerChangeStatus.NO_LEADER, reply.getStatus());
    assertEquals("getRaftState", RaftState.Follower, node1RaftActor.getRaftState());
    // Send an AppendEntries so node1 has a leaderId
    long term = node1RaftActor.getRaftActorContext().getTermInformation().getCurrentTerm();
    node1RaftActorRef.tell(new AppendEntries(term, "downNode1", -1L, -1L, Collections.<ReplicatedLogEntry>emptyList(), 0, -1, (short) 1), ActorRef.noSender());
    // Wait for the ElectionTimeout to clear the leaderId. The leaderId must be null so on the next
    // ChangeServersVotingStatus message, it will try to elect a leader.
    AbstractRaftActorIntegrationTest.verifyRaftState(node1RaftActorRef, rs -> assertEquals("getLeader", null, rs.getLeader()));
    // Update node2's peer address and send the message again
    node1RaftActor.setPeerAddress(node2ID, node2RaftActorRef.path().toString());
    node1RaftActorRef.tell(changeServers, testKit.getRef());
    reply = testKit.expectMsgClass(testKit.duration("5 seconds"), ServerChangeReply.class);
    assertEquals("getStatus", ServerChangeStatus.OK, reply.getStatus());
    ApplyJournalEntries apply = MessageCollectorActor.expectFirstMatching(node1Collector, ApplyJournalEntries.class);
    assertEquals("getToIndex", 1, apply.getToIndex());
    verifyServerConfigurationPayloadEntry(node1RaftActor.getRaftActorContext().getReplicatedLog(), votingServer(node1ID), votingServer(node2ID), nonVotingServer("downNode1"), nonVotingServer("downNode2"));
    assertEquals("isVotingMember", true, node1RaftActor.getRaftActorContext().isVotingMember());
    assertEquals("getRaftState", RaftState.Leader, node1RaftActor.getRaftState());
    apply = MessageCollectorActor.expectFirstMatching(node2Collector, ApplyJournalEntries.class);
    assertEquals("getToIndex", 1, apply.getToIndex());
    verifyServerConfigurationPayloadEntry(node2RaftActor.getRaftActorContext().getReplicatedLog(), votingServer(node1ID), votingServer(node2ID), nonVotingServer("downNode1"), nonVotingServer("downNode2"));
    assertEquals("isVotingMember", true, node2RaftActor.getRaftActorContext().isVotingMember());
    assertEquals("getRaftState", RaftState.Follower, node2RaftActor.getRaftState());
    LOG.info("testChangeToVotingWithNoLeader ending");
}
Also used : ServerInfo(org.opendaylight.controller.cluster.raft.persisted.ServerInfo) ActorRef(akka.actor.ActorRef) TestActorRef(akka.testkit.TestActorRef) FiniteDuration(scala.concurrent.duration.FiniteDuration) AppendEntries(org.opendaylight.controller.cluster.raft.messages.AppendEntries) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ServerConfigurationPayload(org.opendaylight.controller.cluster.raft.persisted.ServerConfigurationPayload) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ChangeServersVotingStatus(org.opendaylight.controller.cluster.raft.messages.ChangeServersVotingStatus) ApplyJournalEntries(org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries) ServerChangeReply(org.opendaylight.controller.cluster.raft.messages.ServerChangeReply) UpdateElectionTerm(org.opendaylight.controller.cluster.raft.persisted.UpdateElectionTerm) Test(org.junit.Test)

Example 53 with SimpleReplicatedLogEntry

use of org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry in project controller by opendaylight.

the class LeaderTest method testSendAppendEntriesSnapshotScenario.

@Test
public void testSendAppendEntriesSnapshotScenario() throws Exception {
    logStart("testSendAppendEntriesSnapshotScenario");
    final MockRaftActorContext actorContext = createActorContextWithFollower();
    Map<String, String> leadersSnapshot = new HashMap<>();
    leadersSnapshot.put("1", "A");
    leadersSnapshot.put("2", "B");
    leadersSnapshot.put("3", "C");
    // clears leaders log
    actorContext.getReplicatedLog().removeFrom(0);
    final int followersLastIndex = 2;
    final int snapshotIndex = 3;
    final int newEntryIndex = 4;
    final int snapshotTerm = 1;
    final int currentTerm = 2;
    // set the snapshot variables in replicatedlog
    actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
    actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
    actorContext.setCommitIndex(followersLastIndex);
    leader = new Leader(actorContext);
    // Leader will send an immediate heartbeat - ignore it.
    MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
    // new entry
    SimpleReplicatedLogEntry entry = new SimpleReplicatedLogEntry(newEntryIndex, currentTerm, new MockRaftActorContext.MockPayload("D"));
    actorContext.getReplicatedLog().append(entry);
    // update follower timestamp
    leader.markFollowerActive(FOLLOWER_ID);
    // this should invoke a sendinstallsnapshot as followersLastIndex < snapshotIndex
    RaftActorBehavior raftBehavior = leader.handleMessage(leaderActor, new Replicate(null, new MockIdentifier("state-id"), entry, true));
    assertTrue(raftBehavior instanceof Leader);
    assertEquals("isCapturing", true, actorContext.getSnapshotManager().isCapturing());
}
Also used : Replicate(org.opendaylight.controller.cluster.raft.base.messages.Replicate) HashMap(java.util.HashMap) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) MockRaftActorContext(org.opendaylight.controller.cluster.raft.MockRaftActorContext) ByteString(com.google.protobuf.ByteString) Test(org.junit.Test)

Example 54 with SimpleReplicatedLogEntry

use of org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry in project controller by opendaylight.

the class LeaderTest method sendReplicate.

private RaftActorBehavior sendReplicate(MockRaftActorContext actorContext, long term, long index, Payload payload) {
    SimpleReplicatedLogEntry newEntry = new SimpleReplicatedLogEntry(index, term, payload);
    actorContext.getReplicatedLog().append(newEntry);
    return leader.handleMessage(leaderActor, new Replicate(null, null, newEntry, true));
}
Also used : Replicate(org.opendaylight.controller.cluster.raft.base.messages.Replicate) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry)

Example 55 with SimpleReplicatedLogEntry

use of org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry in project controller by opendaylight.

the class LeaderTest method testInitiateInstallSnapshot.

@Test
public void testInitiateInstallSnapshot() throws Exception {
    logStart("testInitiateInstallSnapshot");
    MockRaftActorContext actorContext = createActorContextWithFollower();
    // clears leaders log
    actorContext.getReplicatedLog().removeFrom(0);
    final int followersLastIndex = 2;
    final int snapshotIndex = 3;
    final int newEntryIndex = 4;
    final int snapshotTerm = 1;
    final int currentTerm = 2;
    // set the snapshot variables in replicatedlog
    actorContext.getReplicatedLog().setSnapshotIndex(snapshotIndex);
    actorContext.getReplicatedLog().setSnapshotTerm(snapshotTerm);
    actorContext.setLastApplied(3);
    actorContext.setCommitIndex(followersLastIndex);
    leader = new Leader(actorContext);
    // Leader will send an immediate heartbeat - ignore it.
    MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
    // set the snapshot as absent and check if capture-snapshot is invoked.
    leader.setSnapshotHolder(null);
    // new entry
    SimpleReplicatedLogEntry entry = new SimpleReplicatedLogEntry(newEntryIndex, currentTerm, new MockRaftActorContext.MockPayload("D"));
    actorContext.getReplicatedLog().append(entry);
    // update follower timestamp
    leader.markFollowerActive(FOLLOWER_ID);
    leader.handleMessage(leaderActor, new Replicate(null, new MockIdentifier("state-id"), entry, true));
    assertEquals("isCapturing", true, actorContext.getSnapshotManager().isCapturing());
    CaptureSnapshot cs = actorContext.getSnapshotManager().getCaptureSnapshot();
    assertEquals(3, cs.getLastAppliedIndex());
    assertEquals(1, cs.getLastAppliedTerm());
    assertEquals(4, cs.getLastIndex());
    assertEquals(2, cs.getLastTerm());
    // if an initiate is started again when first is in progress, it shouldnt initiate Capture
    leader.handleMessage(leaderActor, new Replicate(null, new MockIdentifier("state-id"), entry, true));
    assertSame("CaptureSnapshot instance", cs, actorContext.getSnapshotManager().getCaptureSnapshot());
}
Also used : Replicate(org.opendaylight.controller.cluster.raft.base.messages.Replicate) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) MockRaftActorContext(org.opendaylight.controller.cluster.raft.MockRaftActorContext) CaptureSnapshot(org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot) Test(org.junit.Test)

Aggregations

SimpleReplicatedLogEntry (org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry)75 Test (org.junit.Test)64 MockPayload (org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload)32 Snapshot (org.opendaylight.controller.cluster.raft.persisted.Snapshot)17 ApplyJournalEntries (org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries)15 UpdateElectionTerm (org.opendaylight.controller.cluster.raft.persisted.UpdateElectionTerm)12 FiniteDuration (scala.concurrent.duration.FiniteDuration)12 ByteString (com.google.protobuf.ByteString)11 ApplyState (org.opendaylight.controller.cluster.raft.base.messages.ApplyState)11 CaptureSnapshot (org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot)11 ServerConfigurationPayload (org.opendaylight.controller.cluster.raft.persisted.ServerConfigurationPayload)11 ServerInfo (org.opendaylight.controller.cluster.raft.persisted.ServerInfo)11 ActorRef (akka.actor.ActorRef)10 TestActorRef (akka.testkit.TestActorRef)9 ApplySnapshot (org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot)8 ByteState (org.opendaylight.controller.cluster.raft.persisted.ByteState)8 ArrayList (java.util.ArrayList)7 MockRaftActorContext (org.opendaylight.controller.cluster.raft.MockRaftActorContext)7 CaptureSnapshotReply (org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotReply)7 DisableElectionsRaftPolicy (org.opendaylight.controller.cluster.raft.policy.DisableElectionsRaftPolicy)7