/**
* 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.protocol.atomicbroadcast.multipaxos;
import org.neo4j.cluster.com.message.Message;
import org.neo4j.cluster.com.message.MessageProcessor;
import org.neo4j.cluster.statemachine.State;
/**
* State machine for Paxos Acceptor
*/
public enum AcceptorState
implements State<AcceptorContext, AcceptorMessage>
{
start
{
@Override
public AcceptorState handle( AcceptorContext context,
Message<AcceptorMessage> message,
MessageProcessor outgoing
)
throws Throwable
{
switch ( message.getMessageType() )
{
case join:
{
return acceptor;
}
}
return this;
}
},
acceptor
{
@Override
public AcceptorState handle( AcceptorContext context,
Message<AcceptorMessage> message,
MessageProcessor outgoing
)
throws Throwable
{
switch ( message.getMessageType() )
{
case prepare:
{
AcceptorMessage.PrepareState prepareState = message.getPayload();
InstanceId instanceId = new InstanceId( message );
AcceptorInstance instance = context.getAcceptorInstance( instanceId );
if ( prepareState.getBallot() >= instance.getBallot() )
{
context.promise( instance, prepareState.getBallot() );
outgoing.process( message.copyHeadersTo( Message.respond( ProposerMessage.promise,
message,
new ProposerMessage.PromiseState( prepareState.getBallot(),
instance.getValue() ) ), InstanceId.INSTANCE ) );
}
else
{
// Optimization - explicit reject
context.getLogger( AcceptorState.class ).debug( "Reject " + instanceId
+ " ballot:" + instance.getBallot() );
outgoing.process( message.copyHeadersTo( Message.respond( ProposerMessage
.rejectPrepare, message,
new ProposerMessage.RejectPrepare( instance.getBallot() ) ),
InstanceId.INSTANCE ) );
}
break;
}
case accept:
{
// Task 4
AcceptorMessage.AcceptState acceptState = message.getPayload();
InstanceId instanceId = new InstanceId( message );
AcceptorInstance instance = context.getAcceptorInstance( instanceId );
if ( acceptState.getBallot() == instance.getBallot() )
{
context.accept( instance, acceptState.getValue() );
instance.accept( acceptState.getValue() );
outgoing.process( message.copyHeadersTo( Message.respond( ProposerMessage.accepted,
message,
new ProposerMessage.AcceptedState() ), InstanceId.INSTANCE ) );
}
else
{
context.getLogger( AcceptorState.class ).debug( "Reject " + instanceId
+ " accept ballot:" + acceptState.getBallot() + " actual ballot:" +
instance.getBallot() );
outgoing.process( message.copyHeadersTo( Message.respond( ProposerMessage
.rejectAccept, message,
new ProposerMessage.RejectAcceptState() ), InstanceId.INSTANCE ) );
}
break;
}
case leave:
{
context.leave();
return start;
}
}
return this;
}
},
}