Search in sources :

Example 1 with ServerInfo

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

the class RaftActorContextImpl method updatePeerIds.

@Override
public void updatePeerIds(final ServerConfigurationPayload serverConfig) {
    votingMember = true;
    boolean foundSelf = false;
    Set<String> currentPeers = new HashSet<>(this.getPeerIds());
    for (ServerInfo server : serverConfig.getServerConfig()) {
        if (getId().equals(server.getId())) {
            foundSelf = true;
            if (!server.isVoting()) {
                votingMember = false;
            }
        } else {
            VotingState votingState = server.isVoting() ? VotingState.VOTING : VotingState.NON_VOTING;
            if (!currentPeers.contains(server.getId())) {
                this.addToPeers(server.getId(), null, votingState);
            } else {
                this.getPeerInfo(server.getId()).setVotingState(votingState);
                currentPeers.remove(server.getId());
            }
        }
    }
    for (String peerIdToRemove : currentPeers) {
        this.removePeer(peerIdToRemove);
    }
    if (!foundSelf) {
        votingMember = false;
    }
    log.debug("{}: Updated server config: isVoting: {}, peers: {}", id, votingMember, peerInfoMap.values());
    setDynamicServerConfigurationInUse();
}
Also used : ServerInfo(org.opendaylight.controller.cluster.raft.persisted.ServerInfo) HashSet(java.util.HashSet)

Example 2 with ServerInfo

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

the class RaftActorTest method testNonVotingOnRecovery.

@Test
public void testNonVotingOnRecovery() throws Exception {
    TEST_LOG.info("testNonVotingOnRecovery starting");
    DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
    config.setElectionTimeoutFactor(1);
    config.setHeartBeatInterval(FiniteDuration.create(1, TimeUnit.MILLISECONDS));
    String persistenceId = factory.generateActorId("test-actor-");
    InMemoryJournal.addEntry(persistenceId, 1, new SimpleReplicatedLogEntry(0, 1, new ServerConfigurationPayload(Arrays.asList(new ServerInfo(persistenceId, false)))));
    TestActorRef<MockRaftActor> raftActorRef = factory.createTestActor(MockRaftActor.builder().id(persistenceId).config(config).props().withDispatcher(Dispatchers.DefaultDispatcherId()), persistenceId);
    MockRaftActor mockRaftActor = raftActorRef.underlyingActor();
    mockRaftActor.waitForInitializeBehaviorComplete();
    // Sleep a bit and verify it didn't get an election timeout and schedule an election.
    Uninterruptibles.sleepUninterruptibly(400, TimeUnit.MILLISECONDS);
    assertEquals("getRaftState", RaftState.Follower, mockRaftActor.getRaftState());
    TEST_LOG.info("testNonVotingOnRecovery ending");
}
Also used : ServerConfigurationPayload(org.opendaylight.controller.cluster.raft.persisted.ServerConfigurationPayload) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ServerInfo(org.opendaylight.controller.cluster.raft.persisted.ServerInfo) ByteString(com.google.protobuf.ByteString) Test(org.junit.Test)

Example 3 with ServerInfo

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

the class ReplicationAndSnapshotsWithLaggingFollowerIntegrationTest method testLeaderSnapshotWithLaggingFollowerCaughtUpViaInstallSnapshot.

/**
 * Send payloads to trigger a leader snapshot due to snapshotBatchCount reached with follower 2
 * lagging where the leader trims its log from the last applied index. Follower 2's log
 * will be behind by several entries and, when it is resumed, it should be caught up via a snapshot
 * installed by the leader.
 */
@Test
public void testLeaderSnapshotWithLaggingFollowerCaughtUpViaInstallSnapshot() throws Exception {
    testLog.info("testLeaderSnapshotWithLaggingFollowerCaughtUpViaInstallSnapshot starting");
    setup();
    sendInitialPayloadsReplicatedToAllFollowers("zero", "one");
    // Configure follower 2 to drop messages and lag.
    follower2Actor.underlyingActor().startDropMessages(AppendEntries.class);
    // Sleep for at least the election timeout interval so follower 2 is deemed inactive by the leader.
    Uninterruptibles.sleepUninterruptibly(leaderConfigParams.getElectionTimeOutInterval().toMillis() + 5, TimeUnit.MILLISECONDS);
    // Send 5 payloads - the second should cause a leader snapshot.
    final MockPayload payload2 = sendPayloadData(leaderActor, "two");
    final MockPayload payload3 = sendPayloadData(leaderActor, "three");
    final MockPayload payload4 = sendPayloadData(leaderActor, "four");
    final MockPayload payload5 = sendPayloadData(leaderActor, "five");
    final MockPayload payload6 = sendPayloadData(leaderActor, "six");
    MessageCollectorActor.expectFirstMatching(leaderCollectorActor, SaveSnapshotSuccess.class);
    // Verify the leader got consensus and applies each log entry even though follower 2 didn't respond.
    List<ApplyState> applyStates = MessageCollectorActor.expectMatching(leaderCollectorActor, ApplyState.class, 5);
    verifyApplyState(applyStates.get(0), leaderCollectorActor, payload2.toString(), currentTerm, 2, payload2);
    verifyApplyState(applyStates.get(2), leaderCollectorActor, payload4.toString(), currentTerm, 4, payload4);
    verifyApplyState(applyStates.get(4), leaderCollectorActor, payload6.toString(), currentTerm, 6, payload6);
    MessageCollectorActor.clearMessages(leaderCollectorActor);
    testLog.info("testLeaderSnapshotWithLaggingFollowerCaughtUpViaInstallSnapshot: " + "sending 1 more payload to trigger second snapshot");
    // Send another payload to trigger a second leader snapshot.
    MockPayload payload7 = sendPayloadData(leaderActor, "seven");
    MessageCollectorActor.expectFirstMatching(leaderCollectorActor, SaveSnapshotSuccess.class);
    ApplyState applyState = MessageCollectorActor.expectFirstMatching(leaderCollectorActor, ApplyState.class);
    verifyApplyState(applyState, leaderCollectorActor, payload7.toString(), currentTerm, 7, payload7);
    // Verify follower 1 applies each log entry.
    applyStates = MessageCollectorActor.expectMatching(follower1CollectorActor, ApplyState.class, 6);
    verifyApplyState(applyStates.get(0), null, null, currentTerm, 2, payload2);
    verifyApplyState(applyStates.get(2), null, null, currentTerm, 4, payload4);
    verifyApplyState(applyStates.get(5), null, null, currentTerm, 7, payload7);
    // The snapshot should have caused the leader to advanced the snapshot index to the leader's last
    // applied index (6) since the log size should have exceed the snapshot batch count (4).
    // replicatedToAllIndex should remain at 1 since follower 2 is lagging.
    verifyLeadersTrimmedLog(7, 1);
    expSnapshotState.add(payload2);
    expSnapshotState.add(payload3);
    expSnapshotState.add(payload4);
    expSnapshotState.add(payload5);
    expSnapshotState.add(payload6);
    MessageCollectorActor.clearMessages(leaderCollectorActor);
    MessageCollectorActor.clearMessages(follower1CollectorActor);
    // Send a server config change to test that the install snapshot includes the server config.
    ServerConfigurationPayload serverConfig = new ServerConfigurationPayload(Arrays.asList(new ServerInfo(leaderId, true), new ServerInfo(follower1Id, false), new ServerInfo(follower2Id, false)));
    leaderContext.updatePeerIds(serverConfig);
    ((AbstractLeader) leader).updateMinReplicaCount();
    leaderActor.tell(serverConfig, ActorRef.noSender());
    applyState = MessageCollectorActor.expectFirstMatching(leaderCollectorActor, ApplyState.class);
    verifyApplyState(applyState, leaderCollectorActor, "serverConfig", currentTerm, 8, serverConfig);
    applyState = MessageCollectorActor.expectFirstMatching(follower1CollectorActor, ApplyState.class);
    verifyApplyState(applyState, null, null, currentTerm, 8, serverConfig);
    // Verify the leader's persisted snapshot.
    List<Snapshot> persistedSnapshots = InMemorySnapshotStore.getSnapshots(leaderId, Snapshot.class);
    assertEquals("Persisted snapshots size", 1, persistedSnapshots.size());
    verifySnapshot("Persisted", persistedSnapshots.get(0), currentTerm, 6, currentTerm, 7);
    List<ReplicatedLogEntry> unAppliedEntry = persistedSnapshots.get(0).getUnAppliedEntries();
    assertEquals("Persisted Snapshot getUnAppliedEntries size", 1, unAppliedEntry.size());
    verifyReplicatedLogEntry(unAppliedEntry.get(0), currentTerm, 7, payload7);
    expSnapshotState.add(payload7);
    verifyInstallSnapshotToLaggingFollower(8, serverConfig);
    testLog.info("testLeaderSnapshotWithLaggingFollowerCaughtUpViaInstallSnapshot complete");
}
Also used : CaptureSnapshot(org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot) ApplySnapshot(org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot) Snapshot(org.opendaylight.controller.cluster.raft.persisted.Snapshot) InstallSnapshot(org.opendaylight.controller.cluster.raft.messages.InstallSnapshot) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ServerConfigurationPayload(org.opendaylight.controller.cluster.raft.persisted.ServerConfigurationPayload) ServerInfo(org.opendaylight.controller.cluster.raft.persisted.ServerInfo) AbstractLeader(org.opendaylight.controller.cluster.raft.behaviors.AbstractLeader) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) ApplyState(org.opendaylight.controller.cluster.raft.base.messages.ApplyState) Test(org.junit.Test)

Example 4 with ServerInfo

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

the class RaftActorRecoverySupportTest method testOnSnapshotOfferWithServerConfiguration.

@Test
public void testOnSnapshotOfferWithServerConfiguration() {
    long electionTerm = 2;
    String electionVotedFor = "member-2";
    ServerConfigurationPayload serverPayload = new ServerConfigurationPayload(Arrays.asList(new ServerInfo(localId, true), new ServerInfo("follower1", true), new ServerInfo("follower2", true)));
    MockSnapshotState snapshotState = new MockSnapshotState(Arrays.asList(new MockPayload("1")));
    Snapshot snapshot = Snapshot.create(snapshotState, Collections.<ReplicatedLogEntry>emptyList(), -1, -1, -1, -1, electionTerm, electionVotedFor, serverPayload);
    SnapshotMetadata metadata = new SnapshotMetadata("test", 6, 12345);
    SnapshotOffer snapshotOffer = new SnapshotOffer(metadata, snapshot);
    sendMessageToSupport(snapshotOffer);
    assertEquals("Journal log size", 0, context.getReplicatedLog().size());
    assertEquals("Election term", electionTerm, context.getTermInformation().getCurrentTerm());
    assertEquals("Election votedFor", electionVotedFor, context.getTermInformation().getVotedFor());
    assertTrue("Dynamic server configuration", context.isDynamicServerConfigurationInUse());
    assertEquals("Peer List", Sets.newHashSet("follower1", "follower2"), Sets.newHashSet(context.getPeerIds()));
}
Also used : MockSnapshotState(org.opendaylight.controller.cluster.raft.MockRaftActor.MockSnapshotState) Snapshot(org.opendaylight.controller.cluster.raft.persisted.Snapshot) ServerConfigurationPayload(org.opendaylight.controller.cluster.raft.persisted.ServerConfigurationPayload) SnapshotMetadata(akka.persistence.SnapshotMetadata) ServerInfo(org.opendaylight.controller.cluster.raft.persisted.ServerInfo) SnapshotOffer(akka.persistence.SnapshotOffer) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) Test(org.junit.Test)

Example 5 with ServerInfo

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

the class RaftActorServerConfigurationSupportTest method testChangeToVotingWithNoLeaderAndOtherLeaderElected.

@Test
public void testChangeToVotingWithNoLeaderAndOtherLeaderElected() {
    LOG.info("testChangeToVotingWithNoLeaderAndOtherLeaderElected starting");
    DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
    configParams.setHeartBeatInterval(new FiniteDuration(100, TimeUnit.MILLISECONDS));
    configParams.setElectionTimeoutFactor(100000);
    final String node1ID = "node1";
    final String node2ID = "node2";
    configParams.setPeerAddressResolver(peerId -> peerId.equals(node1ID) ? actorFactory.createTestActorPath(node1ID) : peerId.equals(node2ID) ? actorFactory.createTestActorPath(node2ID) : null);
    ServerConfigurationPayload persistedServerConfig = new ServerConfigurationPayload(Arrays.asList(new ServerInfo(node1ID, false), new ServerInfo(node2ID, true)));
    SimpleReplicatedLogEntry persistedServerConfigEntry = new SimpleReplicatedLogEntry(0, 1, persistedServerConfig);
    InMemoryJournal.addEntry(node1ID, 1, new UpdateElectionTerm(1, "node1"));
    InMemoryJournal.addEntry(node1ID, 2, persistedServerConfigEntry);
    InMemoryJournal.addEntry(node2ID, 1, new UpdateElectionTerm(1, "node1"));
    InMemoryJournal.addEntry(node2ID, 2, persistedServerConfigEntry);
    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);
    final 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();
    // Send a ChangeServersVotingStatus message to node1 to change node1 to voting. This should cause
    // node1 to try to elect itself as leader in order to apply the new server config. But we'll drop
    // RequestVote messages in node2 and make it the leader so node1 should forward the server change
    // request to node2 when node2 is elected.
    node2RaftActor.setDropMessageOfType(RequestVote.class);
    ChangeServersVotingStatus changeServers = new ChangeServersVotingStatus(ImmutableMap.of(node1ID, true, node2ID, true));
    node1RaftActorRef.tell(changeServers, testKit.getRef());
    MessageCollectorActor.expectFirstMatching(node2Collector, RequestVote.class);
    node2RaftActorRef.tell(TimeoutNow.INSTANCE, ActorRef.noSender());
    ServerChangeReply reply = testKit.expectMsgClass(testKit.duration("5 seconds"), ServerChangeReply.class);
    assertEquals("getStatus", ServerChangeStatus.OK, reply.getStatus());
    MessageCollectorActor.expectFirstMatching(node1Collector, ApplyJournalEntries.class);
    verifyServerConfigurationPayloadEntry(node1RaftActor.getRaftActorContext().getReplicatedLog(), votingServer(node1ID), votingServer(node2ID));
    assertEquals("isVotingMember", true, node1RaftActor.getRaftActorContext().isVotingMember());
    assertEquals("getRaftState", RaftState.Follower, node1RaftActor.getRaftState());
    MessageCollectorActor.expectFirstMatching(node2Collector, ApplyJournalEntries.class);
    verifyServerConfigurationPayloadEntry(node2RaftActor.getRaftActorContext().getReplicatedLog(), votingServer(node1ID), votingServer(node2ID));
    assertEquals("getRaftState", RaftState.Leader, node2RaftActor.getRaftState());
    LOG.info("testChangeToVotingWithNoLeaderAndOtherLeaderElected ending");
}
Also used : ServerConfigurationPayload(org.opendaylight.controller.cluster.raft.persisted.ServerConfigurationPayload) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) ServerInfo(org.opendaylight.controller.cluster.raft.persisted.ServerInfo) ActorRef(akka.actor.ActorRef) TestActorRef(akka.testkit.TestActorRef) ChangeServersVotingStatus(org.opendaylight.controller.cluster.raft.messages.ChangeServersVotingStatus) FiniteDuration(scala.concurrent.duration.FiniteDuration) ServerChangeReply(org.opendaylight.controller.cluster.raft.messages.ServerChangeReply) UpdateElectionTerm(org.opendaylight.controller.cluster.raft.persisted.UpdateElectionTerm) Test(org.junit.Test)

Aggregations

ServerInfo (org.opendaylight.controller.cluster.raft.persisted.ServerInfo)23 ServerConfigurationPayload (org.opendaylight.controller.cluster.raft.persisted.ServerConfigurationPayload)21 Test (org.junit.Test)17 SimpleReplicatedLogEntry (org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry)13 UpdateElectionTerm (org.opendaylight.controller.cluster.raft.persisted.UpdateElectionTerm)7 FiniteDuration (scala.concurrent.duration.FiniteDuration)5 ActorRef (akka.actor.ActorRef)4 TestActorRef (akka.testkit.TestActorRef)4 ArrayList (java.util.ArrayList)4 CoreMatchers.containsString (org.hamcrest.CoreMatchers.containsString)4 ApplySnapshot (org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot)4 ApplyState (org.opendaylight.controller.cluster.raft.base.messages.ApplyState)4 ChangeServersVotingStatus (org.opendaylight.controller.cluster.raft.messages.ChangeServersVotingStatus)4 InstallSnapshot (org.opendaylight.controller.cluster.raft.messages.InstallSnapshot)4 ServerChangeReply (org.opendaylight.controller.cluster.raft.messages.ServerChangeReply)4 ApplyJournalEntries (org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries)3 Snapshot (org.opendaylight.controller.cluster.raft.persisted.Snapshot)3 Props (akka.actor.Props)2 UntypedActor (akka.actor.UntypedActor)2 Dispatchers (akka.dispatch.Dispatchers)2