use of org.neo4j.cluster.statemachine.StateMachine in project neo4j by neo4j.
the class StateMachinesTest method whenMessageHandlingCausesNewMessagesThenEnsureCorrectOrder.
@Test
public void whenMessageHandlingCausesNewMessagesThenEnsureCorrectOrder() throws Exception {
// Given
StateMachines stateMachines = new StateMachines(NullLogProvider.getInstance(), mock(StateMachines.Monitor.class), mock(MessageSource.class), Mockito.mock(MessageSender.class), Mockito.mock(Timeouts.class), Mockito.mock(DelayedDirectExecutor.class), new Executor() {
@Override
public void execute(Runnable command) {
command.run();
}
}, mock(InstanceId.class));
ArrayList<TestMessage> handleOrder = new ArrayList<>();
StateMachine stateMachine = new StateMachine(handleOrder, TestMessage.class, TestState.test, NullLogProvider.getInstance());
stateMachines.addStateMachine(stateMachine);
// When
stateMachines.process(internal(TestMessage.message1));
// Then
assertThat(handleOrder.toString(), equalTo("[message1, message2, message4, message5, message3]"));
}
use of org.neo4j.cluster.statemachine.StateMachine in project neo4j by neo4j.
the class MultiPaxosServerFactory method constructSupportingInfrastructureFor.
/**
* Sets up the supporting infrastructure and communication hooks for our state machines. This is here to support
* an external requirement for assembling protocol servers given an existing set of state machines (used to prove
* correctness).
*/
public ProtocolServer constructSupportingInfrastructureFor(InstanceId me, MessageSource input, MessageSender output, DelayedDirectExecutor executor, Timeouts timeouts, Executor stateMachineExecutor, final MultiPaxosContext context, StateMachine[] machines) {
StateMachines stateMachines = new StateMachines(logging, stateMachinesMonitor, input, output, timeouts, executor, stateMachineExecutor, me);
for (StateMachine machine : machines) {
stateMachines.addStateMachine(machine);
}
final ProtocolServer server = new ProtocolServer(me, stateMachines, logging);
server.addBindingListener(new BindingListener() {
@Override
public void listeningAt(URI me) {
context.getClusterContext().setBoundAt(me);
}
});
stateMachines.addMessageProcessor(new HeartbeatRefreshProcessor(stateMachines.getOutgoing(), context.getClusterContext()));
input.addMessageProcessor(new HeartbeatIAmAliveProcessor(stateMachines.getOutgoing(), context.getClusterContext()));
Cluster cluster = server.newClient(Cluster.class);
cluster.addClusterListener(new HeartbeatJoinListener(stateMachines.getOutgoing()));
cluster.addClusterListener(new HeartbeatLeftListener(context.getHeartbeatContext(), logging));
context.getHeartbeatContext().addHeartbeatListener(new HeartbeatReelectionListener(server.newClient(Election.class), logging));
context.getClusterContext().addClusterListener(new ClusterLeaveReelectionListener(server.newClient(Election.class), logging));
StateMachineRules rules = new StateMachineRules(stateMachines.getOutgoing()).rule(ClusterState.start, ClusterMessage.create, ClusterState.entered, internal(AtomicBroadcastMessage.entered), internal(ProposerMessage.join), internal(AcceptorMessage.join), internal(LearnerMessage.join), internal(HeartbeatMessage.join), internal(ElectionMessage.created), internal(SnapshotMessage.join)).rule(ClusterState.discovery, ClusterMessage.configurationResponse, ClusterState.joining, internal(AcceptorMessage.join), internal(LearnerMessage.join), internal(AtomicBroadcastMessage.join)).rule(ClusterState.discovery, ClusterMessage.configurationResponse, ClusterState.entered, internal(AtomicBroadcastMessage.entered), internal(ProposerMessage.join), internal(AcceptorMessage.join), internal(LearnerMessage.join), internal(HeartbeatMessage.join), internal(ElectionMessage.join), internal(SnapshotMessage.join)).rule(ClusterState.joining, ClusterMessage.configurationChanged, ClusterState.entered, internal(AtomicBroadcastMessage.entered), internal(ProposerMessage.join), internal(AcceptorMessage.join), internal(LearnerMessage.join), internal(HeartbeatMessage.join), internal(ElectionMessage.join), internal(SnapshotMessage.join)).rule(ClusterState.joining, ClusterMessage.joinFailure, ClusterState.start, internal(AtomicBroadcastMessage.leave), internal(AcceptorMessage.leave), internal(LearnerMessage.leave), internal(ProposerMessage.leave)).rule(ClusterState.entered, ClusterMessage.leave, ClusterState.start, internal(AtomicBroadcastMessage.leave), internal(AcceptorMessage.leave), internal(LearnerMessage.leave), internal(HeartbeatMessage.leave), internal(SnapshotMessage.leave), internal(ElectionMessage.leave), internal(ProposerMessage.leave)).rule(ClusterState.entered, ClusterMessage.leave, ClusterState.start, internal(AtomicBroadcastMessage.leave), internal(AcceptorMessage.leave), internal(LearnerMessage.leave), internal(HeartbeatMessage.leave), internal(ElectionMessage.leave), internal(SnapshotMessage.leave), internal(ProposerMessage.leave)).rule(ClusterState.leaving, ClusterMessage.configurationChanged, ClusterState.start, internal(AtomicBroadcastMessage.leave), internal(AcceptorMessage.leave), internal(LearnerMessage.leave), internal(HeartbeatMessage.leave), internal(ElectionMessage.leave), internal(SnapshotMessage.leave), internal(ProposerMessage.leave)).rule(ClusterState.leaving, ClusterMessage.leaveTimedout, ClusterState.start, internal(AtomicBroadcastMessage.leave), internal(AcceptorMessage.leave), internal(LearnerMessage.leave), internal(HeartbeatMessage.leave), internal(ElectionMessage.leave), internal(SnapshotMessage.leave), internal(ProposerMessage.leave));
stateMachines.addStateTransitionListener(rules);
return server;
}
use of org.neo4j.cluster.statemachine.StateMachine in project neo4j by neo4j.
the class ClusterInstance method snapshotStateMachine.
private StateMachine snapshotStateMachine(LogProvider logProvider, MultiPaxosContext snapshotCtx, StateMachine stateMachine) {
// This is done this way because all the state machines are sharing one piece of global state
// (MultiPaxosContext), which is snapshotted as one coherent component. This means the state machines
// cannot snapshot themselves, an external service needs to snapshot the full shared state and then create
// new state machines sharing that state.
Object ctx;
Class<? extends MessageType> msgType = stateMachine.getMessageType();
if (msgType == AtomicBroadcastMessage.class) {
ctx = snapshotCtx.getAtomicBroadcastContext();
} else if (msgType == AcceptorMessage.class) {
ctx = snapshotCtx.getAcceptorContext();
} else if (msgType == ProposerMessage.class) {
ctx = snapshotCtx.getProposerContext();
} else if (msgType == LearnerMessage.class) {
ctx = snapshotCtx.getLearnerContext();
} else if (msgType == HeartbeatMessage.class) {
ctx = snapshotCtx.getHeartbeatContext();
} else if (msgType == ElectionMessage.class) {
ctx = snapshotCtx.getElectionContext();
} else if (msgType == SnapshotMessage.class) {
ctx = new SnapshotContext(snapshotCtx.getClusterContext(), snapshotCtx.getLearnerContext());
} else if (msgType == ClusterMessage.class) {
ctx = snapshotCtx.getClusterContext();
} else {
throw new IllegalArgumentException("I don't know how to snapshot this state machine: " + stateMachine);
}
return new StateMachine(ctx, stateMachine.getMessageType(), stateMachine.getState(), logProvider);
}
Aggregations