/** * Copyright (c) 2002-2012 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Neo4j is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.neo4j.cluster; import static org.neo4j.cluster.com.message.Message.internal; import java.net.URI; import org.neo4j.cluster.com.message.MessageProcessor; import org.neo4j.cluster.com.message.MessageSource; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.AcceptorContext; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.AcceptorInstanceStore; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.AcceptorMessage; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.AcceptorState; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.AtomicBroadcastContext; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.AtomicBroadcastMessage; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.AtomicBroadcastState; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.LearnerContext; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.LearnerMessage; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.LearnerState; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.MultiPaxosContext; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.ProposerContext; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.ProposerMessage; import org.neo4j.cluster.protocol.atomicbroadcast.multipaxos.ProposerState; import org.neo4j.cluster.protocol.cluster.Cluster; import org.neo4j.cluster.protocol.cluster.ClusterConfiguration; import org.neo4j.cluster.protocol.cluster.ClusterContext; import org.neo4j.cluster.protocol.cluster.ClusterMessage; import org.neo4j.cluster.protocol.cluster.ClusterState; import org.neo4j.cluster.protocol.election.ClusterLeaveReelectionListener; import org.neo4j.cluster.protocol.election.Election; import org.neo4j.cluster.protocol.election.ElectionContext; import org.neo4j.cluster.protocol.election.ElectionCredentialsProvider; import org.neo4j.cluster.protocol.election.ElectionMessage; import org.neo4j.cluster.protocol.election.ElectionRole; import org.neo4j.cluster.protocol.election.ElectionState; import org.neo4j.cluster.protocol.election.HeartbeatFailedReelectionListener; import org.neo4j.cluster.protocol.heartbeat.HeartbeatContext; import org.neo4j.cluster.protocol.heartbeat.HeartbeatIAmAliveProcessor; import org.neo4j.cluster.protocol.heartbeat.HeartbeatJoinListener; import org.neo4j.cluster.protocol.heartbeat.HeartbeatMessage; import org.neo4j.cluster.protocol.heartbeat.HeartbeatRefreshProcessor; import org.neo4j.cluster.protocol.heartbeat.HeartbeatState; import org.neo4j.cluster.protocol.snapshot.SnapshotContext; import org.neo4j.cluster.protocol.snapshot.SnapshotMessage; import org.neo4j.cluster.protocol.snapshot.SnapshotState; import org.neo4j.cluster.statemachine.StateMachine; import org.neo4j.cluster.statemachine.StateMachineRules; import org.neo4j.cluster.timeout.LatencyCalculator; import org.neo4j.cluster.timeout.TimeoutStrategy; import org.neo4j.cluster.timeout.Timeouts; import org.neo4j.helpers.collection.Iterables; import org.neo4j.kernel.logging.Loggers; import org.neo4j.kernel.logging.Logging; /** * Factory for MultiPaxos {@link ProtocolServer}s. */ public class MultiPaxosServerFactory implements ProtocolServerFactory { private final ClusterConfiguration initialConfig; private final Logging logging; public MultiPaxosServerFactory( ClusterConfiguration initialConfig, Logging logging ) { this.initialConfig = initialConfig; this.logging = logging; } @Override public ProtocolServer newProtocolServer( TimeoutStrategy timeoutStrategy, MessageSource input, MessageProcessor output, AcceptorInstanceStore acceptorInstanceStore, ElectionCredentialsProvider electionCredentialsProvider ) { LatencyCalculator latencyCalculator = new LatencyCalculator( timeoutStrategy, input ); DelayedDirectExecutor executor = new DelayedDirectExecutor(); // Create state machines ConnectedStateMachines connectedStateMachines = new ConnectedStateMachines( input, output, latencyCalculator, executor ); Timeouts timeouts = connectedStateMachines.getTimeouts(); connectedStateMachines.addMessageProcessor( latencyCalculator ); AcceptorContext acceptorContext = new AcceptorContext( logging, acceptorInstanceStore ); LearnerContext learnerContext = new LearnerContext(); ProposerContext proposerContext = new ProposerContext(); final ClusterContext clusterContext = new ClusterContext( proposerContext, learnerContext, new ClusterConfiguration( initialConfig.getName(), initialConfig.getMembers() ), timeouts, executor, logging ); final HeartbeatContext heartbeatContext = new HeartbeatContext( clusterContext, learnerContext, executor ); final MultiPaxosContext context = new MultiPaxosContext( clusterContext, proposerContext, learnerContext, heartbeatContext, timeouts ); ElectionContext electionContext = new ElectionContext( Iterables.iterable( new ElectionRole( ClusterConfiguration .COORDINATOR ) ), clusterContext, heartbeatContext ); SnapshotContext snapshotContext = new SnapshotContext( clusterContext, learnerContext ); AtomicBroadcastContext atomicBroadcastContext = new AtomicBroadcastContext( clusterContext, executor ); connectedStateMachines.addStateMachine( new StateMachine( atomicBroadcastContext, AtomicBroadcastMessage.class, AtomicBroadcastState.start ) ); connectedStateMachines.addStateMachine( new StateMachine( acceptorContext, AcceptorMessage.class, AcceptorState.start ) ); connectedStateMachines.addStateMachine( new StateMachine( context, ProposerMessage.class, ProposerState.start ) ); connectedStateMachines.addStateMachine( new StateMachine( context, LearnerMessage.class, LearnerState.start ) ); connectedStateMachines.addStateMachine( new StateMachine( heartbeatContext, HeartbeatMessage.class, HeartbeatState.start ) ); connectedStateMachines.addStateMachine( new StateMachine( electionContext, ElectionMessage.class, ElectionState.start ) ); connectedStateMachines.addStateMachine( new StateMachine( snapshotContext, SnapshotMessage.class, SnapshotState.start ) ); final ProtocolServer server = new ProtocolServer( connectedStateMachines, logging.getLogger( Loggers.CLUSTER ) ); StateMachine cluster = new StateMachine( clusterContext, ClusterMessage.class, ClusterState.start ); connectedStateMachines.addStateMachine( cluster ); server.addBindingListener( new BindingListener() { @Override public void listeningAt( URI me ) { clusterContext.setMe( me ); } } ); connectedStateMachines.addMessageProcessor( new HeartbeatRefreshProcessor( connectedStateMachines.getOutgoing () ) ); input.addMessageProcessor( new HeartbeatIAmAliveProcessor( connectedStateMachines.getOutgoing() ) ); server.newClient( Cluster.class ).addClusterListener( new HeartbeatJoinListener( connectedStateMachines .getOutgoing() ) ); heartbeatContext.addHeartbeatListener( new HeartbeatFailedReelectionListener( server.newClient( Election .class ) ) ); clusterContext.addClusterListener( new ClusterLeaveReelectionListener( server.newClient( Election.class ) ) ); electionContext.setElectionCredentialsProvider( electionCredentialsProvider ); StateMachineRules rules = new StateMachineRules( connectedStateMachines.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.acquiringConfiguration, ClusterMessage.configurationResponse, ClusterState.joining, internal( AcceptorMessage.join ), internal( LearnerMessage.join ), internal( AtomicBroadcastMessage.join ) ) .rule( ClusterState.acquiringConfiguration, 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 ) ); connectedStateMachines.addStateTransitionListener( rules ); return server; } }