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());
}
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());
}
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());
}
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");
}
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());
}
Aggregations