Search in sources :

Example 41 with SimpleReplicatedLogEntry

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

the class SnapshotManagerTest method testIllegalCapture.

@SuppressWarnings("unchecked")
@Test
public void testIllegalCapture() throws Exception {
    boolean capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1, new MockRaftActorContext.MockPayload()), 9);
    assertTrue(capture);
    verify(mockProcedure).accept(anyObject());
    reset(mockProcedure);
    // This will not cause snapshot capture to start again
    capture = snapshotManager.capture(new SimpleReplicatedLogEntry(9, 1, new MockRaftActorContext.MockPayload()), 9);
    assertFalse(capture);
    verify(mockProcedure, never()).accept(anyObject());
}
Also used : SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) Test(org.junit.Test)

Example 42 with SimpleReplicatedLogEntry

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

the class SnapshotManagerTest method testLastAppliedTermInformationReader.

@Test
public void testLastAppliedTermInformationReader() {
    LastAppliedTermInformationReader reader = new LastAppliedTermInformationReader();
    doReturn(4L).when(mockReplicatedLog).getSnapshotTerm();
    doReturn(7L).when(mockReplicatedLog).getSnapshotIndex();
    ReplicatedLogEntry lastLogEntry = new SimpleReplicatedLogEntry(9L, 6L, new MockRaftActorContext.MockPayload());
    // No followers and valid lastLogEntry
    reader.init(mockReplicatedLog, 1L, lastLogEntry, false);
    assertEquals("getTerm", 6L, reader.getTerm());
    assertEquals("getIndex", 9L, reader.getIndex());
    // No followers and null lastLogEntry
    reader.init(mockReplicatedLog, 1L, null, false);
    assertEquals("getTerm", -1L, reader.getTerm());
    assertEquals("getIndex", -1L, reader.getIndex());
    // Followers and valid originalIndex entry
    doReturn(new SimpleReplicatedLogEntry(8L, 5L, new MockRaftActorContext.MockPayload())).when(mockReplicatedLog).get(8L);
    reader.init(mockReplicatedLog, 8L, lastLogEntry, true);
    assertEquals("getTerm", 5L, reader.getTerm());
    assertEquals("getIndex", 8L, reader.getIndex());
    // Followers and null originalIndex entry and valid snapshot index
    reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
    assertEquals("getTerm", 4L, reader.getTerm());
    assertEquals("getIndex", 7L, reader.getIndex());
    // Followers and null originalIndex entry and invalid snapshot index
    doReturn(-1L).when(mockReplicatedLog).getSnapshotIndex();
    reader.init(mockReplicatedLog, 7L, lastLogEntry, true);
    assertEquals("getTerm", -1L, reader.getTerm());
    assertEquals("getIndex", -1L, reader.getIndex());
}
Also used : LastAppliedTermInformationReader(org.opendaylight.controller.cluster.raft.SnapshotManager.LastAppliedTermInformationReader) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry) Test(org.junit.Test)

Example 43 with SimpleReplicatedLogEntry

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

the class MockRaftActorContext method initReplicatedLog.

public void initReplicatedLog() {
    SimpleReplicatedLog replicatedLog = new SimpleReplicatedLog();
    long term = getTermInformation().getCurrentTerm();
    replicatedLog.append(new SimpleReplicatedLogEntry(0, term, new MockPayload("1")));
    replicatedLog.append(new SimpleReplicatedLogEntry(1, term, new MockPayload("2")));
    setReplicatedLog(replicatedLog);
    setCommitIndex(replicatedLog.lastIndex());
    setLastApplied(replicatedLog.lastIndex());
}
Also used : SimpleReplicatedLogEntry(org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry)

Example 44 with SimpleReplicatedLogEntry

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

the class NonVotingFollowerIntegrationTest method testFollowerResyncWithMoreLeaderLogEntriesAndDownPeerAfterNonPersistentLeaderRestart.

/**
 * Tests non-voting follower re-sync after the non-persistent leader restarts and commits new log
 * entries prior to re-connecting to the follower. The leader's last index will be greater than the
 * follower's last index corresponding to the previous data retained in memory. So the follower's log
 * will be behind the leader's log but the leader's log entries will have a higher term. It also adds a
 * "down" peer on restart so the leader doesn't trim its log as it's trying to resync the follower.
 * Eventually the follower should force the leader to install snapshot to re-sync its state.
 */
@Test
public void testFollowerResyncWithMoreLeaderLogEntriesAndDownPeerAfterNonPersistentLeaderRestart() {
    testLog.info("testFollowerResyncWithMoreLeaderLogEntriesAndDownPeerAfterNonPersistentLeaderRestart starting");
    setupLeaderAndNonVotingFollower();
    // Add log entries and verify they are committed and applied by both nodes.
    expSnapshotState.add(sendPayloadData(leaderActor, "zero"));
    expSnapshotState.add(sendPayloadData(leaderActor, "one"));
    expSnapshotState.add(sendPayloadData(leaderActor, "two"));
    MessageCollectorActor.expectMatching(leaderCollectorActor, ApplyState.class, expSnapshotState.size());
    MessageCollectorActor.expectMatching(follower1CollectorActor, ApplyState.class, expSnapshotState.size());
    long lastIndex = 2;
    assertEquals("Leader journal lastIndex", lastIndex, leaderContext.getReplicatedLog().lastIndex());
    assertEquals("Leader commit index", lastIndex, leaderContext.getCommitIndex());
    assertEquals("Follower journal lastIndex", lastIndex, follower1Context.getReplicatedLog().lastIndex());
    assertEquals("Follower commit index", lastIndex, follower1Context.getCommitIndex());
    assertEquals("Follower applied state", expSnapshotState, followerInstance.getState());
    MessageCollectorActor.clearMessages(follower1CollectorActor);
    MessageCollectorActor.expectFirstMatching(follower1CollectorActor, AppendEntries.class);
    assertEquals("Follower snapshot index", lastIndex - 1, follower1Context.getReplicatedLog().getSnapshotIndex());
    assertEquals("Follower journal size", 1, leaderContext.getReplicatedLog().size());
    // Restart the leader
    killActor(leaderActor);
    MessageCollectorActor.clearMessages(follower1CollectorActor);
    // Temporarily drop AppendEntries to simulate a disconnect when the leader restarts.
    followerInstance.startDropMessages(AppendEntries.class);
    // Add a "down" peer so the leader doesn't trim its log as it's trying to resync the follower. The
    // leader will keep decrementing the follower's nextIndex to try to find a matching index. Since
    // there is no matching index it will eventually hit index 0 which should cause the follower to
    // force an install snapshot upon failure to remove the conflicting indexes due to indexes 0 and 1
    // being in the prior snapshot and not the log.
    // 
    // We also add another voting follower actor into the mix even though it shoildn't affect the
    // outcome.
    ServerConfigurationPayload persistedServerConfig = new ServerConfigurationPayload(Arrays.asList(new ServerInfo(leaderId, true), new ServerInfo(follower1Id, false), new ServerInfo(follower2Id, true), new ServerInfo("downPeer", false)));
    SimpleReplicatedLogEntry persistedServerConfigEntry = new SimpleReplicatedLogEntry(0, currentTerm, persistedServerConfig);
    InMemoryJournal.clear();
    InMemoryJournal.addEntry(leaderId, 1, new UpdateElectionTerm(currentTerm, leaderId));
    InMemoryJournal.addEntry(leaderId, 2, persistedServerConfigEntry);
    InMemoryJournal.addEntry(follower2Id, 1, persistedServerConfigEntry);
    DefaultConfigParamsImpl follower2ConfigParams = newFollowerConfigParams();
    follower2ConfigParams.setCustomRaftPolicyImplementationClass(DisableElectionsRaftPolicy.class.getName());
    follower2Actor = newTestRaftActor(follower2Id, TestRaftActor.newBuilder().peerAddresses(ImmutableMap.of(leaderId, testActorPath(leaderId), follower1Id, follower1Actor.path().toString())).config(follower2ConfigParams).persistent(Optional.of(false)));
    TestRaftActor follower2Instance = follower2Actor.underlyingActor();
    follower2Instance.waitForRecoveryComplete();
    follower2CollectorActor = follower2Instance.collectorActor();
    peerAddresses = ImmutableMap.of(follower1Id, follower1Actor.path().toString(), follower2Id, follower2Actor.path().toString());
    createNewLeaderActor();
    currentTerm++;
    assertEquals("Leader term", currentTerm, leaderContext.getTermInformation().getCurrentTerm());
    assertEquals("Leader journal lastIndex", -1, leaderContext.getReplicatedLog().lastIndex());
    assertEquals("Leader commit index", -1, leaderContext.getCommitIndex());
    // Add new log entries to the leader - several more than the prior log entries
    expSnapshotState.add(sendPayloadData(leaderActor, "zero-1"));
    expSnapshotState.add(sendPayloadData(leaderActor, "one-1"));
    expSnapshotState.add(sendPayloadData(leaderActor, "two-1"));
    expSnapshotState.add(sendPayloadData(leaderActor, "three-1"));
    expSnapshotState.add(sendPayloadData(leaderActor, "four-1"));
    MessageCollectorActor.expectMatching(leaderCollectorActor, ApplyState.class, expSnapshotState.size());
    MessageCollectorActor.expectMatching(follower2CollectorActor, ApplyState.class, expSnapshotState.size());
    lastIndex = 4;
    assertEquals("Leader journal lastIndex", lastIndex, leaderContext.getReplicatedLog().lastIndex());
    assertEquals("Leader commit index", lastIndex, leaderContext.getCommitIndex());
    assertEquals("Leader snapshot index", -1, leaderContext.getReplicatedLog().getSnapshotIndex());
    assertEquals("Leader replicatedToAllIndex", -1, leaderInstance.getCurrentBehavior().getReplicatedToAllIndex());
    // Re-enable AppendEntries to the follower. The follower's log will be out of sync and it should
    // should force the leader to install snapshot to re-sync the entire follower's log and state.
    followerInstance.stopDropMessages(AppendEntries.class);
    MessageCollectorActor.expectFirstMatching(follower1CollectorActor, SnapshotComplete.class);
    assertEquals("Follower term", currentTerm, follower1Context.getTermInformation().getCurrentTerm());
    assertEquals("Follower journal lastIndex", lastIndex, follower1Context.getReplicatedLog().lastIndex());
    assertEquals("Follower journal lastTerm", currentTerm, follower1Context.getReplicatedLog().lastTerm());
    assertEquals("Follower commit index", lastIndex, follower1Context.getCommitIndex());
    assertEquals("Follower applied state", expSnapshotState, followerInstance.getState());
    testLog.info("testFollowerResyncWithMoreLeaderLogEntriesAndDownPeerAfterNonPersistentLeaderRestart 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) DisableElectionsRaftPolicy(org.opendaylight.controller.cluster.raft.policy.DisableElectionsRaftPolicy) UpdateElectionTerm(org.opendaylight.controller.cluster.raft.persisted.UpdateElectionTerm) Test(org.junit.Test)

Example 45 with SimpleReplicatedLogEntry

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

the class NonVotingFollowerIntegrationTest method setupLeaderAndNonVotingFollower.

private void setupLeaderAndNonVotingFollower() {
    snapshotBatchCount = 100;
    int persistedTerm = 1;
    // Set up a persisted ServerConfigurationPayload with the leader voting and the follower non-voting.
    ServerConfigurationPayload persistedServerConfig = new ServerConfigurationPayload(Arrays.asList(new ServerInfo(leaderId, true), new ServerInfo(follower1Id, false)));
    SimpleReplicatedLogEntry persistedServerConfigEntry = new SimpleReplicatedLogEntry(0, persistedTerm, persistedServerConfig);
    InMemoryJournal.addEntry(leaderId, 1, new UpdateElectionTerm(persistedTerm, leaderId));
    InMemoryJournal.addEntry(leaderId, 2, persistedServerConfigEntry);
    InMemoryJournal.addEntry(follower1Id, 1, new UpdateElectionTerm(persistedTerm, leaderId));
    InMemoryJournal.addEntry(follower1Id, 2, persistedServerConfigEntry);
    DefaultConfigParamsImpl followerConfigParams = newFollowerConfigParams();
    follower1Actor = newTestRaftActor(follower1Id, follower1Builder.peerAddresses(ImmutableMap.of(leaderId, testActorPath(leaderId))).config(followerConfigParams).persistent(Optional.of(false)));
    peerAddresses = ImmutableMap.<String, String>builder().put(follower1Id, follower1Actor.path().toString()).build();
    leaderConfigParams = newLeaderConfigParams();
    leaderActor = newTestRaftActor(leaderId, TestRaftActor.newBuilder().peerAddresses(peerAddresses).config(leaderConfigParams).persistent(Optional.of(false)));
    followerInstance = follower1Actor.underlyingActor();
    follower1CollectorActor = followerInstance.collectorActor();
    leaderInstance = leaderActor.underlyingActor();
    leaderCollectorActor = leaderInstance.collectorActor();
    leaderContext = leaderInstance.getRaftActorContext();
    follower1Context = followerInstance.getRaftActorContext();
    waitUntilLeader(leaderActor);
    // Verify leader's context after startup
    currentTerm = persistedTerm + 1;
    assertEquals("Leader term", currentTerm, leaderContext.getTermInformation().getCurrentTerm());
    assertEquals("Leader server config", Sets.newHashSet(persistedServerConfig.getServerConfig()), Sets.newHashSet(leaderContext.getPeerServerInfo(true).getServerConfig()));
    assertEquals("Leader isVotingMember", true, leaderContext.isVotingMember());
    // Verify follower's context after startup
    MessageCollectorActor.expectFirstMatching(follower1CollectorActor, AppendEntries.class);
    assertEquals("Follower term", currentTerm, follower1Context.getTermInformation().getCurrentTerm());
    assertEquals("Follower server config", Sets.newHashSet(persistedServerConfig.getServerConfig()), Sets.newHashSet(follower1Context.getPeerServerInfo(true).getServerConfig()));
    assertEquals("FollowerisVotingMember", false, follower1Context.isVotingMember());
}
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) UpdateElectionTerm(org.opendaylight.controller.cluster.raft.persisted.UpdateElectionTerm)

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