Search in sources :

Example 1 with RoleChanged

use of org.opendaylight.controller.cluster.notifications.RoleChanged in project controller by opendaylight.

the class RaftActorTest method testRaftRoleChangeNotifierWhenRaftActorHasPeers.

@Test
public void testRaftRoleChangeNotifierWhenRaftActorHasPeers() throws Exception {
    ActorRef notifierActor = factory.createActor(MessageCollectorActor.props());
    MessageCollectorActor.waitUntilReady(notifierActor);
    DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
    long heartBeatInterval = 100;
    config.setHeartBeatInterval(FiniteDuration.create(heartBeatInterval, TimeUnit.MILLISECONDS));
    config.setElectionTimeoutFactor(1);
    String persistenceId = factory.generateActorId("notifier-");
    factory.createActor(MockRaftActor.builder().id(persistenceId).peerAddresses(ImmutableMap.of("leader", "fake/path")).config(config).roleChangeNotifier(notifierActor).props());
    List<RoleChanged> matches = null;
    for (int i = 0; i < 5000 / heartBeatInterval; i++) {
        matches = MessageCollectorActor.getAllMatching(notifierActor, RoleChanged.class);
        assertNotNull(matches);
        if (matches.size() == 3) {
            break;
        }
        Uninterruptibles.sleepUninterruptibly(heartBeatInterval, TimeUnit.MILLISECONDS);
    }
    assertNotNull(matches);
    assertEquals(2, matches.size());
    // check if the notifier got a role change from null to Follower
    RoleChanged raftRoleChanged = matches.get(0);
    assertEquals(persistenceId, raftRoleChanged.getMemberId());
    assertNull(raftRoleChanged.getOldRole());
    assertEquals(RaftState.Follower.name(), raftRoleChanged.getNewRole());
    // check if the notifier got a role change from Follower to Candidate
    raftRoleChanged = matches.get(1);
    assertEquals(persistenceId, raftRoleChanged.getMemberId());
    assertEquals(RaftState.Follower.name(), raftRoleChanged.getOldRole());
    assertEquals(RaftState.Candidate.name(), raftRoleChanged.getNewRole());
}
Also used : ActorRef(akka.actor.ActorRef) TestActorRef(akka.testkit.TestActorRef) ByteString(com.google.protobuf.ByteString) RoleChanged(org.opendaylight.controller.cluster.notifications.RoleChanged) Test(org.junit.Test)

Example 2 with RoleChanged

use of org.opendaylight.controller.cluster.notifications.RoleChanged in project controller by opendaylight.

the class PreLeaderScenarioTest method testUnComittedEntryOnLeaderChange.

@Test
public void testUnComittedEntryOnLeaderChange() throws Exception {
    testLog.info("testUnComittedEntryOnLeaderChange starting");
    createRaftActors();
    // Drop AppendEntriesReply to the leader so it doesn't commit the payload entry.
    leaderActor.underlyingActor().startDropMessages(AppendEntriesReply.class);
    follower2Actor.underlyingActor().startDropMessages(AppendEntries.class);
    // Send a payload and verify AppendEntries is received in follower1.
    MockPayload payload0 = sendPayloadData(leaderActor, "zero");
    AppendEntries appendEntries = expectFirstMatching(follower1CollectorActor, AppendEntries.class);
    assertEquals("AppendEntries - # entries", 1, appendEntries.getEntries().size());
    verifyReplicatedLogEntry(appendEntries.getEntries().get(0), currentTerm, 0, payload0);
    // Kill the leader actor.
    killActor(leaderActor);
    // At this point, the payload entry is in follower1's log but is uncommitted. follower2 has not
    // received the payload entry yet.
    assertEquals("Follower 1 journal log size", 1, follower1Context.getReplicatedLog().size());
    assertEquals("Follower 1 journal last index", 0, follower1Context.getReplicatedLog().lastIndex());
    assertEquals("Follower 1 commit index", -1, follower1Context.getCommitIndex());
    assertEquals("Follower 1 last applied index", -1, follower1Context.getLastApplied());
    assertEquals("Follower 2 journal log size", 0, follower2Context.getReplicatedLog().size());
    follower2Actor.underlyingActor().stopDropMessages(AppendEntries.class);
    clearMessages(follower1NotifierActor);
    // Force follower1 to start an election. It should win since it's journal is more up-to-date than
    // follower2's journal.
    follower1Actor.tell(TimeoutNow.INSTANCE, ActorRef.noSender());
    // Verify the expected raft state changes. It should go to PreLeader since it has an uncommitted entry.
    List<RoleChanged> roleChange = expectMatching(follower1NotifierActor, RoleChanged.class, 3);
    assertEquals("Role change 1", RaftState.Candidate.name(), roleChange.get(0).getNewRole());
    assertEquals("Role change 2", RaftState.PreLeader.name(), roleChange.get(1).getNewRole());
    assertEquals("Role change 3", RaftState.Leader.name(), roleChange.get(2).getNewRole());
    final long previousTerm = currentTerm;
    currentTerm = follower1Context.getTermInformation().getCurrentTerm();
    // Since it went to Leader, it should've appended and successfully replicated a NoopPaylod with the
    // new term to follower2 and committed both entries, including the first payload from the previous term.
    assertEquals("Follower 1 journal log size", 2, follower1Context.getReplicatedLog().size());
    assertEquals("Follower 1 journal last index", 1, follower1Context.getReplicatedLog().lastIndex());
    assertEquals("Follower 1 commit index", 1, follower1Context.getCommitIndex());
    verifyReplicatedLogEntry(follower1Context.getReplicatedLog().get(0), previousTerm, 0, payload0);
    verifyReplicatedLogEntry(follower1Context.getReplicatedLog().get(1), currentTerm, 1, NoopPayload.INSTANCE);
    // Both entries should be applied to the state.
    expectMatching(follower1CollectorActor, ApplyState.class, 2);
    expectMatching(follower2CollectorActor, ApplyState.class, 2);
    assertEquals("Follower 1 last applied index", 1, follower1Context.getLastApplied());
    // Verify follower2's journal matches follower1's.
    assertEquals("Follower 2 journal log size", 2, follower2Context.getReplicatedLog().size());
    assertEquals("Follower 2 journal last index", 1, follower2Context.getReplicatedLog().lastIndex());
    assertEquals("Follower 2 commit index", 1, follower2Context.getCommitIndex());
    assertEquals("Follower 2 last applied index", 1, follower2Context.getLastApplied());
    verifyReplicatedLogEntry(follower2Context.getReplicatedLog().get(0), previousTerm, 0, payload0);
    verifyReplicatedLogEntry(follower2Context.getReplicatedLog().get(1), currentTerm, 1, NoopPayload.INSTANCE);
    // Reinstate follower1.
    killActor(follower1Actor);
    follower1Actor = newTestRaftActor(follower1Id, TestRaftActor.newBuilder().peerAddresses(ImmutableMap.of(leaderId, testActorPath(leaderId), follower2Id, testActorPath(follower2Id))).config(followerConfigParams));
    follower1Actor.underlyingActor().waitForRecoveryComplete();
    follower1Context = follower1Actor.underlyingActor().getRaftActorContext();
    // Verify follower1's journal was persisted and recovered correctly.
    assertEquals("Follower 1 journal log size", 2, follower1Context.getReplicatedLog().size());
    assertEquals("Follower 1 journal last index", 1, follower1Context.getReplicatedLog().lastIndex());
    assertEquals("Follower 1 commit index", 1, follower1Context.getCommitIndex());
    assertEquals("Follower 1 last applied index", 1, follower1Context.getLastApplied());
    verifyReplicatedLogEntry(follower1Context.getReplicatedLog().get(0), previousTerm, 0, payload0);
    verifyReplicatedLogEntry(follower1Context.getReplicatedLog().get(1), currentTerm, 1, NoopPayload.INSTANCE);
    testLog.info("testUnComittedEntryOnLeaderChange ending");
}
Also used : AppendEntries(org.opendaylight.controller.cluster.raft.messages.AppendEntries) RoleChanged(org.opendaylight.controller.cluster.notifications.RoleChanged) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) Test(org.junit.Test)

Example 3 with RoleChanged

use of org.opendaylight.controller.cluster.notifications.RoleChanged in project controller by opendaylight.

the class RaftActorTest method testRaftRoleChangeNotifierWhenRaftActorHasNoPeers.

@Test
public void testRaftRoleChangeNotifierWhenRaftActorHasNoPeers() throws Exception {
    ActorRef notifierActor = factory.createActor(MessageCollectorActor.props());
    MessageCollectorActor.waitUntilReady(notifierActor);
    DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
    long heartBeatInterval = 100;
    config.setHeartBeatInterval(FiniteDuration.create(heartBeatInterval, TimeUnit.MILLISECONDS));
    config.setElectionTimeoutFactor(20);
    String persistenceId = factory.generateActorId("notifier-");
    final TestActorRef<MockRaftActor> raftActorRef = factory.createTestActor(MockRaftActor.builder().id(persistenceId).config(config).roleChangeNotifier(notifierActor).dataPersistenceProvider(createProvider()).props().withDispatcher(Dispatchers.DefaultDispatcherId()), persistenceId);
    List<RoleChanged> matches = MessageCollectorActor.expectMatching(notifierActor, RoleChanged.class, 3);
    // check if the notifier got a role change from null to Follower
    RoleChanged raftRoleChanged = matches.get(0);
    assertEquals(persistenceId, raftRoleChanged.getMemberId());
    assertNull(raftRoleChanged.getOldRole());
    assertEquals(RaftState.Follower.name(), raftRoleChanged.getNewRole());
    // check if the notifier got a role change from Follower to Candidate
    raftRoleChanged = matches.get(1);
    assertEquals(persistenceId, raftRoleChanged.getMemberId());
    assertEquals(RaftState.Follower.name(), raftRoleChanged.getOldRole());
    assertEquals(RaftState.Candidate.name(), raftRoleChanged.getNewRole());
    // check if the notifier got a role change from Candidate to Leader
    raftRoleChanged = matches.get(2);
    assertEquals(persistenceId, raftRoleChanged.getMemberId());
    assertEquals(RaftState.Candidate.name(), raftRoleChanged.getOldRole());
    assertEquals(RaftState.Leader.name(), raftRoleChanged.getNewRole());
    LeaderStateChanged leaderStateChange = MessageCollectorActor.expectFirstMatching(notifierActor, LeaderStateChanged.class);
    assertEquals(raftRoleChanged.getMemberId(), leaderStateChange.getLeaderId());
    assertEquals(MockRaftActor.PAYLOAD_VERSION, leaderStateChange.getLeaderPayloadVersion());
    MessageCollectorActor.clearMessages(notifierActor);
    MockRaftActor raftActor = raftActorRef.underlyingActor();
    final String newLeaderId = "new-leader";
    final short newLeaderVersion = 6;
    Follower follower = new Follower(raftActor.getRaftActorContext()) {

        @Override
        public RaftActorBehavior handleMessage(final ActorRef sender, final Object message) {
            setLeaderId(newLeaderId);
            setLeaderPayloadVersion(newLeaderVersion);
            return this;
        }
    };
    raftActor.newBehavior(follower);
    leaderStateChange = MessageCollectorActor.expectFirstMatching(notifierActor, LeaderStateChanged.class);
    assertEquals(persistenceId, leaderStateChange.getMemberId());
    assertEquals(null, leaderStateChange.getLeaderId());
    raftRoleChanged = MessageCollectorActor.expectFirstMatching(notifierActor, RoleChanged.class);
    assertEquals(RaftState.Leader.name(), raftRoleChanged.getOldRole());
    assertEquals(RaftState.Follower.name(), raftRoleChanged.getNewRole());
    MessageCollectorActor.clearMessages(notifierActor);
    raftActor.handleCommand("any");
    leaderStateChange = MessageCollectorActor.expectFirstMatching(notifierActor, LeaderStateChanged.class);
    assertEquals(persistenceId, leaderStateChange.getMemberId());
    assertEquals(newLeaderId, leaderStateChange.getLeaderId());
    assertEquals(newLeaderVersion, leaderStateChange.getLeaderPayloadVersion());
    MessageCollectorActor.clearMessages(notifierActor);
    raftActor.handleCommand("any");
    Uninterruptibles.sleepUninterruptibly(505, TimeUnit.MILLISECONDS);
    leaderStateChange = MessageCollectorActor.getFirstMatching(notifierActor, LeaderStateChanged.class);
    assertNull(leaderStateChange);
}
Also used : ActorRef(akka.actor.ActorRef) TestActorRef(akka.testkit.TestActorRef) Follower(org.opendaylight.controller.cluster.raft.behaviors.Follower) Matchers.anyObject(org.mockito.Matchers.anyObject) ByteString(com.google.protobuf.ByteString) RoleChanged(org.opendaylight.controller.cluster.notifications.RoleChanged) LeaderStateChanged(org.opendaylight.controller.cluster.notifications.LeaderStateChanged) Test(org.junit.Test)

Example 4 with RoleChanged

use of org.opendaylight.controller.cluster.notifications.RoleChanged in project controller by opendaylight.

the class RaftActor method handleBehaviorChange.

private void handleBehaviorChange(final BehaviorState oldBehaviorState, final RaftActorBehavior currentBehavior) {
    RaftActorBehavior oldBehavior = oldBehaviorState.getBehavior();
    if (oldBehavior != currentBehavior) {
        onStateChanged();
    }
    String lastLeaderId = oldBehavior == null ? null : oldBehaviorState.getLastLeaderId();
    String lastValidLeaderId = oldBehavior == null ? null : oldBehaviorState.getLastValidLeaderId();
    String oldBehaviorStateName = oldBehavior == null ? null : oldBehavior.state().name();
    // it can happen that the state has not changed but the leader has changed.
    Optional<ActorRef> roleChangeNotifier = getRoleChangeNotifier();
    if (!Objects.equals(lastLeaderId, currentBehavior.getLeaderId()) || oldBehaviorState.getLeaderPayloadVersion() != currentBehavior.getLeaderPayloadVersion()) {
        if (roleChangeNotifier.isPresent()) {
            roleChangeNotifier.get().tell(newLeaderStateChanged(getId(), currentBehavior.getLeaderId(), currentBehavior.getLeaderPayloadVersion()), getSelf());
        }
        onLeaderChanged(lastValidLeaderId, currentBehavior.getLeaderId());
        RaftActorLeadershipTransferCohort leadershipTransferInProgress = context.getRaftActorLeadershipTransferCohort();
        if (leadershipTransferInProgress != null) {
            leadershipTransferInProgress.onNewLeader(currentBehavior.getLeaderId());
        }
        serverConfigurationSupport.onNewLeader(currentBehavior.getLeaderId());
    }
    if (roleChangeNotifier.isPresent() && (oldBehavior == null || oldBehavior.state() != currentBehavior.state())) {
        roleChangeNotifier.get().tell(new RoleChanged(getId(), oldBehaviorStateName, currentBehavior.state().name()), getSelf());
    }
}
Also used : ActorRef(akka.actor.ActorRef) RaftActorBehavior(org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior) AbstractRaftActorBehavior(org.opendaylight.controller.cluster.raft.behaviors.AbstractRaftActorBehavior) RoleChanged(org.opendaylight.controller.cluster.notifications.RoleChanged)

Example 5 with RoleChanged

use of org.opendaylight.controller.cluster.notifications.RoleChanged in project controller by opendaylight.

the class RoleChangeNotifierTest method testHandleRaftRoleChanged.

@Test
public void testHandleRaftRoleChanged() throws Exception {
    new TestKit(getSystem()) {

        {
            String memberId = "testHandleRegisterRoleChangeListenerWithNotificationSet";
            ActorRef listenerActor = getSystem().actorOf(MessageCollectorActor.props());
            ActorRef shardActor = getTestActor();
            TestActorRef<RoleChangeNotifier> notifierTestActorRef = TestActorRef.create(getSystem(), RoleChangeNotifier.getProps(memberId), memberId);
            notifierTestActorRef.tell(new RoleChanged(memberId, RaftState.Candidate.name(), RaftState.Leader.name()), shardActor);
            // no notification should be sent as listener has not yet
            // registered
            assertNull(MessageCollectorActor.getFirstMatching(listenerActor, RoleChangeNotification.class));
            // listener registers after role has been changed, ensure we
            // sent the latest role change after a reply
            notifierTestActorRef.tell(new RegisterRoleChangeListener(), listenerActor);
            RegisterRoleChangeListenerReply reply = MessageCollectorActor.getFirstMatching(listenerActor, RegisterRoleChangeListenerReply.class);
            assertNotNull(reply);
            RoleChangeNotification notification = MessageCollectorActor.getFirstMatching(listenerActor, RoleChangeNotification.class);
            assertNotNull(notification);
            assertEquals(RaftState.Candidate.name(), notification.getOldRole());
            assertEquals(RaftState.Leader.name(), notification.getNewRole());
        }
    };
}
Also used : RoleChangeNotifier(org.opendaylight.controller.cluster.notifications.RoleChangeNotifier) RegisterRoleChangeListener(org.opendaylight.controller.cluster.notifications.RegisterRoleChangeListener) TestActorRef(akka.testkit.TestActorRef) ActorRef(akka.actor.ActorRef) RoleChangeNotification(org.opendaylight.controller.cluster.notifications.RoleChangeNotification) RegisterRoleChangeListenerReply(org.opendaylight.controller.cluster.notifications.RegisterRoleChangeListenerReply) TestKit(akka.testkit.javadsl.TestKit) RoleChanged(org.opendaylight.controller.cluster.notifications.RoleChanged) Test(org.junit.Test)

Aggregations

RoleChanged (org.opendaylight.controller.cluster.notifications.RoleChanged)5 ActorRef (akka.actor.ActorRef)4 Test (org.junit.Test)4 TestActorRef (akka.testkit.TestActorRef)3 ByteString (com.google.protobuf.ByteString)2 TestKit (akka.testkit.javadsl.TestKit)1 Matchers.anyObject (org.mockito.Matchers.anyObject)1 LeaderStateChanged (org.opendaylight.controller.cluster.notifications.LeaderStateChanged)1 RegisterRoleChangeListener (org.opendaylight.controller.cluster.notifications.RegisterRoleChangeListener)1 RegisterRoleChangeListenerReply (org.opendaylight.controller.cluster.notifications.RegisterRoleChangeListenerReply)1 RoleChangeNotification (org.opendaylight.controller.cluster.notifications.RoleChangeNotification)1 RoleChangeNotifier (org.opendaylight.controller.cluster.notifications.RoleChangeNotifier)1 MockPayload (org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload)1 AbstractRaftActorBehavior (org.opendaylight.controller.cluster.raft.behaviors.AbstractRaftActorBehavior)1 Follower (org.opendaylight.controller.cluster.raft.behaviors.Follower)1 RaftActorBehavior (org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior)1 AppendEntries (org.opendaylight.controller.cluster.raft.messages.AppendEntries)1