Search in sources :

Example 1 with Follower

use of org.opendaylight.controller.cluster.raft.behaviors.Follower in project controller by opendaylight.

the class RaftActor method updateConfigParams.

protected void updateConfigParams(final ConfigParams configParams) {
    // obtain the RaftPolicy for oldConfigParams and the updated one.
    String oldRaftPolicy = context.getConfigParams().getCustomRaftPolicyImplementationClass();
    String newRaftPolicy = configParams.getCustomRaftPolicyImplementationClass();
    LOG.debug("{}: RaftPolicy used with prev.config {}, RaftPolicy used with newConfig {}", persistenceId(), oldRaftPolicy, newRaftPolicy);
    context.setConfigParams(configParams);
    if (!Objects.equals(oldRaftPolicy, newRaftPolicy)) {
        // The RaftPolicy was modified. If the current behavior is Follower then re-initialize to Follower
        // but transfer the previous leaderId so it doesn't immediately try to schedule an election. This
        // avoids potential disruption. Otherwise, switch to Follower normally.
        RaftActorBehavior behavior = getCurrentBehavior();
        if (behavior != null && behavior.state() == RaftState.Follower) {
            String previousLeaderId = behavior.getLeaderId();
            short previousLeaderPayloadVersion = behavior.getLeaderPayloadVersion();
            LOG.debug("{}: Re-initializing to Follower with previous leaderId {}", persistenceId(), previousLeaderId);
            changeCurrentBehavior(new Follower(context, previousLeaderId, previousLeaderPayloadVersion));
        } else {
            initializeBehavior();
        }
    }
}
Also used : RaftActorBehavior(org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior) AbstractRaftActorBehavior(org.opendaylight.controller.cluster.raft.behaviors.AbstractRaftActorBehavior) Follower(org.opendaylight.controller.cluster.raft.behaviors.Follower)

Example 2 with Follower

use of org.opendaylight.controller.cluster.raft.behaviors.Follower in project controller by opendaylight.

the class RaftActorServerConfigurationSupportTest method testAddServersAsNonVoting.

@Test
public void testAddServersAsNonVoting() throws Exception {
    LOG.info("testAddServersAsNonVoting starting");
    setupNewFollower();
    RaftActorContext initialActorContext = new MockRaftActorContext();
    TestActorRef<MockLeaderRaftActor> leaderActor = actorFactory.createTestActor(MockLeaderRaftActor.props(ImmutableMap.<String, String>of(), initialActorContext).withDispatcher(Dispatchers.DefaultDispatcherId()), actorFactory.generateActorId(LEADER_ID));
    MockLeaderRaftActor leaderRaftActor = leaderActor.underlyingActor();
    final RaftActorContext leaderActorContext = leaderRaftActor.getRaftActorContext();
    final ActorRef leaderCollectorActor = newLeaderCollectorActor(leaderRaftActor);
    leaderActor.tell(new AddServer(NEW_SERVER_ID, newFollowerRaftActor.path().toString(), false), testKit.getRef());
    AddServerReply addServerReply = testKit.expectMsgClass(testKit.duration("5 seconds"), AddServerReply.class);
    assertEquals("getStatus", ServerChangeStatus.OK, addServerReply.getStatus());
    assertEquals("getLeaderHint", LEADER_ID, addServerReply.getLeaderHint().get());
    // Verify ServerConfigurationPayload entry in leader's log
    expectFirstMatching(leaderCollectorActor, ApplyState.class);
    assertEquals("Leader journal last index", 0, leaderActorContext.getReplicatedLog().lastIndex());
    assertEquals("Leader commit index", 0, leaderActorContext.getCommitIndex());
    assertEquals("Leader last applied index", 0, leaderActorContext.getLastApplied());
    verifyServerConfigurationPayloadEntry(leaderActorContext.getReplicatedLog(), votingServer(LEADER_ID), nonVotingServer(NEW_SERVER_ID));
    // Verify ServerConfigurationPayload entry in the new follower
    expectFirstMatching(newFollowerCollectorActor, ApplyState.class);
    assertEquals("New follower journal last index", 0, newFollowerActorContext.getReplicatedLog().lastIndex());
    verifyServerConfigurationPayloadEntry(newFollowerActorContext.getReplicatedLog(), votingServer(LEADER_ID), nonVotingServer(NEW_SERVER_ID));
    // Verify new server config was applied in the new follower
    assertEquals("New follower peers", Sets.newHashSet(LEADER_ID), newFollowerActorContext.getPeerIds());
    assertNoneMatching(newFollowerCollectorActor, InstallSnapshot.class, 500);
    // Add another non-voting server.
    clearMessages(leaderCollectorActor);
    RaftActorContext follower2ActorContext = newFollowerContext(NEW_SERVER_ID2, followerActor);
    Follower newFollower2 = new Follower(follower2ActorContext);
    followerActor.underlyingActor().setBehavior(newFollower2);
    leaderActor.tell(new AddServer(NEW_SERVER_ID2, followerActor.path().toString(), false), testKit.getRef());
    addServerReply = testKit.expectMsgClass(testKit.duration("5 seconds"), AddServerReply.class);
    assertEquals("getStatus", ServerChangeStatus.OK, addServerReply.getStatus());
    assertEquals("getLeaderHint", java.util.Optional.of(LEADER_ID), addServerReply.getLeaderHint());
    expectFirstMatching(leaderCollectorActor, ApplyState.class);
    assertEquals("Leader journal last index", 1, leaderActorContext.getReplicatedLog().lastIndex());
    assertEquals("Leader commit index", 1, leaderActorContext.getCommitIndex());
    assertEquals("Leader last applied index", 1, leaderActorContext.getLastApplied());
    verifyServerConfigurationPayloadEntry(leaderActorContext.getReplicatedLog(), votingServer(LEADER_ID), nonVotingServer(NEW_SERVER_ID), nonVotingServer(NEW_SERVER_ID2));
    LOG.info("testAddServersAsNonVoting ending");
}
Also used : ActorRef(akka.actor.ActorRef) TestActorRef(akka.testkit.TestActorRef) Follower(org.opendaylight.controller.cluster.raft.behaviors.Follower) AddServerReply(org.opendaylight.controller.cluster.raft.messages.AddServerReply) AddServer(org.opendaylight.controller.cluster.raft.messages.AddServer) Test(org.junit.Test)

Example 3 with Follower

use of org.opendaylight.controller.cluster.raft.behaviors.Follower in project controller by opendaylight.

the class RaftActorServerConfigurationSupportTest method testAddServerWithLeaderChangeBeforePriorSnapshotComplete.

@Test
public void testAddServerWithLeaderChangeBeforePriorSnapshotComplete() throws Exception {
    LOG.info("testAddServerWithLeaderChangeBeforePriorSnapshotComplete starting");
    setupNewFollower();
    RaftActorContext initialActorContext = new MockRaftActorContext();
    TestActorRef<MockLeaderRaftActor> leaderActor = actorFactory.createTestActor(MockLeaderRaftActor.props(ImmutableMap.<String, String>of(), initialActorContext).withDispatcher(Dispatchers.DefaultDispatcherId()), actorFactory.generateActorId(LEADER_ID));
    MockLeaderRaftActor leaderRaftActor = leaderActor.underlyingActor();
    RaftActorContext leaderActorContext = leaderRaftActor.getRaftActorContext();
    ((DefaultConfigParamsImpl) leaderActorContext.getConfigParams()).setElectionTimeoutFactor(100);
    final ActorRef leaderCollectorActor = newLeaderCollectorActor(leaderRaftActor);
    // Drop the commit message so the snapshot doesn't complete yet.
    leaderRaftActor.setDropMessageOfType(COMMIT_MESSAGE_CLASS);
    leaderActor.tell(new InitiateCaptureSnapshot(), leaderActor);
    leaderActor.tell(new AddServer(NEW_SERVER_ID, newFollowerRaftActor.path().toString(), true), testKit.getRef());
    Object commitMsg = expectFirstMatching(leaderCollectorActor, COMMIT_MESSAGE_CLASS);
    // Change the leader behavior to follower
    leaderActor.tell(new Follower(leaderActorContext), leaderActor);
    // Drop CaptureSnapshotReply in case install snapshot is incorrectly initiated after the prior
    // snapshot completes. This will prevent the invalid snapshot from completing and fail the
    // isCapturing assertion below.
    leaderRaftActor.setDropMessageOfType(CaptureSnapshotReply.class);
    // Complete the prior snapshot - this should be a no-op b/c it's no longer the leader
    leaderActor.tell(commitMsg, leaderActor);
    leaderActor.tell(new RaftActorServerConfigurationSupport.ServerOperationTimeout(NEW_SERVER_ID), leaderActor);
    AddServerReply addServerReply = testKit.expectMsgClass(testKit.duration("5 seconds"), AddServerReply.class);
    assertEquals("getStatus", ServerChangeStatus.NO_LEADER, addServerReply.getStatus());
    assertEquals("Leader peers size", 0, leaderActorContext.getPeerIds().size());
    assertEquals("isCapturing", false, leaderActorContext.getSnapshotManager().isCapturing());
    LOG.info("testAddServerWithLeaderChangeBeforePriorSnapshotComplete ending");
}
Also used : InitiateCaptureSnapshot(org.opendaylight.controller.cluster.raft.base.messages.InitiateCaptureSnapshot) ActorRef(akka.actor.ActorRef) TestActorRef(akka.testkit.TestActorRef) Follower(org.opendaylight.controller.cluster.raft.behaviors.Follower) AddServer(org.opendaylight.controller.cluster.raft.messages.AddServer) AddServerReply(org.opendaylight.controller.cluster.raft.messages.AddServerReply) Test(org.junit.Test)

Example 4 with Follower

use of org.opendaylight.controller.cluster.raft.behaviors.Follower in project controller by opendaylight.

the class RaftActorServerConfigurationSupportTest method testAddServerWithOperationInProgress.

@Test
public void testAddServerWithOperationInProgress() throws Exception {
    LOG.info("testAddServerWithOperationInProgress starting");
    setupNewFollower();
    RaftActorContext initialActorContext = new MockRaftActorContext();
    TestActorRef<MockLeaderRaftActor> leaderActor = actorFactory.createTestActor(MockLeaderRaftActor.props(ImmutableMap.<String, String>of(), initialActorContext).withDispatcher(Dispatchers.DefaultDispatcherId()), actorFactory.generateActorId(LEADER_ID));
    MockLeaderRaftActor leaderRaftActor = leaderActor.underlyingActor();
    final RaftActorContext leaderActorContext = leaderRaftActor.getRaftActorContext();
    final ActorRef leaderCollectorActor = newLeaderCollectorActor(leaderRaftActor);
    RaftActorContext follower2ActorContext = newFollowerContext(NEW_SERVER_ID2, followerActor);
    Follower newFollower2 = new Follower(follower2ActorContext);
    followerActor.underlyingActor().setBehavior(newFollower2);
    MockNewFollowerRaftActor newFollowerRaftActorInstance = newFollowerRaftActor.underlyingActor();
    newFollowerRaftActorInstance.setDropMessageOfType(InstallSnapshot.class);
    leaderActor.tell(new AddServer(NEW_SERVER_ID, newFollowerRaftActor.path().toString(), true), testKit.getRef());
    // Wait for leader's install snapshot and capture it
    InstallSnapshot installSnapshot = expectFirstMatching(newFollowerCollectorActor, InstallSnapshot.class);
    // Send a second AddServer - should get queued
    TestKit testKit2 = new TestKit(getSystem());
    leaderActor.tell(new AddServer(NEW_SERVER_ID2, followerActor.path().toString(), false), testKit2.getRef());
    // Continue the first AddServer
    newFollowerRaftActorInstance.setDropMessageOfType(null);
    newFollowerRaftActor.tell(installSnapshot, leaderActor);
    // Verify both complete successfully
    AddServerReply addServerReply = testKit.expectMsgClass(testKit.duration("5 seconds"), AddServerReply.class);
    assertEquals("getStatus", ServerChangeStatus.OK, addServerReply.getStatus());
    addServerReply = testKit2.expectMsgClass(testKit2.duration("5 seconds"), AddServerReply.class);
    assertEquals("getStatus", ServerChangeStatus.OK, addServerReply.getStatus());
    // Verify ServerConfigurationPayload entries in leader's log
    expectMatching(leaderCollectorActor, ApplyState.class, 2);
    assertEquals("Leader journal last index", 1, leaderActorContext.getReplicatedLog().lastIndex());
    assertEquals("Leader commit index", 1, leaderActorContext.getCommitIndex());
    assertEquals("Leader last applied index", 1, leaderActorContext.getLastApplied());
    verifyServerConfigurationPayloadEntry(leaderActorContext.getReplicatedLog(), votingServer(LEADER_ID), votingServer(NEW_SERVER_ID), nonVotingServer(NEW_SERVER_ID2));
    // Verify ServerConfigurationPayload entry in the new follower
    expectMatching(newFollowerCollectorActor, ApplyState.class, 2);
    assertEquals("New follower peers", Sets.newHashSet(LEADER_ID, NEW_SERVER_ID2), newFollowerActorContext.getPeerIds());
    LOG.info("testAddServerWithOperationInProgress ending");
}
Also used : ActorRef(akka.actor.ActorRef) TestActorRef(akka.testkit.TestActorRef) Follower(org.opendaylight.controller.cluster.raft.behaviors.Follower) TestKit(akka.testkit.javadsl.TestKit) AddServerReply(org.opendaylight.controller.cluster.raft.messages.AddServerReply) AddServer(org.opendaylight.controller.cluster.raft.messages.AddServer) InstallSnapshot(org.opendaylight.controller.cluster.raft.messages.InstallSnapshot) Test(org.junit.Test)

Example 5 with Follower

use of org.opendaylight.controller.cluster.raft.behaviors.Follower in project controller by opendaylight.

the class RaftActorServerConfigurationSupportTest method testAddServerWithLeaderChangeDuringInstallSnapshot.

@Test
public void testAddServerWithLeaderChangeDuringInstallSnapshot() throws Exception {
    LOG.info("testAddServerWithLeaderChangeDuringInstallSnapshot starting");
    setupNewFollower();
    RaftActorContext initialActorContext = new MockRaftActorContext();
    TestActorRef<MockLeaderRaftActor> leaderActor = actorFactory.createTestActor(MockLeaderRaftActor.props(ImmutableMap.<String, String>of(), initialActorContext).withDispatcher(Dispatchers.DefaultDispatcherId()), actorFactory.generateActorId(LEADER_ID));
    MockLeaderRaftActor leaderRaftActor = leaderActor.underlyingActor();
    RaftActorContext leaderActorContext = leaderRaftActor.getRaftActorContext();
    ((DefaultConfigParamsImpl) leaderActorContext.getConfigParams()).setElectionTimeoutFactor(8);
    ActorRef leaderCollectorActor = newLeaderCollectorActor(leaderRaftActor);
    // Drop the UnInitializedFollowerSnapshotReply to delay it.
    leaderRaftActor.setDropMessageOfType(UnInitializedFollowerSnapshotReply.class);
    leaderActor.tell(new AddServer(NEW_SERVER_ID, newFollowerRaftActor.path().toString(), true), testKit.getRef());
    final UnInitializedFollowerSnapshotReply snapshotReply = expectFirstMatching(leaderCollectorActor, UnInitializedFollowerSnapshotReply.class);
    // Prevent election timeout when the leader switches to follower
    ((DefaultConfigParamsImpl) leaderActorContext.getConfigParams()).setElectionTimeoutFactor(100);
    // Change the leader behavior to follower
    leaderActor.tell(new Follower(leaderActorContext), leaderActor);
    // Send the captured UnInitializedFollowerSnapshotReply - should be a no-op
    leaderRaftActor.setDropMessageOfType(null);
    leaderActor.tell(snapshotReply, leaderActor);
    AddServerReply addServerReply = testKit.expectMsgClass(testKit.duration("5 seconds"), AddServerReply.class);
    assertEquals("getStatus", ServerChangeStatus.NO_LEADER, addServerReply.getStatus());
    assertEquals("Leader peers size", 0, leaderActorContext.getPeerIds().size());
    LOG.info("testAddServerWithLeaderChangeDuringInstallSnapshot ending");
}
Also used : ActorRef(akka.actor.ActorRef) TestActorRef(akka.testkit.TestActorRef) UnInitializedFollowerSnapshotReply(org.opendaylight.controller.cluster.raft.messages.UnInitializedFollowerSnapshotReply) Follower(org.opendaylight.controller.cluster.raft.behaviors.Follower) AddServerReply(org.opendaylight.controller.cluster.raft.messages.AddServerReply) AddServer(org.opendaylight.controller.cluster.raft.messages.AddServer) Test(org.junit.Test)

Aggregations

Follower (org.opendaylight.controller.cluster.raft.behaviors.Follower)8 ActorRef (akka.actor.ActorRef)7 TestActorRef (akka.testkit.TestActorRef)7 Test (org.junit.Test)7 AddServer (org.opendaylight.controller.cluster.raft.messages.AddServer)5 AddServerReply (org.opendaylight.controller.cluster.raft.messages.AddServerReply)5 ByteString (com.google.protobuf.ByteString)2 TestKit (akka.testkit.javadsl.TestKit)1 HashMap (java.util.HashMap)1 Matchers.anyObject (org.mockito.Matchers.anyObject)1 DataPersistenceProvider (org.opendaylight.controller.cluster.DataPersistenceProvider)1 LeaderStateChanged (org.opendaylight.controller.cluster.notifications.LeaderStateChanged)1 RoleChanged (org.opendaylight.controller.cluster.notifications.RoleChanged)1 MockPayload (org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload)1 ApplySnapshot (org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot)1 CaptureSnapshotReply (org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotReply)1 InitiateCaptureSnapshot (org.opendaylight.controller.cluster.raft.base.messages.InitiateCaptureSnapshot)1 AbstractRaftActorBehavior (org.opendaylight.controller.cluster.raft.behaviors.AbstractRaftActorBehavior)1 RaftActorBehavior (org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior)1 AppendEntries (org.opendaylight.controller.cluster.raft.messages.AppendEntries)1