package put.consensus; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.List; import java.util.Vector; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import lsr.common.Configuration; import lsr.paxos.replica.Replica; import lsr.service.AbstractService; import put.consensus.listeners.CommitListener; import put.consensus.listeners.ConsensusListener; import put.consensus.listeners.RecoveryListener; public class SerializablePaxosConsensus extends AbstractService implements CommitableConsensus { private Replica replica; private ConsensusDelegateProposer client; private BlockingQueue<Runnable> operationsToBeDone = new LinkedBlockingQueue<Runnable>(); private List<ConsensusListener> consensusListeners = new Vector<ConsensusListener>(); private List<RecoveryListener> recoveryListeners = new Vector<RecoveryListener>(); private List<CommitListener> commitListeners = new Vector<CommitListener>(); private int lastDeliveredRequest = -1; public SerializablePaxosConsensus(Configuration configuration, int localId) throws IOException { replica = new Replica(configuration, localId, this); } public final void start() throws IOException { replica.start(); client = new ConsensusDelegateProposerImpl(); startThreads(); } private final void startThreads() { // Starting thread for all actions Thread thread = new Thread() { public void run() { try { while (true) { operationsToBeDone.take().run(); } } catch (InterruptedException e) { throw new RuntimeException(e); } } }; thread.start(); } public final byte[] execute(final byte[] value, final int seqNo) { operationsToBeDone.add(new Runnable() { public void run() { Object val = byteArrayToObject(value); synchronized (consensusListeners) { for (ConsensusListener l : consensusListeners) { l.decide(val); } } lastDeliveredRequest = seqNo; } }); return new byte[0]; } public final void propose(Object obj) { client.propose(obj); } public final void commit(final Object commitData) { operationsToBeDone.add(new Runnable() { public void run() { for (CommitListener listner : commitListeners) { listner.onCommit(commitData); } fireSnapshotMade(lastDeliveredRequest, byteArrayFromObject(commitData), null); } }); } public final void updateToSnapshot(final int instanceId, final byte[] snapshot) { operationsToBeDone.add(new Runnable() { public void run() { lastDeliveredRequest = instanceId; for (RecoveryListener listner : recoveryListeners) { listner.recoverFromCommit(byteArrayToObject(snapshot)); } } }); } public final void recoveryFinished() { super.recoveryFinished(); operationsToBeDone.add(new Runnable() { public void run() { for (RecoveryListener listner : recoveryListeners) { listner.recoveryFinished(); } } }); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ public final void addConsensusListener(ConsensusListener listener) { synchronized (consensusListeners) { consensusListeners.add(listener); } } public final void removeConsensusListener(ConsensusListener listener) { synchronized (consensusListeners) { consensusListeners.remove(listener); } } public final boolean addCommitListener(CommitListener listener) { return commitListeners.add(listener); } public final boolean removeCommitListener(CommitListener listener) { return commitListeners.remove(listener); } public final boolean addRecoveryListener(RecoveryListener listener) { return recoveryListeners.add(listener); } public final boolean removeRecoveryListener(RecoveryListener listener) { return recoveryListeners.remove(listener); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ protected Object byteArrayToObject(byte[] bytes) { try { ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream ois; ois = new ObjectInputStream(bis); return ois.readObject(); } catch (Exception e) { throw new RuntimeException(e); } } protected byte[] byteArrayFromObject(Object object) { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); new ObjectOutputStream(bos).writeObject(object); return bos.toByteArray(); } catch (Exception e) { throw new RuntimeException(e); } } public final void askForSnapshot(int lastSnapshotInstance) { } public final void forceSnapshot(int lastSnapshotInstance) { } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ public ConsensusDelegateProposer getNewDelegateProposer() throws IOException { return new ConsensusDelegateProposerImpl(); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ public final int getHighestExecuteSeqNo() { return lastDeliveredRequest; } }