use of org.neo4j.causalclustering.core.consensus.log.RaftLog in project neo4j by neo4j.
the class SegmentedRaftLogRotationTruncationPruneTest method shouldPruneAwaySingleEntriesIfRotationHappenedEveryEntry.
@Test
public void shouldPruneAwaySingleEntriesIfRotationHappenedEveryEntry() throws Exception {
/**
* If you have a raft log which rotates after every append, therefore having a single entry in every segment,
* we assert that every sequential prune attempt will result in the prevIndex incrementing by one.
*/
// given
RaftLog log = createRaftLog();
long term = 0;
for (int i = 0; i < 10; i++) {
log.append(new RaftLogEntry(term, valueOf(i)));
}
assertEquals(-1, log.prevIndex());
for (int i = 0; i < 9; i++) {
log.prune(i);
assertEquals(i, log.prevIndex());
}
log.prune(9);
assertEquals(8, log.prevIndex());
}
use of org.neo4j.causalclustering.core.consensus.log.RaftLog in project neo4j by neo4j.
the class SegmentedRaftLogRotationTruncationPruneTest method shouldPruneAwaySingleEntriesAfterTruncationIfRotationHappenedEveryEntry.
@Test
public void shouldPruneAwaySingleEntriesAfterTruncationIfRotationHappenedEveryEntry() throws Exception {
/**
* Given a log with many single-entry segments, a series of truncations at decending values followed by
* pruning at more previous segments will maintain the correct prevIndex for the log.
*
* Initial Scenario: [0][1][2][3][4][5][6][7][8][9] prevIndex = 0
* Truncate segment 9 : [0][1][2][3][4][5][6][7][8] (9) prevIndex = 0
* Truncate segment 8 : [0][1][2][3][4][5][6][7] (8)(9) prevIndex = 0
* Truncate segment 7 : [0][1][2][3][4][5][6] (7)(8)(9) prevIndex = 0
* Prune segment 0 : [1][2][3][4][5][6] (7)(8)(9) prevIndex = 1
* Prune segment 1 : [2][3][4][5][6] (7)(8)(9) prevIndex = 2
* Prune segment 2 : [3][4][5][6] (7)(8)(9) prevIndex = 3
* Prune segment 3 : [4][5][6] (7)(8)(9) prevIndex = 4
* Prune segment 4 : [5][6] (7)(8)(9) prevIndex = 5
* Prune segment 5 : [5][6] (7)(8)(9) prevIndex = 5
* Prune segment 6 : [5][6] (7)(8)(9) prevIndex = 5
* Etc...
*
* The prevIndex should not become corrupt and become greater than 5 in this example.
*/
// given
RaftLog log = createRaftLog();
long term = 0;
for (int i = 0; i < 10; i++) {
log.append(new RaftLogEntry(term, valueOf(i)));
}
log.truncate(9);
log.truncate(8);
log.truncate(7);
assertEquals(-1, log.prevIndex());
for (int i = 0; i <= 5; i++) {
log.prune(i);
assertEquals(i, log.prevIndex());
}
for (int i = 5; i < 10; i++) {
log.prune(i);
assertEquals(5, log.prevIndex());
}
}
use of org.neo4j.causalclustering.core.consensus.log.RaftLog in project neo4j by neo4j.
the class LeaderTest method leaderShouldSpawnMismatchCommandOnFailure.
// TODO: rethink this test, it does too much
@Test
public void leaderShouldSpawnMismatchCommandOnFailure() throws Exception {
// given
/*
* A leader who
* - has an append index of 100
* - knows about instance 2
* - assumes that instance 2 is fully caught up
*/
Leader leader = new Leader();
MemberId instance2 = member(2);
FollowerState instance2State = createArtificialFollowerState(100);
ReadableRaftState state = mock(ReadableRaftState.class);
FollowerStates<MemberId> followerState = new FollowerStates<>();
followerState = new FollowerStates<>(followerState, instance2, instance2State);
RaftLog log = new InMemoryRaftLog();
for (int i = 0; i <= 100; i++) {
log.append(new RaftLogEntry(0, valueOf(i)));
}
when(state.commitIndex()).thenReturn(-1L);
when(state.entryLog()).thenReturn(log);
when(state.followerStates()).thenReturn(followerState);
// both leader and follower are in the same term
when(state.term()).thenReturn(4L);
// when
// that leader is asked to handle a response from that follower that says that the follower is still missing
// things
RaftMessages.AppendEntries.Response response = appendEntriesResponse().failure().appendIndex(0).matchIndex(-1).term(4).from(instance2).build();
Outcome outcome = leader.handle(response, state, mock(Log.class));
// then
int mismatchCount = 0;
for (ShipCommand shipCommand : outcome.getShipCommands()) {
if (shipCommand instanceof ShipCommand.Mismatch) {
mismatchCount++;
}
}
assertThat(mismatchCount, greaterThan(0));
}
use of org.neo4j.causalclustering.core.consensus.log.RaftLog in project neo4j by neo4j.
the class FollowerTest method followerReceivingHeartbeatIndicatingClusterIsAheadShouldElicitAppendResponse.
@Test
public void followerReceivingHeartbeatIndicatingClusterIsAheadShouldElicitAppendResponse() throws Exception {
// given
int term = 1;
int followerAppendIndex = 9;
RaftLog entryLog = new InMemoryRaftLog();
entryLog.append(new RaftLogEntry(0, new RaftTestGroup(0)));
RaftState state = raftState().myself(myself).term(term).build();
Follower follower = new Follower();
appendSomeEntriesToLog(state, follower, followerAppendIndex - 1, term, 1);
AppendEntries.Request heartbeat = appendEntriesRequest().from(member1).leaderTerm(term).prevLogIndex(// leader has appended 2 ahead from this follower
followerAppendIndex + 2).prevLogTerm(// in the same term
term).build();
Outcome outcome = follower.handle(heartbeat, state, log());
assertEquals(1, outcome.getOutgoingMessages().size());
RaftMessage outgoing = outcome.getOutgoingMessages().iterator().next().message();
assertEquals(RaftMessages.Type.APPEND_ENTRIES_RESPONSE, outgoing.type());
RaftMessages.AppendEntries.Response response = (AppendEntries.Response) outgoing;
assertFalse(response.success());
}
use of org.neo4j.causalclustering.core.consensus.log.RaftLog in project neo4j by neo4j.
the class FollowerTest method shouldTruncateIfTermDoesNotMatch.
@Test
public void shouldTruncateIfTermDoesNotMatch() throws Exception {
// given
RaftLog entryLog = new InMemoryRaftLog();
entryLog.append(new RaftLogEntry(0, new RaftTestGroup(0)));
int term = 1;
RaftState state = raftState().myself(myself).entryLog(entryLog).term(term).build();
Follower follower = new Follower();
state.update(follower.handle(new AppendEntries.Request(member1, 1, 0, 0, new RaftLogEntry[] { new RaftLogEntry(2, ContentGenerator.content()) }, 0), state, log()));
RaftLogEntry[] entries = { new RaftLogEntry(1, new ReplicatedString("commit this!")) };
Outcome outcome = follower.handle(new AppendEntries.Request(member1, 1, 0, 0, entries, 0), state, log());
state.update(outcome);
// then
assertEquals(1, state.entryLog().appendIndex());
assertEquals(1, state.entryLog().readEntryTerm(1));
}
Aggregations