Search in sources :

Example 41 with AppendEntriesReply

use of org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply in project controller by opendaylight.

the class LeaderTest method testHandleAppendEntriesReplyUnknownFollower.

@Test
public void testHandleAppendEntriesReplyUnknownFollower() {
    logStart("testHandleAppendEntriesReplyUnknownFollower");
    MockRaftActorContext leaderActorContext = createActorContext();
    leader = new Leader(leaderActorContext);
    AppendEntriesReply reply = new AppendEntriesReply("unkown-follower", 1, false, 10, 1, (short) 0);
    RaftActorBehavior raftActorBehavior = leader.handleAppendEntriesReply(followerActor, reply);
    assertEquals(RaftState.Leader, raftActorBehavior.state());
}
Also used : AppendEntriesReply(org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply) MockRaftActorContext(org.opendaylight.controller.cluster.raft.MockRaftActorContext) Test(org.junit.Test)

Example 42 with AppendEntriesReply

use of org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply in project controller by opendaylight.

the class LeaderTest method testHandleAppendEntriesReplyWithNewerTerm.

@Test
public void testHandleAppendEntriesReplyWithNewerTerm() {
    logStart("testHandleAppendEntriesReplyWithNewerTerm");
    MockRaftActorContext leaderActorContext = createActorContext();
    ((DefaultConfigParamsImpl) leaderActorContext.getConfigParams()).setHeartBeatInterval(new FiniteDuration(10000, TimeUnit.SECONDS));
    leaderActorContext.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().createEntries(0, 2, 2).build());
    leader = new Leader(leaderActorContext);
    leaderActor.underlyingActor().setBehavior(leader);
    leaderActor.tell(new AppendEntriesReply("foo", 20, false, 1000, 10, (short) 1), ActorRef.noSender());
    AppendEntriesReply appendEntriesReply = MessageCollectorActor.expectFirstMatching(leaderActor, AppendEntriesReply.class);
    assertEquals(false, appendEntriesReply.isSuccess());
    assertEquals(RaftState.Follower, leaderActor.underlyingActor().getFirstBehaviorChange().state());
    MessageCollectorActor.clearMessages(leaderActor);
}
Also used : AppendEntriesReply(org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply) MockRaftActorContext(org.opendaylight.controller.cluster.raft.MockRaftActorContext) FiniteDuration(scala.concurrent.duration.FiniteDuration) DefaultConfigParamsImpl(org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl) Test(org.junit.Test)

Example 43 with AppendEntriesReply

use of org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply in project controller by opendaylight.

the class LeaderTest method testReplicationWithPayloadSizeThatExceedsThreshold.

@Test
public void testReplicationWithPayloadSizeThatExceedsThreshold() {
    logStart("testReplicationWithPayloadSizeThatExceedsThreshold");
    final int serializedSize = SerializationUtils.serialize(new AppendEntries(1, LEADER_ID, -1, -1, Arrays.asList(new SimpleReplicatedLogEntry(0, 1, new MockRaftActorContext.MockPayload("large"))), 0, -1, (short) 0)).length;
    final MockRaftActorContext.MockPayload largePayload = new MockRaftActorContext.MockPayload("large", serializedSize);
    MockRaftActorContext leaderActorContext = createActorContextWithFollower();
    ((DefaultConfigParamsImpl) leaderActorContext.getConfigParams()).setHeartBeatInterval(new FiniteDuration(300, TimeUnit.MILLISECONDS));
    ((DefaultConfigParamsImpl) leaderActorContext.getConfigParams()).setSnapshotChunkSize(serializedSize - 50);
    leaderActorContext.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().build());
    leaderActorContext.setCommitIndex(-1);
    leaderActorContext.setLastApplied(-1);
    leader = new Leader(leaderActorContext);
    leaderActorContext.setCurrentBehavior(leader);
    // Send initial heartbeat reply so follower is marked active
    MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
    leader.handleMessage(followerActor, new AppendEntriesReply(FOLLOWER_ID, -1, true, -1, -1, (short) 0));
    MessageCollectorActor.clearMessages(followerActor);
    // Send normal payload first to prime commit index.
    final long term = leaderActorContext.getTermInformation().getCurrentTerm();
    sendReplicate(leaderActorContext, term, 0);
    AppendEntries appendEntries = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
    assertEquals("Entries size", 1, appendEntries.getEntries().size());
    assertEquals("Entry getIndex", 0, appendEntries.getEntries().get(0).getIndex());
    leader.handleMessage(followerActor, new AppendEntriesReply(FOLLOWER_ID, term, true, 0, term, (short) 0));
    assertEquals("getCommitIndex", 0, leaderActorContext.getCommitIndex());
    MessageCollectorActor.clearMessages(followerActor);
    // Now send a large payload that exceeds the maximum size for a single AppendEntries - it should be sliced.
    sendReplicate(leaderActorContext, term, 1, largePayload);
    MessageSlice messageSlice = MessageCollectorActor.expectFirstMatching(followerActor, MessageSlice.class);
    assertEquals("getSliceIndex", 1, messageSlice.getSliceIndex());
    assertEquals("getTotalSlices", 2, messageSlice.getTotalSlices());
    final Identifier slicingId = messageSlice.getIdentifier();
    appendEntries = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
    assertEquals("getPrevLogIndex", 0, appendEntries.getPrevLogIndex());
    assertEquals("getPrevLogTerm", term, appendEntries.getPrevLogTerm());
    assertEquals("getLeaderCommit", -1, appendEntries.getLeaderCommit());
    assertEquals("Entries size", 0, appendEntries.getEntries().size());
    MessageCollectorActor.clearMessages(followerActor);
    // Initiate a heartbeat - it should send an empty AppendEntries since slicing is in progress.
    // Sleep for the heartbeat interval so AppendEntries is sent.
    Uninterruptibles.sleepUninterruptibly(leaderActorContext.getConfigParams().getHeartBeatInterval().toMillis(), TimeUnit.MILLISECONDS);
    leader.handleMessage(leaderActor, SendHeartBeat.INSTANCE);
    appendEntries = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
    assertEquals("getLeaderCommit", -1, appendEntries.getLeaderCommit());
    assertEquals("Entries size", 0, appendEntries.getEntries().size());
    MessageCollectorActor.clearMessages(followerActor);
    // Simulate the MessageSliceReply's and AppendEntriesReply from the follower.
    leader.handleMessage(followerActor, MessageSliceReply.success(slicingId, 1, followerActor));
    messageSlice = MessageCollectorActor.expectFirstMatching(followerActor, MessageSlice.class);
    assertEquals("getSliceIndex", 2, messageSlice.getSliceIndex());
    leader.handleMessage(followerActor, MessageSliceReply.success(slicingId, 2, followerActor));
    leader.handleMessage(followerActor, new AppendEntriesReply(FOLLOWER_ID, term, true, 1, term, (short) 0));
    MessageCollectorActor.clearMessages(followerActor);
    // Send another normal payload.
    sendReplicate(leaderActorContext, term, 2);
    appendEntries = MessageCollectorActor.expectFirstMatching(followerActor, AppendEntries.class);
    assertEquals("Entries size", 1, appendEntries.getEntries().size());
    assertEquals("Entry getIndex", 2, appendEntries.getEntries().get(0).getIndex());
    assertEquals("getLeaderCommit", 1, appendEntries.getLeaderCommit());
}
Also used : MockRaftActorContext(org.opendaylight.controller.cluster.raft.MockRaftActorContext) FiniteDuration(scala.concurrent.duration.FiniteDuration) DefaultConfigParamsImpl(org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl) AppendEntries(org.opendaylight.controller.cluster.raft.messages.AppendEntries) Identifier(org.opendaylight.yangtools.concepts.Identifier) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) AppendEntriesReply(org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply) MessageSlice(org.opendaylight.controller.cluster.messaging.MessageSlice) Test(org.junit.Test)

Example 44 with AppendEntriesReply

use of org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply in project controller by opendaylight.

the class PartitionedLeadersElectionScenarioTest method resolvePartitionedLeadersWithLeaderMember3SendingHeartbeatFirst.

private void resolvePartitionedLeadersWithLeaderMember3SendingHeartbeatFirst() {
    testLog.info("resolvePartitionedLeadersWithLeaderMember3SendingHeartbeatFirst starting");
    // Re-establish connectivity between member 2 and 3, ie stop dropping messages between
    // the 2. Send heartbeats (AppendEntries) from now leader member 3. Both member 1 and 2 should send
    // back an unsuccessful AppendEntriesReply b/c their term (3) is greater than member 3's term (2).
    // This should cause member 3 to switch to Follower.
    member1Actor.clear();
    member1Actor.expectMessageClass(AppendEntries.class, 1);
    member2Actor.clear();
    member2Actor.expectMessageClass(AppendEntries.class, 1);
    member3Actor.clear();
    member3Actor.expectMessageClass(AppendEntriesReply.class, 1);
    sendHeartbeat(member3ActorRef);
    member3Actor.waitForExpectedMessages(AppendEntriesReply.class);
    AppendEntriesReply appendEntriesReply = member3Actor.getCapturedMessage(AppendEntriesReply.class);
    assertEquals("isSuccess", false, appendEntriesReply.isSuccess());
    assertEquals("getTerm", 3, appendEntriesReply.getTerm());
    verifyBehaviorState("member 1", member1Actor, RaftState.Follower);
    verifyBehaviorState("member 2", member2Actor, RaftState.Leader);
    verifyBehaviorState("member 3", member3Actor, RaftState.Follower);
    assertEquals("member 1 election term", 3, member1Context.getTermInformation().getCurrentTerm());
    assertEquals("member 2 election term", 3, member2Context.getTermInformation().getCurrentTerm());
    assertEquals("member 3 election term", 3, member3Context.getTermInformation().getCurrentTerm());
    testLog.info("resolvePartitionedLeadersWithLeaderMember3SendingHeartbeatFirst ending");
}
Also used : AppendEntriesReply(org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply)

Example 45 with AppendEntriesReply

use of org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply in project controller by opendaylight.

the class RaftActorTest method testFakeSnapshotsForLeaderWithInInitiateSnapshots.

@Test
public void testFakeSnapshotsForLeaderWithInInitiateSnapshots() throws Exception {
    final String persistenceId = factory.generateActorId("leader-");
    final String follower1Id = factory.generateActorId("follower-");
    final String follower2Id = factory.generateActorId("follower-");
    final ActorRef followerActor1 = factory.createActor(MessageCollectorActor.props(), follower1Id);
    final ActorRef followerActor2 = factory.createActor(MessageCollectorActor.props(), follower2Id);
    DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
    config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
    config.setIsolatedLeaderCheckInterval(new FiniteDuration(1, TimeUnit.DAYS));
    DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
    Map<String, String> peerAddresses = new HashMap<>();
    peerAddresses.put(follower1Id, followerActor1.path().toString());
    peerAddresses.put(follower2Id, followerActor2.path().toString());
    TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId, peerAddresses, config, dataPersistenceProvider), persistenceId);
    MockRaftActor leaderActor = mockActorRef.underlyingActor();
    leaderActor.getRaftActorContext().setCommitIndex(9);
    leaderActor.getRaftActorContext().setLastApplied(9);
    leaderActor.getRaftActorContext().getTermInformation().update(1, persistenceId);
    leaderActor.waitForInitializeBehaviorComplete();
    Leader leader = new Leader(leaderActor.getRaftActorContext());
    leaderActor.setCurrentBehavior(leader);
    assertEquals(RaftState.Leader, leaderActor.getCurrentBehavior().state());
    // create 5 entries in the log
    MockRaftActorContext.MockReplicatedLogBuilder logBuilder = new MockRaftActorContext.MockReplicatedLogBuilder();
    leaderActor.getRaftActorContext().setReplicatedLog(logBuilder.createEntries(5, 10, 1).build());
    // set the snapshot index to 4 , 0 to 4 are snapshotted
    leaderActor.getRaftActorContext().getReplicatedLog().setSnapshotIndex(4);
    // setting replicatedToAllIndex = 9, for the log to clear
    leader.setReplicatedToAllIndex(9);
    assertEquals(5, leaderActor.getReplicatedLog().size());
    assertEquals(RaftState.Leader, leaderActor.getCurrentBehavior().state());
    leaderActor.onReceiveCommand(new AppendEntriesReply(follower1Id, 1, true, 9, 1, (short) 0));
    assertEquals(5, leaderActor.getReplicatedLog().size());
    assertEquals(RaftState.Leader, leaderActor.getCurrentBehavior().state());
    // set the 2nd follower nextIndex to 1 which has been snapshotted
    leaderActor.onReceiveCommand(new AppendEntriesReply(follower2Id, 1, true, 0, 1, (short) 0));
    assertEquals(5, leaderActor.getReplicatedLog().size());
    assertEquals(RaftState.Leader, leaderActor.getCurrentBehavior().state());
    // simulate a real snapshot
    leaderActor.onReceiveCommand(SendHeartBeat.INSTANCE);
    assertEquals(5, leaderActor.getReplicatedLog().size());
    assertEquals(String.format("expected to be Leader but was %s. Current Leader = %s ", leaderActor.getCurrentBehavior().state(), leaderActor.getLeaderId()), RaftState.Leader, leaderActor.getCurrentBehavior().state());
    // reply from a slow follower does not initiate a fake snapshot
    leaderActor.onReceiveCommand(new AppendEntriesReply(follower2Id, 1, true, 9, 1, (short) 0));
    assertEquals("Fake snapshot should not happen when Initiate is in progress", 5, leaderActor.getReplicatedLog().size());
    ByteString snapshotBytes = fromObject(Arrays.asList(new MockRaftActorContext.MockPayload("foo-0"), new MockRaftActorContext.MockPayload("foo-1"), new MockRaftActorContext.MockPayload("foo-2"), new MockRaftActorContext.MockPayload("foo-3"), new MockRaftActorContext.MockPayload("foo-4")));
    leaderActor.onReceiveCommand(new CaptureSnapshotReply(ByteState.of(snapshotBytes.toByteArray()), java.util.Optional.empty()));
    assertTrue(leaderActor.getRaftActorContext().getSnapshotManager().isCapturing());
    assertEquals("Real snapshot didn't clear the log till replicatedToAllIndex", 0, leaderActor.getReplicatedLog().size());
    // reply from a slow follower after should not raise errors
    leaderActor.onReceiveCommand(new AppendEntriesReply(follower2Id, 1, true, 5, 1, (short) 0));
    assertEquals(0, leaderActor.getReplicatedLog().size());
}
Also used : CaptureSnapshotReply(org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotReply) Leader(org.opendaylight.controller.cluster.raft.behaviors.Leader) HashMap(java.util.HashMap) ActorRef(akka.actor.ActorRef) TestActorRef(akka.testkit.TestActorRef) ByteString(com.google.protobuf.ByteString) FiniteDuration(scala.concurrent.duration.FiniteDuration) ByteString(com.google.protobuf.ByteString) MockPayload(org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload) AppendEntriesReply(org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply) DataPersistenceProvider(org.opendaylight.controller.cluster.DataPersistenceProvider) Test(org.junit.Test)

Aggregations

AppendEntriesReply (org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply)57 Test (org.junit.Test)48 MockRaftActorContext (org.opendaylight.controller.cluster.raft.MockRaftActorContext)40 AppendEntries (org.opendaylight.controller.cluster.raft.messages.AppendEntries)34 FiniteDuration (scala.concurrent.duration.FiniteDuration)23 DefaultConfigParamsImpl (org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl)22 SimpleReplicatedLogEntry (org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry)17 ReplicatedLogEntry (org.opendaylight.controller.cluster.raft.ReplicatedLogEntry)15 ByteString (com.google.protobuf.ByteString)13 HashMap (java.util.HashMap)8 ActorRef (akka.actor.ActorRef)7 TestActorRef (akka.testkit.TestActorRef)6 InstallSnapshot (org.opendaylight.controller.cluster.raft.messages.InstallSnapshot)6 FollowerLogInformation (org.opendaylight.controller.cluster.raft.FollowerLogInformation)5 FollowerInitialSyncUpStatus (org.opendaylight.controller.cluster.raft.base.messages.FollowerInitialSyncUpStatus)5 AtomicReference (java.util.concurrent.atomic.AtomicReference)4 MockPayload (org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload)4 RaftActorLeadershipTransferCohort (org.opendaylight.controller.cluster.raft.RaftActorLeadershipTransferCohort)4 ApplySnapshot (org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot)4 ApplyState (org.opendaylight.controller.cluster.raft.base.messages.ApplyState)4