use of org.neo4j.causalclustering.core.consensus.log.RaftLogEntry in project neo4j by neo4j.
the class CommandApplicationProcessTest method shouldApplyCommittedCommand.
@Test
public void shouldApplyCommittedCommand() throws Throwable {
// given
RaftLogCommitIndexMonitor listener = mock(RaftLogCommitIndexMonitor.class);
monitors.addMonitorListener(listener);
applicationProcess.start();
InOrder inOrder = inOrder(coreStateMachines, commandDispatcher);
// when
raftLog.append(new RaftLogEntry(0, operation(nullTx)));
raftLog.append(new RaftLogEntry(0, operation(nullTx)));
raftLog.append(new RaftLogEntry(0, operation(nullTx)));
applicationProcess.notifyCommitted(2);
applier.sync(false);
// then
inOrder.verify(coreStateMachines).commandDispatcher();
inOrder.verify(commandDispatcher).dispatch(eq(nullTx), eq(0L), anyCallback());
inOrder.verify(commandDispatcher).dispatch(eq(nullTx), eq(1L), anyCallback());
inOrder.verify(commandDispatcher).dispatch(eq(nullTx), eq(2L), anyCallback());
inOrder.verify(commandDispatcher).close();
verify(listener).commitIndex(2);
}
use of org.neo4j.causalclustering.core.consensus.log.RaftLogEntry in project neo4j by neo4j.
the class CommandApplicationProcessTest method shouldNotApplyUncommittedCommands.
@Test
public void shouldNotApplyUncommittedCommands() throws Throwable {
// given
applicationProcess.start();
// when
raftLog.append(new RaftLogEntry(0, operation(nullTx)));
raftLog.append(new RaftLogEntry(0, operation(nullTx)));
applicationProcess.notifyCommitted(-1);
applier.sync(false);
// then
verifyZeroInteractions(commandDispatcher);
}
use of org.neo4j.causalclustering.core.consensus.log.RaftLogEntry in project neo4j by neo4j.
the class CommandApplicationProcessTest method duplicatesShouldBeIgnoredButStillIncreaseCommandIndex.
@Test
public void duplicatesShouldBeIgnoredButStillIncreaseCommandIndex() throws Exception {
// given
applicationProcess.start();
// when
raftLog.append(new RaftLogEntry(0, new NewLeaderBarrier()));
raftLog.append(new RaftLogEntry(0, new DistributedOperation(nullTx, globalSession, new LocalOperationId(0, 0))));
// duplicate
raftLog.append(new RaftLogEntry(0, new DistributedOperation(nullTx, globalSession, new LocalOperationId(0, 0))));
raftLog.append(new RaftLogEntry(0, new DistributedOperation(nullTx, globalSession, new LocalOperationId(0, 1))));
applicationProcess.notifyCommitted(3);
applier.sync(false);
InOrder inOrder = inOrder(coreStateMachines, commandDispatcher);
// then
inOrder.verify(coreStateMachines).commandDispatcher();
inOrder.verify(commandDispatcher).dispatch(eq(nullTx), eq(1L), anyCallback());
// duplicate not dispatched
inOrder.verify(commandDispatcher).dispatch(eq(nullTx), eq(3L), anyCallback());
inOrder.verify(commandDispatcher).close();
verifyNoMoreInteractions(commandDispatcher);
}
use of org.neo4j.causalclustering.core.consensus.log.RaftLogEntry in project neo4j by neo4j.
the class CommandApplicationProcessTest method shouldFallbackToLogCursorOnCacheMiss.
@Test
public void shouldFallbackToLogCursorOnCacheMiss() throws Throwable {
// if the cache does not contain all things to be applied, make sure we fall back to the log
// should only happen in recovery, otherwise this is probably a bug.
applicationProcess.start();
//given cache with missing entry
ReplicatedContent operation0 = operation(nullTx);
ReplicatedContent operation1 = operation(nullTx);
ReplicatedContent operation2 = operation(nullTx);
inFlightMap.put(0L, new RaftLogEntry(0, operation0));
inFlightMap.put(2L, new RaftLogEntry(2, operation2));
raftLog.append(new RaftLogEntry(0, operation0));
raftLog.append(new RaftLogEntry(1, operation1));
raftLog.append(new RaftLogEntry(2, operation2));
//when
applicationProcess.notifyCommitted(2);
applier.sync(false);
//then the cache stops being used after it finds 1 is missing
verify(inFlightMap, times(1)).get(0L);
verify(inFlightMap, times(1)).get(1L);
verify(inFlightMap, times(0)).get(2L);
// we only look up 1 so let's remove that from the cache
verify(inFlightMap, times(1)).remove(0L);
verify(commandDispatcher, times(1)).dispatch(eq(nullTx), eq(0L), anyCallback());
verify(commandDispatcher, times(1)).dispatch(eq(nullTx), eq(1L), anyCallback());
verify(commandDispatcher, times(1)).dispatch(eq(nullTx), eq(2L), anyCallback());
verify(raftLog, times(1)).getEntryCursor(1);
}
use of org.neo4j.causalclustering.core.consensus.log.RaftLogEntry in project neo4j by neo4j.
the class CommandApplicationProcess method submitApplyJob.
private void submitApplyJob(long lastToApply) {
boolean success = applier.submit((status) -> () -> {
final long snapshotLastSeenCommitIndex = this.lastSeenCommitIndex;
try (InFlightLogEntryReader logEntrySupplier = new InFlightLogEntryReader(raftLog, inFlightMap, true)) {
for (long logIndex = lastApplied + 1; !status.isCancelled() && logIndex <= snapshotLastSeenCommitIndex; logIndex++) {
RaftLogEntry entry = logEntrySupplier.get(logIndex);
if (entry == null) {
throw new IllegalStateException(format("Committed log %d entry must exist.", logIndex));
}
if (entry.content() instanceof DistributedOperation) {
DistributedOperation distributedOperation = (DistributedOperation) entry.content();
progressTracker.trackReplication(distributedOperation);
batcher.add(logIndex, distributedOperation);
} else {
batcher.flush();
// since this last entry didn't get in the batcher we need to update the lastApplied:
lastApplied = logIndex;
}
}
batcher.flush();
} catch (Throwable e) {
log.error("Failed to apply up to index " + lastToApply, e);
dbHealth.get().panic(e);
applier.panic();
}
});
if (!success) {
log.error("Applier has entered a state of panic, no more jobs can be submitted.");
try {
// Let's sleep a while so that the log does not get flooded in this state.
// TODO: Consider triggering a shutdown of the database on panic.
Thread.sleep(1000);
} catch (InterruptedException ignored) {
}
}
}
Aggregations