/**
* Copyright (c) 2007-2009 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags
*
* This file is part of SMaRt.
*
* SMaRt is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SMaRt 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SMaRt. If not, see <http://www.gnu.org/licenses/>.
*/
package bftsmart.demo.counter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.locks.ReentrantLock;
import bftsmart.statemanagment.ApplicationState;
import bftsmart.tom.MessageContext;
import bftsmart.tom.ReplicaContext;
import bftsmart.tom.ServiceReplica;
import bftsmart.tom.server.BatchExecutable;
import bftsmart.tom.server.Recoverable;
import bftsmart.tom.server.SingleExecutable;
/**
* Example replica that implements a BFT replicated service (a counter).
*
*/
public final class CounterServer implements BatchExecutable, Recoverable {
private ServiceReplica replica;
private int counter = 0;
private int iterations = 0;
private ReplicaContext replicaContext = null;
private MessageDigest md;
private ReentrantLock stateLock = new ReentrantLock();
private int lastEid = -1;
public CounterServer(int id) {
replica = new ServiceReplica(id, this, this);
try {
md = MessageDigest.getInstance("MD5"); // TODO: shouldn't it be SHA?
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
}
//******* EDUARDO BEGIN **************//
public CounterServer(int id, boolean join) {
replica = new ServiceReplica(id, join, this, this);
}
//******* EDUARDO END **************//
public void setReplicaContext(ReplicaContext replicaContext) {
this.replicaContext = replicaContext;
}
@Override
public byte[][] executeBatch(byte[][] commands, MessageContext[] msgCtxs) {
stateLock.lock();
byte [][] replies = new byte[commands.length][];
for (int i = 0; i < commands.length; i++) {
replies[i] = execute(commands[i],msgCtxs[i]);
}
stateLock.unlock();
return replies;
}
@Override
public byte[] executeUnordered(byte[] command, MessageContext msgCtx) {
return execute(command,msgCtx);
}
public byte[] execute(byte[] command, MessageContext msgCtx) {
iterations++;
try {
int increment = new DataInputStream(new ByteArrayInputStream(command)).readInt();
//System.out.println("read-only request: "+(msgCtx.getConsensusId() == -1));
counter += increment;
lastEid = msgCtx.getConsensusId();
if (msgCtx.getConsensusId() == -1)
System.out.println("(" + iterations + ") Counter incremented: " + counter);
else
System.out.println("(" + iterations + " / " + msgCtx.getConsensusId() + ") Counter incremented: " + counter);
ByteArrayOutputStream out = new ByteArrayOutputStream(4);
new DataOutputStream(out).writeInt(counter);
return out.toByteArray();
} catch (IOException ex) {
System.err.println("Invalid request received!");
return new byte[0];
}
}
public static void main(String[] args){
if(args.length < 1) {
System.out.println("Use: java CounterServer <processId> <join option (optional)>");
System.exit(-1);
}
if(args.length > 1) {
new CounterServer(Integer.parseInt(args[0]), Boolean.valueOf(args[1]));
}else{
new CounterServer(Integer.parseInt(args[0]));
}
}
/** THIS IS JOAO'S CODE, TO HANDLE CHECKPOINTS */
@Override
public ApplicationState getState(int eid, boolean sendState) {
stateLock.lock();
if (eid == -1 || eid > lastEid) return new CounterState();
byte[] b = new byte[4];
byte[] d = null;
for (int i = 0; i < 4; i++) {
int offset = (b.length - 1 - i) * 8;
b[i] = (byte) ((counter >>> offset) & 0xFF);
}
stateLock.unlock();
d = md.digest(b);
return new CounterState(lastEid, (sendState ? b : null), d);
}
@Override
public int setState(ApplicationState state) {
int value = 0;
for (int i = 0; i < 4; i++) {
int shift = (4 - 1 - i) * 8;
value += (state.getSerializedState()[i] & 0x000000FF) << shift;
}
//System.out.println("setting counter to: "+value);
stateLock.lock();
this.counter = value;
stateLock.unlock();
this.lastEid = state.getLastEid();
return state.getLastEid();
}
/********************************************************/
}