提交 87dce623 编写于 作者: M marcelmhs@gmail.com

- Changed Netty code to do not require specific client key. Now there is only...

- Changed Netty code to do not require specific client key. Now there is only one private and one public key in the config folder;
- Renamed package bftsmart.statemanagment to bftsmart.statemanagement and refactored code where needed;
- Removed some comments and unnecessary imports;
- Added YCSB implementation and library;
- Change state management protocol to allow different strategies. Added an implementation of the Durable State Transfer defined in the paper presented in USENIX ATC 2013;
- Changed ServiceProxy to allow invoke asynchronous to define a message type and also fixed locks to respect other invoke methods;
- Added FIFO message delivery strategy available to replicas.
上级 d999d17b
......@@ -20,7 +20,7 @@
<pathelement location="${dist.dir}" />
</path>
<target name="compile" description="Compilation target">
<javac classpathref="libs" source="1.5" target="1.5" destdir="${build.dir}" nowarn="on">
<javac classpathref="libs" source="1.7" target="1.7" destdir="${build.dir}" nowarn="on">
<src path="${src.dir}" />
<src path="${test.dir}" />
</javac>
......
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALC6hNZtIUOdWOiHB1l+2gDC/egL
FQ+dSKI00f2levIRbyRIVEZUnvMkLDEme3dhkaek8bGcLeEAjheQbbqE7v5PGSBpia/kZtqYv3jq
5khLG/Ro1fdhto5//8wLoXy1KEV8KelaWPrwVi6Uzl0LY444dpQl+h9CGZd+xoRZTbnXAgMBAAEC
gYAJaUVdrd4RnbV4XIh1qZ2uYLPowX5ToIqXqLxuB3vunCMRCZEDVcpJJGn+DBCTIO0CwnPkg26m
BsOKWbSeNCoN5gOi5yd6Poe0D40ZmvHP1hMCQ9LYhwjLB3Aa+Cl5gYL074Qe/eJFqJaYjZApkeJU
Ay1HkXhM5OBW9grrXxg6YQJBAPTIni5fG5f2SYutkR2pUydZP4haKVabRkZr8nSHuClGDE2HzbNQ
jb17z5rRVxJCKMLb2HiPg7ZsUgGK/J1ri78CQQC405h45rL1mCIyZQCXcK/nQZTVi8UaaelKN/ub
LQKtTGenJao/zoL+m39i+gGRkHWiG6HNaGFdOkRJmeeH+rfpAkEAn0fwDjKbDP4ZC0fM1uU4k7Ey
czJgFdgCGY7ifMtXnZvUI5sL0fPH15W6GH7BzsK4LVvK92BDj6/aiOB80p6JlwJASjL4NSE4mwv2
PpD5ydI9a/OSEqDIAjCerWMIKWXKe1P/EMU4MeFwCVLXsx523r9F2kyJinLrE4g+veWBY7+tcQJB
AKCTm3tbbwLJnnPN46mAgrYb5+LFOmHyNtEDgjxEVrzpQaCChZici2YGY1jTBjb/De4jii8RXllA
tUhBEsqyXDA=
\ No newline at end of file
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwuoTWbSFDnVjohwdZftoAwv3oCxUPnUiiNNH9
pXryEW8kSFRGVJ7zJCwxJnt3YZGnpPGxnC3hAI4XkG26hO7+TxkgaYmv5GbamL946uZISxv0aNX3
YbaOf//MC6F8tShFfCnpWlj68FYulM5dC2OOOHaUJfofQhmXfsaEWU251wIDAQAB
\ No newline at end of file
# Copyright (c) 2010 Yahoo! Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you
# may not use this file except in compliance with the License. You
# may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License. See accompanying
# LICENSE file.
# Yahoo! Cloud System Benchmark
# Workload A: Update heavy workload
# Application example: Session store recording recent actions
#
# Read/update ratio: 50/50
# Default data size: 1 KB records (10 fields, 100 bytes each, plus key)
# Request distribution: zipfian
fieldcount=1
fieldlength=4096
recordcount=250000
operationcount=0
workload=com.yahoo.ycsb.workloads.CoreWorkload
readallfields=true
readproportion=0
updateproportion=1
scanproportion=0
insertproportion=0
requestdistribution=zipfian
#maxexecutiontime=30
smart-initkey=1000
文件已添加
#/bin/bash
REPLICA_INDEX=$1
java -cp bin/:lib/* bftsmart.demo.ycsb.YCSBServer $REPLICA_INDEX
#! /usr/bin/env bash
# Set the YCSB specific environment. Adds all the required libraries to the class path.
# Copyright (c) 2010 Yahoo! Inc. All rights reserved.
# *
# * Licensed under the Apache License, Version 2.0 (the "License"); you
# * may not use this file except in compliance with the License. You
# * may obtain a copy of the License at
# *
# * http://www.apache.org/licenses/LICENSE-2.0
# *
# * Unless required by applicable law or agreed to in writing, software
# * distributed under the License is distributed on an "AS IS" BASIS,
# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# * implied. See the License for the specific language governing
# * permissions and limitations under the License. See accompanying
# * LICENSE file.
#
# The Java implementation to use. This is required.
#export JAVA_HOME=
# Any JVM options to pass.
#export YCSB_OPTS="-Djava.compiler=NONE"
# YCSB client heap size.
#export YCSB_HEAP_SIZE=500
this=`dirname "$0"`
this=`cd "$this"; pwd`
while [ -h "$this" ]; do
ls=`ls -ld "$this"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '.*/.*' > /dev/null; then
this="$link"
else
this=`dirname "$this"`/"$link"
fi
done
bin=`dirname "$this"`
script=`basename "$this"`
bin=`cd "$bin"; pwd`
this="$bin/$script"
# the root of the Hadoop installation
export YCSB_HOME=`dirname "$this"`
echo "YCSB_HOME $YCSB_HOME"
cygwin=false
case "`uname`" in
CYGWIN*) cygwin=true;;
esac
# if no args specified, show usage
if [ $# = 0 ]; then
echo "Usage: ycsb CLASSNAME"
echo "where CLASSNAME is the name of the class to run"
echo "The jar file for the class must be in bin, build, lib, or db/*/lib."
exit 1
fi
# get arguments
COMMAND=$1
shift
JAVA=""
if [ "$JAVA_HOME" != "" ]; then
JAVA=$JAVA_HOME/bin/java
else
echo "JAVA_HOME must be set."
exit 1
fi
JAVA_HEAP_MAX=-Xmx500m
# check envvars which might override default args
if [ "$YCSB_HEAP_SIZE" != "" ]; then
JAVA_HEAP_MAX="-Xmx""$YCSB_HEAP_SIZE""m"
fi
# Set the classpath.
if [ "$CLASSPATH" != "" ]; then
CLASSPATH=${CLASSPATH}:$JAVA_HOME/lib/tools.jar
else
CLASSPATH=$JAVA_HOME/lib/tools.jar
fi
# so that filenames w/ spaces are handled correctly in loops below
IFS=
for f in $YCSB_HOME/build/*.jar; do
CLASSPATH=${CLASSPATH}:$f
done
for f in $YCSB_HOME/lib/*.jar; do
CLASSPATH=${CLASSPATH}:$f
done
for f in $YCSB_HOME/db/*; do
if [ -d $f ]; then
for j in $f/lib/*.jar; do
CLASSPATH=${CLASSPATH}:$j
done
fi
done
#echo "CLASSPATH=$CLASSPATH"
# restore ordinary behavior
unset IFS
CLASS=$COMMAND
# cygwin path translation
if $cygwin; then
CLASSPATH=`cygpath -p -w "$CLASSPATH"`
YCSB_HOME=`cygpath -w "$YCSB_HOME"`
fi
#echo "Executing command $CLASS with options $JAVA_HEAP_MAX $YCSB_OPTS $CLASS $@"
exec "$JAVA" $JAVA_HEAP_MAX $YCSB_OPTS -classpath "$CLASSPATH" $CLASS "$@"
#/bin/bash
java -cp lib/core-0.1.4.jar:lib/netty-3.1.1.GA.jar:lib/commons-codec-1.5.jar:./bin/ com.yahoo.ycsb.Client -threads 10 -P config/workloads/workloada -p measurementtype=timeseries -p timeseries.granularity=1000 -db bftsmart.demo.ycsb.YCSBClient -s > output.txt
# load set to 500 ops/s
#java -cp lib/core-0.1.4.jar:lib/netty-3.1.1.GA.jar:lib/commons-codec-1.5.jar:./bin/ com.yahoo.ycsb.Client -threads 10 -target 500 -P config/workloads/workloada -p measurementtype=timeseries -p timeseries.granularity=1000 -db bftsmart.demo.ycsb.YCSBClient -s > output.txt
......@@ -65,7 +65,7 @@ public class ClientsManager {
//******* EDUARDO BEGIN **************//
clientData = new ClientData(clientId,
(manager.getStaticConf().getUseSignatures() == 1)
? manager.getStaticConf().getRSAPublicKey(clientId)
? manager.getStaticConf().getRSAPublicKey()
: null);
//******* EDUARDO END **************//
clientsData.put(clientId, clientData);
......
......@@ -22,7 +22,7 @@ package bftsmart.communication;
import bftsmart.paxosatwar.messages.MessageFactory;
import bftsmart.paxosatwar.messages.PaxosMessage;
import bftsmart.paxosatwar.roles.Acceptor;
import bftsmart.statemanagment.SMMessage;
import bftsmart.statemanagement.SMMessage;
import bftsmart.tom.core.TOMLayer;
import bftsmart.tom.core.messages.TOMMessage;
import bftsmart.tom.core.timer.ForwardedMessage;
......@@ -119,68 +119,68 @@ public class MessageHandler {
Logger.println("(MessageHandler.processData) Discarding unauthenticated message from " + sm.getSender());
}
} else if (sm.authenticated) {
/*** This is Joao's code, related to leader change */
if (sm instanceof LCMessage) {
LCMessage lcMsg = (LCMessage) sm;
String type = null;
switch(lcMsg.getType()) {
case TOMUtil.STOP:
type = "STOP";
break;
case TOMUtil.STOPDATA:
type = "STOPDATA";
break;
case TOMUtil.SYNC:
type = "SYNC";
break;
default:
type = "LOCAL";
break;
}
System.out.println("(MessageHandler.processData) LC_MSG received: type " + type + ", regency " + lcMsg.getReg() + ", (replica " + lcMsg.getSender() + ")");
if (lcMsg.TRIGGER_LC_LOCALLY) tomLayer.requestsTimer.run_lc_protocol();
else tomLayer.deliverTimeoutRequest(lcMsg);
/**************************************************************/
} else if (sm instanceof ForwardedMessage) {
TOMMessage request = ((ForwardedMessage) sm).getRequest();
tomLayer.requestReceived(request);
/** This is Joao's code, to handle state transfer */
} else if (sm instanceof SMMessage) {
SMMessage smsg = (SMMessage) sm;
String type = null;
switch(smsg.getType()) {
case TOMUtil.SM_REQUEST:
type = "SM_REQUEST";
break;
case TOMUtil.SM_REPLY:
type = "SM_REPLY";
break;
default:
type = "LOCAL";
break;
}
System.out.println("(MessageHandler.processData) SM_MSG received: type " + type + ", regency " + smsg.getRegency() + ", (replica " + smsg.getSender() + ")");
if (smsg.TRIGGER_SM_LOCALLY) {
tomLayer.getStateManager().stateTimeout();
}
else if (smsg.getType() == TOMUtil.SM_REQUEST) {
tomLayer.getStateManager().SMRequestDeliver(smsg);
} else {
tomLayer.getStateManager().SMReplyDeliver(smsg);
}
/******************************************************************/
}
} else {
Logger.println("(MessageHandler.processData) Discarding unauthenticated message from " + sm.getSender());
if (sm.authenticated) {
/*** This is Joao's code, related to leader change */
if (sm instanceof LCMessage) {
LCMessage lcMsg = (LCMessage) sm;
String type = null;
switch(lcMsg.getType()) {
case TOMUtil.STOP:
type = "STOP";
break;
case TOMUtil.STOPDATA:
type = "STOPDATA";
break;
case TOMUtil.SYNC:
type = "SYNC";
break;
default:
type = "LOCAL";
break;
}
System.out.println("(MessageHandler.processData) LC_MSG received: type " + type + ", regency " + lcMsg.getReg() + ", (replica " + lcMsg.getSender() + ")");
if (lcMsg.TRIGGER_LC_LOCALLY) tomLayer.requestsTimer.run_lc_protocol();
else tomLayer.deliverTimeoutRequest(lcMsg);
/**************************************************************/
} else if (sm instanceof ForwardedMessage) {
TOMMessage request = ((ForwardedMessage) sm).getRequest();
tomLayer.requestReceived(request);
/** This is Joao's code, to handle state transfer */
} else if (sm instanceof SMMessage) {
SMMessage smsg = (SMMessage) sm;
String type = null;
switch(smsg.getType()) {
case TOMUtil.SM_REQUEST:
type = "SM_REQUEST";
break;
case TOMUtil.SM_REPLY:
type = "SM_REPLY";
break;
default:
type = "LOCAL";
break;
}
System.out.println("(MessageHandler.processData) SM_MSG received: type " + type + ", regency " + smsg.getRegency() + ", (replica " + smsg.getSender() + ")");
if (smsg.TRIGGER_SM_LOCALLY) {
tomLayer.getStateManager().stateTimeout();
} else if (smsg.getType() == TOMUtil.SM_REQUEST) {
tomLayer.getStateManager().SMRequestDeliver(smsg);
} else {
tomLayer.getStateManager().SMReplyDeliver(smsg);
}
/******************************************************************/
} else {
System.out.println("UNKNOWN MESSAGE TYPE: " + sm);
}
} else {
System.out.println("(MessageHandler.processData) Discarding unauthenticated message from " + sm.getSender());
}
}
}
......
......@@ -125,7 +125,7 @@ public class NettyClientServerCommunicationSystemClientSide extends SimpleChanne
Mac macReceive = Mac.getInstance(manager.getStaticConf().getHmacAlgorithm());
macReceive.init(authKey);
NettyClientServerSession cs = new NettyClientServerSession(future.getChannel(), macSend,
macReceive, currV[i], manager.getStaticConf().getRSAPublicKey(currV[i]), new ReentrantLock());
macReceive, currV[i], manager.getStaticConf().getRSAPublicKey(), new ReentrantLock());
sessionTable.put(currV[i], cs);
System.out.println("Connecting to replica " + currV[i] + " at " + manager.getRemoteAddress(currV[i]));
......@@ -194,7 +194,7 @@ public class NettyClientServerCommunicationSystemClientSide extends SimpleChanne
macSend.init(authKey);
Mac macReceive = Mac.getInstance(manager.getStaticConf().getHmacAlgorithm());
macReceive.init(authKey);
NettyClientServerSession cs = new NettyClientServerSession(future.getChannel(), macSend, macReceive, currV[i], manager.getStaticConf().getRSAPublicKey(currV[i]), new ReentrantLock());
NettyClientServerSession cs = new NettyClientServerSession(future.getChannel(), macSend, macReceive, currV[i], manager.getStaticConf().getRSAPublicKey(), new ReentrantLock());
sessionTable.put(currV[i], cs);
System.out.println("Connecting to replica " + currV[i] + " at " + manager.getRemoteAddress(currV[i]));
......@@ -222,6 +222,7 @@ public class NettyClientServerCommunicationSystemClientSide extends SimpleChanne
System.out.println("Impossible to connect to replica.");
} else {
System.out.println("Replica disconnected.");
e.getCause().printStackTrace();
}
}
@Override
......@@ -276,7 +277,7 @@ public class NettyClientServerCommunicationSystemClientSide extends SimpleChanne
//creates MAC stuff
Mac macSend = ncss.getMacSend();
Mac macReceive = ncss.getMacReceive();
NettyClientServerSession cs = new NettyClientServerSession(future.getChannel(), macSend, macReceive, ncss.getReplicaId(), manager.getStaticConf().getRSAPublicKey(ncss.getReplicaId()), new ReentrantLock());
NettyClientServerSession cs = new NettyClientServerSession(future.getChannel(), macSend, macReceive, ncss.getReplicaId(), manager.getStaticConf().getRSAPublicKey(), new ReentrantLock());
sessionTable.remove(ncss.getReplicaId());
sessionTable.put(ncss.getReplicaId(), cs);
//System.out.println("RE-Connecting to replica "+ncss.getReplicaId()+" at " + conf.getRemoteAddress(ncss.getReplicaId()));
......
......@@ -189,7 +189,7 @@ public class NettyTOMMessageDecoder extends FrameDecoder {
macSend.init(authKey);
Mac macReceive = Mac.getInstance(manager.getStaticConf().getHmacAlgorithm());
macReceive.init(authKey);
NettyClientServerSession cs = new NettyClientServerSession(channel, macSend, macReceive, sm.getSender(), manager.getStaticConf().getRSAPublicKey(sm.getSender()), new ReentrantLock());
NettyClientServerSession cs = new NettyClientServerSession(channel, macSend, macReceive, sm.getSender(), manager.getStaticConf().getRSAPublicKey(), new ReentrantLock());
//******* EDUARDO END **************//
rl.writeLock().lock();
......
......@@ -42,8 +42,6 @@ import bftsmart.reconfiguration.TTPMessage;
import bftsmart.tom.ServiceReplica;
import bftsmart.tom.util.Logger;
import java.util.HashSet;
import java.util.TreeSet;
/**
* This class represents a connection with other server.
......@@ -185,7 +183,6 @@ public class ServerConnection {
* if some problem is detected, a reconnection is done
*/
private final void sendBytes(byte[] messageData, boolean useMAC) {
int i = 0;
boolean abort = false;
do {
if (abort) return; // if there is a need to reconnect, abort this method
......@@ -218,8 +215,6 @@ public class ServerConnection {
waitAndConnect();
abort = true;
}
//br.ufsc.das.tom.util.Logger.println("(ServerConnection.sendBytes) iteration " + i);
i++;
} while (doWork);
}
......@@ -343,6 +338,8 @@ public class ServerConnection {
socket.close();
} catch (IOException ex) {
Logger.println("Error closing socket to "+remoteId);
} catch (NullPointerException npe) {
Logger.println("Socket already closed");
}
socket = null;
......
......@@ -53,15 +53,15 @@ public class BFTMapBatchServer extends DefaultRecoverable {
@Override
public byte[][] executeBatch2(byte[][] commands, MessageContext[] msgCtxs) {
public byte[][] appExecuteBatch(byte[][] commands, MessageContext[] msgCtxs) {
byte[][] replies = new byte[commands.length][];
stateLock.lock();
ops += commands.length;
if(ops % 5000 == 0)
System.out.println("OPS: " + ops + ", Eid: " + msgCtxs[0].getConsensusId());
try {
int index = 0;
for(byte[] command: commands) {
int index = 0;
ByteArrayInputStream in = new ByteArrayInputStream(command);
ByteArrayOutputStream out = null;
byte[] reply = null;
......
......@@ -28,22 +28,22 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.locks.ReentrantLock;
import bftsmart.statemanagment.ApplicationState;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.statemanagement.StateManager;
import bftsmart.statemanagement.strategy.StandardStateManager;
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;
......@@ -52,8 +52,10 @@ public final class CounterServer implements BatchExecutable, Recoverable {
private ReentrantLock stateLock = new ReentrantLock();
private int lastEid = -1;
private StateManager stateManager;
public CounterServer(int id) {
replica = new ServiceReplica(id, this, this);
new ServiceReplica(id, this, this);
try {
md = MessageDigest.getInstance("MD5"); // TODO: shouldn't it be SHA?
......@@ -64,7 +66,7 @@ public final class CounterServer implements BatchExecutable, Recoverable {
//******* EDUARDO BEGIN **************//
public CounterServer(int id, boolean join) {
replica = new ServiceReplica(id, join, this, this);
new ServiceReplica(id, join, this, this);
}
//******* EDUARDO END **************//
......@@ -171,5 +173,11 @@ public final class CounterServer implements BatchExecutable, Recoverable {
return state.getLastEid();
}
/********************************************************/
@Override
public StateManager getStateManager() {
if(stateManager == null)
stateManager = new StandardStateManager();
return stateManager;
}
}
......@@ -6,7 +6,7 @@ package bftsmart.demo.counter;
import java.util.Arrays;
import bftsmart.statemanagment.ApplicationState;
import bftsmart.statemanagement.ApplicationState;
/**
*
......
......@@ -159,7 +159,7 @@ public class BFTListImpl extends DefaultRecoverable {
@Override
@SuppressWarnings("static-access")
public byte[][] executeBatch2(byte[][] commands, MessageContext[] msgCtxs) {
public byte[][] appExecuteBatch(byte[][] commands, MessageContext[] msgCtxs) {
byte [][] replies = new byte[commands.length][];
for (int i = 0; i < commands.length; i++) {
......
......@@ -18,7 +18,9 @@
package bftsmart.demo.microbenchmarks;
import bftsmart.statemanagment.ApplicationState;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.statemanagement.StateManager;
import bftsmart.statemanagement.strategy.StandardStateManager;
import bftsmart.tom.MessageContext;
import bftsmart.tom.ReplicaContext;
import bftsmart.tom.ServiceReplica;
......@@ -46,6 +48,8 @@ public class LatencyServer implements SingleExecutable, Recoverable {
private ServiceReplica replica;
private ReplicaContext replicaContext;
private StateManager stateManager;
public LatencyServer(int id, int interval, int hashs, int replySize) {
replica = new ServiceReplica(id, this, this);
......@@ -141,4 +145,12 @@ public class LatencyServer implements SingleExecutable, Recoverable {
public int setState(ApplicationState state) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public StateManager getStateManager() {
if(stateManager == null)
stateManager = new StandardStateManager();
return stateManager;
}
}
......@@ -18,11 +18,12 @@
package bftsmart.demo.microbenchmarks;
import bftsmart.statemanagment.ApplicationState;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.statemanagement.StateManager;
import bftsmart.statemanagement.strategy.StandardStateManager;
import bftsmart.tom.MessageContext;
import bftsmart.tom.ReplicaContext;
import bftsmart.tom.ServiceReplica;
import bftsmart.tom.server.Executable;
import bftsmart.tom.server.Recoverable;
import bftsmart.tom.server.SingleExecutable;
import bftsmart.tom.util.Storage;
......@@ -52,6 +53,8 @@ public final class ThroughputLatencyServer implements SingleExecutable, Recovera
private ServiceReplica replica;
private ReplicaContext replicaContext;
private StateManager stateManager;
public ThroughputLatencyServer(int id, int interval, int replySize, int stateSize, boolean context) {
replica = new ServiceReplica(id, this, this);
......@@ -164,4 +167,12 @@ public final class ThroughputLatencyServer implements SingleExecutable, Recovera
public int setState(ApplicationState state) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public StateManager getStateManager() {
if(stateManager == null)
stateManager = new StandardStateManager();
return stateManager;
}
}
......@@ -30,12 +30,9 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Scanner;
import bftsmart.statemanagment.ApplicationState;
import bftsmart.tom.MessageContext;
import bftsmart.tom.ReplicaContext;
import bftsmart.tom.ServiceReplica;
import bftsmart.tom.server.Executable;
import bftsmart.tom.server.Recoverable;
import bftsmart.tom.server.defaultservices.DefaultRecoverable;
/**
......@@ -205,7 +202,7 @@ public final class RandomServer extends DefaultRecoverable {
}
@Override
public byte[][] executeBatch2(byte[][] commands, MessageContext[] msgCtxs) {
public byte[][] appExecuteBatch(byte[][] commands, MessageContext[] msgCtxs) {
byte [][] replies = new byte[commands.length][];
for (int i = 0; i < commands.length; i++) {
replies[i] = executeOrdered(commands[i], (msgCtxs != null ? msgCtxs[i] : null));
......
package bftsmart.demo.ycsb;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;
import bftsmart.tom.ServiceProxy;
import com.yahoo.ycsb.ByteIterator;
import com.yahoo.ycsb.DB;
public class YCSBClient extends DB {
private static AtomicInteger counter = new AtomicInteger();
private ServiceProxy proxy = null;
private int myId;
public YCSBClient() {
}
@Override
public void init() {
Properties props = getProperties();
int initId = Integer.valueOf((String)props.get("smart-initkey"));
myId = initId + counter.addAndGet(1);
proxy = new ServiceProxy(myId);
System.out.println("YCSBKVClient. Initiated client id: " + myId);
}
@Override
public int delete(String arg0, String arg1) {
throw new UnsupportedOperationException();
}
@Override
public int insert(String table, String key,
HashMap<String, ByteIterator> values) {
Iterator<String> keys = values.keySet().iterator();
HashMap<String, byte[]> map = new HashMap<String, byte[]>();
while(keys.hasNext()) {
String field = keys.next();
map.put(field, values.get(field).toArray());
}
YCSBMessage msg = YCSBMessage.newInsertRequest(table, key, map);
byte[] reply = proxy.invokeOrdered(msg.getBytes());
YCSBMessage replyMsg = YCSBMessage.getObject(reply);
return replyMsg.getResult();
}
@Override
public int read(String table, String key,
Set<String> fields, HashMap<String, ByteIterator> result) {
HashMap<String, byte[]> results = new HashMap<String, byte[]>();
YCSBMessage request = YCSBMessage.newReadRequest(table, key, fields, results);
byte[] reply = proxy.invokeUnordered(request.getBytes());
YCSBMessage replyMsg = YCSBMessage.getObject(reply);
return replyMsg.getResult();
}
@Override
public int scan(String arg0, String arg1, int arg2, Set<String> arg3,
Vector<HashMap<String, ByteIterator>> arg4) {
throw new UnsupportedOperationException();
}
@Override
public int update(String table, String key,
HashMap<String, ByteIterator> values) {
Iterator<String> keys = values.keySet().iterator();
HashMap<String, byte[]> map = new HashMap<String, byte[]>();
while(keys.hasNext()) {
String field = keys.next();
map.put(field, values.get(field).toArray());
}
YCSBMessage msg = YCSBMessage.newUpdateRequest(table, key, map);
byte[] reply = proxy.invokeOrdered(msg.getBytes());
YCSBMessage replyMsg = YCSBMessage.getObject(reply);
return replyMsg.getResult();
}
}
package bftsmart.demo.ycsb;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Set;
public class YCSBMessage implements Serializable {
private static final long serialVersionUID = 6198684730704708506L;
public enum Type {
CREATE, READ, SCAN, UPDATE, DELETE, SIZE, ERROR
};
public enum Entity {
TABLE, RECORD, FIELD
};
private Type type;
private Entity entity;
private String table;
private String key;
private Set<String> fields;
private HashMap<String, byte[]> values;
private int result = -1;
private HashMap<String, byte[]> results;
private String errorMsg;
private YCSBMessage() {
super();
result = -1;
}
public static YCSBMessage newInsertRequest(String table, String key, HashMap<String, byte[]> values) {
YCSBMessage message = new YCSBMessage();
message.type = Type.CREATE;
message.entity = Entity.RECORD;
message.table = table;
message.key = key;
message.values = values;
return message;
}
public static YCSBMessage newUpdateRequest(String table, String key, HashMap<String, byte[]> values) {
YCSBMessage message = new YCSBMessage();
message.type = Type.UPDATE;
message.entity = Entity.RECORD;
message.table = table;
message.key = key;
message.values = values;
return message;
}
public static YCSBMessage newReadRequest(String table, String key, Set<String> fields, HashMap<String, byte[]> results) {
YCSBMessage message = new YCSBMessage();
message.type = Type.READ;
message.entity = Entity.RECORD;
message.table = table;
message.key = key;
message.fields = fields;
message.results = results;
return message;
}
public static YCSBMessage newInsertResponse(int result) {
YCSBMessage message = new YCSBMessage();
message.result = result;
return message;
}
public static YCSBMessage newUpdateResponse(int result) {
YCSBMessage message = new YCSBMessage();
message.result = result;
return message;
}
public static YCSBMessage newReadResponse(HashMap<String, byte[]> results, int result) {
YCSBMessage message = new YCSBMessage();
message.result = result;
message.results = results;
return message;
}
public static YCSBMessage newErrorMessage(String errorMsg) {
YCSBMessage message = new YCSBMessage();
message.errorMsg = errorMsg;
return message;
}
public byte[] getBytes() {
try {
byte[] aArray = null;
ByteArrayOutputStream aBaos = new ByteArrayOutputStream();
ObjectOutputStream aOos = new ObjectOutputStream(aBaos);
aOos.writeObject(this);
aOos.flush();
aBaos.flush();
aArray = aBaos.toByteArray();
aOos.close();
aBaos.close();
return aArray;
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
}
public static YCSBMessage getObject(byte[] theBytes) {
try {
ByteArrayInputStream aBais = new ByteArrayInputStream(theBytes);
ObjectInputStream aOis = new ObjectInputStream(aBais);
YCSBMessage aMessage = (YCSBMessage) aOis.readObject();
aOis.close();
aBais.close();
return aMessage;
} catch (ClassNotFoundException ex) {
return null;
} catch (IOException e) {
return null;
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("(").append(type).append(",").append(entity).append(",");
sb.append(table).append(",").append(key).append(",").append(values).append(")");
return sb.toString();
}
public int getResult() {
return result;
}
public HashMap<String, byte[]> getResults() {
return results;
}
public Type getType() {
return type;
}
public Entity getEntity() {
return entity;
}
public String getTable() {
return table;
}
public String getKey() {
return key;
}
public Set<String> getFields() {
return fields;
}
public HashMap<String, byte[]> getValues() {
return values;
}
public String getErrorMsg() {
return errorMsg;
}
}
package bftsmart.demo.ycsb;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.TreeMap;
import bftsmart.tom.MessageContext;
import bftsmart.tom.ServiceReplica;
import bftsmart.tom.server.defaultservices.durability.DurabilityCoordinator;
public class YCSBServer extends DurabilityCoordinator {
private static boolean _debug = false;
private TreeMap<String, YCSBTable> mTables;
private boolean logPrinted = false;
public static void main(String[] args) throws Exception {
if (args.length == 1) {
new YCSBServer(new Integer(args[0]));
} else {
printUsage();
}
}
private static void printUsage() {
System.out.println("Usage: java YCSBServer <replica_id>");
}
private YCSBServer(int id) {
this.mTables = new TreeMap<String, YCSBTable>();
new ServiceReplica(id, this, this);
}
@Override
public byte[][] appExecuteBatch(byte[][] commands, MessageContext[] msgCtx) {
byte[][] replies = new byte[commands.length][];
int index = 0;
for(byte[] command: commands) {
if(msgCtx != null && msgCtx[index] != null && msgCtx[index].getConsensusId() % 5000 == 0 && !logPrinted) {
System.out.println("YCSBServer executing eid: " + msgCtx[index].getConsensusId());
logPrinted = true;
} else
logPrinted = false;
YCSBMessage aRequest = YCSBMessage.getObject(command);
YCSBMessage reply = YCSBMessage.newErrorMessage("");
if (aRequest == null) {
replies[index] = reply.getBytes();
continue;
}
if (_debug)
System.out.println("[INFO] Processing an ordered request");
switch (aRequest.getType()) {
case CREATE: { // ##### operation: create #####
switch (aRequest.getEntity()) {
case RECORD: // ##### entity: record #####
if (!mTables.containsKey(aRequest.getTable())) {
mTables.put((String) aRequest.getTable(), new YCSBTable());
}
if (!mTables.get(aRequest.getTable()).containsKey(
aRequest.getKey())) {
mTables.get(aRequest.getTable()).put(aRequest.getKey(), aRequest.getValues());
reply = YCSBMessage.newInsertResponse(0);
}
break;
default: // Only create records
break;
}
break;
}
case UPDATE: { // ##### operation: update #####
switch (aRequest.getEntity()) {
case RECORD: // ##### entity: record #####
if (!mTables.containsKey(aRequest.getTable())) {
mTables.put((String) aRequest.getTable(), new YCSBTable());
}
mTables.get(aRequest.getTable()).put(aRequest.getKey(), aRequest.getValues());
reply = YCSBMessage.newUpdateResponse(1);
break;
default: // Only update records
break;
}
break;
}
}
if (_debug)
System.out.println("[INFO] Sending reply");
replies[index++] = reply.getBytes();
}
// System.out.println("RETURNING REPLY");
return replies;
}
@Override
public byte[] executeUnordered(byte[] theCommand, MessageContext theContext) {
YCSBMessage aRequest = YCSBMessage.getObject(theCommand);
YCSBMessage reply = YCSBMessage.newErrorMessage("");
if (aRequest == null) {
return reply.getBytes();
}
if (_debug)
System.out.println("[INFO] Processing an unordered request");
switch (aRequest.getType()) {
case READ: { // ##### operation: read #####
switch (aRequest.getEntity()) {
case RECORD: // ##### entity: record #####
if(!mTables.containsKey(aRequest.getTable())) {
reply = YCSBMessage.newErrorMessage("Table not found");
break;
}
if(!mTables.get(aRequest.getTable()).containsKey(aRequest.getKey())) {
reply = YCSBMessage.newErrorMessage("Record not found");
break;
} else {
reply = YCSBMessage.newReadResponse(mTables.get(aRequest.getTable()).get(aRequest.getKey()), 0);
break;
}
}
}
}
if (_debug)
System.out.println("[INFO] Sending reply");
return reply.getBytes();
}
@SuppressWarnings("unchecked")
@Override
public void installSnapshot(byte[] state) {
try {
System.out.println("setState called");
ByteArrayInputStream bis = new ByteArrayInputStream(state);
ObjectInput in = new ObjectInputStream(bis);
mTables = (TreeMap<String, YCSBTable>) in.readObject();
in.close();
bis.close();
} catch (Exception e) {
System.err.println("[ERROR] Error deserializing state: "
+ e.getMessage());
}
}
@Override
public byte[] getSnapshot() {
try {
System.out.println("getState called");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = new ObjectOutputStream(bos);
out.writeObject(mTables);
out.flush();
bos.flush();
out.close();
bos.close();
return bos.toByteArray();
} catch (IOException ioe) {
System.err.println("[ERROR] Error serializing state: "
+ ioe.getMessage());
return "ERROR".getBytes();
}
}
}
package bftsmart.demo.ycsb;
import java.io.Serializable;
import java.util.HashMap;
import java.util.TreeMap;
public class YCSBTable extends TreeMap<String, HashMap<String, byte[]>> implements Serializable {
private static final long serialVersionUID = 3786544460082473686L;
}
......@@ -72,7 +72,7 @@ public class Reconfiguration {
byte[] signature = TOMUtil.signMessage(key, reqBytes);
request.setSignature(signature);
StatusReplyListener listener = new StatusReplyListener();
proxy.invokeAsynchronous(TOMUtil.getBytes(request), listener, new int[] {id});
proxy.invokeAsynchronous(TOMUtil.getBytes(request), listener, new int[] {id}, TOMMessageType.ASK_STATUS);
StatusReply status = listener.getResponse();
return status;
}
......
......@@ -90,7 +90,7 @@ public class ServerViewManager extends ViewManager {
public void enqueueUpdate(TOMMessage up) {
ReconfigureRequest request = (ReconfigureRequest) TOMUtil.getObject(up.getContent());
if (TOMUtil.verifySignature(getStaticConf().getRSAPublicKey(request.getSender()),
if (TOMUtil.verifySignature(getStaticConf().getRSAPublicKey(),
request.toString().getBytes(), request.getSignature())) {
if (request.getSender() == getStaticConf().getTTPId()) {
this.updates.add(up);
......
......@@ -70,7 +70,6 @@ public class Configuration {
try{
hosts = new HostsConfig(configHome, hostsFileName);
loadConfig();
String s = (String) configs.remove("system.autoconnect");
......
......@@ -25,7 +25,6 @@ import java.security.PublicKey;
import java.security.spec.EncodedKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Hashtable;
import org.apache.commons.codec.binary.Base64;
/**
......@@ -34,141 +33,72 @@ import org.apache.commons.codec.binary.Base64;
*/
public class RSAKeyLoader {
private String path;
//private PublicKey[] pubKeys;
private PrivateKey priKey;
private TOMConfiguration conf;
private Hashtable<Integer, PublicKey> pubKeys = new Hashtable<Integer, PublicKey>();
/** Creates a new instance of RSAKeyLoader */
public RSAKeyLoader(TOMConfiguration conf, String configHome) {
this.conf = conf;
if (configHome.equals("")) {
path = "config" + System.getProperty("file.separator") + "keys" +
System.getProperty("file.separator");
} else {
path = configHome + System.getProperty("file.separator") + "keys" +
System.getProperty("file.separator");
}
}
/**
* Load the public keys from processes 0..conf.getN()-1 (all servers).
*
* @return the array of public keys loaded
* @throws Exception problems reading or parsing the keys
*/
/* public PublicKey[] loadServersPublicKeys() throws Exception {
if(pubKeys == null){
pubKeys = new PublicKey[conf.getN()];
for(int i = 0; i < pubKeys.length; i++){
pubKeys[i] = loadPublicKey(i);
}
}
return pubKeys;
}*/
/**
* Loads the public key of some processes from configuration files
*
* @param id the id of the process that we want to load the public key
* @return the PublicKey loaded from config/keys/publickey<id>
* @throws Exception problems reading or parsing the key
*/
public PublicKey loadPublicKey(int id) throws Exception {
PublicKey ret = this.pubKeys.get(id);
if (ret == null) {
BufferedReader r = new BufferedReader(new FileReader(path + "publickey" + id));
String tmp = "";
String key = "";
while ((tmp = r.readLine()) != null) {
key = key + tmp;
}
r.close();
ret = getPublicKeyFromString(key);
this.pubKeys.put(id, ret);
}
return ret;
}
/**
* Loads the private key of this process
*
* @return the PrivateKey loaded from config/keys/publickey<conf.getProcessId()>
* @throws Exception problems reading or parsing the key
*/
public PrivateKey loadPrivateKey() throws Exception {
if (priKey == null) {
BufferedReader r = new BufferedReader(
new FileReader(path + "privatekey" + conf.getProcessId()));
String tmp = "";
String key = "";
while ((tmp = r.readLine()) != null) {
key = key + tmp;
}
r.close();
priKey = getPrivateKeyFromString(key);
}
return priKey;
}
//utility methods for going from string to public/private key
private PrivateKey getPrivateKeyFromString(String key) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key));
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
return privateKey;
}
private PublicKey getPublicKeyFromString(String key) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(key));
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
return publicKey;
}
private String path;
private PrivateKey priKey;
/** Creates a new instance of RSAKeyLoader */
public RSAKeyLoader(String configHome) {
if (configHome.equals("")) {
path = "config" + System.getProperty("file.separator") + "keys" +
System.getProperty("file.separator");
} else {
path = configHome + System.getProperty("file.separator") + "keys" +
System.getProperty("file.separator");
}
}
/**
* Loads the public key of some processes from configuration files
*
* @return the PublicKey loaded from config/keys/publickey<id>
* @throws Exception problems reading or parsing the key
*/
public PublicKey loadPublicKey() throws Exception {
BufferedReader r = new BufferedReader(new FileReader(path + "publickey"));
String tmp = "";
String key = "";
while ((tmp = r.readLine()) != null) {
key = key + tmp;
}
r.close();
PublicKey ret = getPublicKeyFromString(key);
return ret;
}
/**
* Loads the private key of this process
*
* @return the PrivateKey loaded from config/keys/publickey<conf.getProcessId()>
* @throws Exception problems reading or parsing the key
*/
public PrivateKey loadPrivateKey() throws Exception {
if (priKey == null) {
BufferedReader r = new BufferedReader(
new FileReader(path + "privatekey"));
String tmp = "";
String key = "";
while ((tmp = r.readLine()) != null) {
key = key + tmp;
}
r.close();
priKey = getPrivateKeyFromString(key);
}
return priKey;
}
//utility methods for going from string to public/private key
private PrivateKey getPrivateKeyFromString(String key) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key));
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
return privateKey;
}
private PublicKey getPublicKeyFromString(String key) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(key));
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
return publicKey;
}
}
......@@ -314,7 +314,7 @@ public class TOMConfiguration extends Configuration {
globalCheckpointPeriod = Integer.parseInt(s);
}
rsaLoader = new RSAKeyLoader(this, TOMConfiguration.configHome);
rsaLoader = new RSAKeyLoader(TOMConfiguration.configHome);
} catch (Exception e) {
e.printStackTrace(System.err);
......@@ -359,7 +359,7 @@ public class TOMConfiguration extends Configuration {
public int getF() {
return f;
}
public int getPaxosHighMark() {
return paxosHighMark;
}
......@@ -468,9 +468,9 @@ public class TOMConfiguration extends Configuration {
return useControlFlow;
}
public PublicKey getRSAPublicKey(int id) {
public PublicKey getRSAPublicKey() {
try {
return rsaLoader.loadPublicKey(id);
return rsaLoader.loadPublicKey();
} catch (Exception e) {
e.printStackTrace(System.err);
return null;
......
......@@ -16,50 +16,63 @@
* 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.tom;
package bftsmart.statemanagement;
import bftsmart.tom.core.messages.TOMMessage;
import java.io.Serializable;
/**
* Interface meant for objects that receive requests from clients
* This classe represents a state tranfered from a replica to another. The state associated with the last
* checkpoint together with all the batches of messages received do far, comprises the sender's
* current state
*
* IMPORTANT: The hash state MUST ALWAYS be present, regardless if the replica is supposed to
* send the complete state or not
*
* @author Jo�o Sousa
*/
public interface TOMReceiver {
public interface ApplicationState extends Serializable {
/**
* This is the method invoked by the DeliveryThread to deliver a message to the receiver.
* It is used to receive readonly messages. These types of messages are delivered as
* soon as they are received by TomLayer
*
* @param msg The request delivered by the TOM layer
* The consensus of the last batch of commands which the application was given
* @return consensus of the last batch of commands which the application was given
*/
public void receiveReadonlyMessage(TOMMessage msg, MessageContext msgCtx);
/**
* This is the method invoked by the DeliveryThread to deliver a batch of messages to
* the receiver.
* If the receiver implements the BatchExcetutable interface, the messages are delivered
* as a bath. Otherwise, messages are delivered one by one.
*
* @param consId The id of the consensus in which the messages were ordered.
* @param regency
* @param requests The batch with TOMMessage objects.
*/
public void receiveMessages(int consId, int regency, boolean fromConsensus, TOMMessage[] requests, byte[] decision);
public int getLastEid();
/**
* Indicates if the sender replica had the state requested by the recovering replica
* @return true if the sender replica had the state requested by the recovering replica, false otherwise
*/
public boolean hasState();
/**
* This method is used by the TOM Layer to retrieve the state of the application. This must be
* implemented by the programmer, and it should retrieve an array of bytes that contains the application
* state.
* @return An rray of bytes that can be diserialized into the application state
* Sets a byte array that must be a representation of the application state
* @param state a byte array that must be a representation of the application state
*/
//public byte[] getState();
public void setSerializedState(byte[] state);
/**
* Byte array that must be a representation of the application state
* @returns A byte array that must be a representation of the application state
*/
public byte[] getSerializedState();
/**
* Gets an secure hash of the application state
* @return Secure hash of the application state
*/
public byte[] getStateHash();
/**
* This method is invoked by the TOM Layer in order to ser a state upon the aplication. This is done when
* a replica is delayed compared to the rest of the group, and when it recovers after a failure.
* This method MUST be implemented. However, the attribute returned by getSerializedState()
* should be ignored, and getStateHash() should be used instead
*/
//public void setState(byte[] state);
@Override
public abstract boolean equals(Object obj);
/**
* This method MUST be implemented. However, the attribute returned by getSerializedState()
* should be ignored, and getStateHash() should be used instead
*/
@Override
public abstract int hashCode();
}
/**
* 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.statemanagement;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import bftsmart.communication.SystemMessage;
import bftsmart.reconfiguration.views.View;
import bftsmart.tom.util.TOMUtil;
/**
* This classe represents a message used in the state transfer protocol
*
* @author Jo�o Sousa
*/
public abstract class SMMessage extends SystemMessage implements Externalizable {
private ApplicationState state; // State log
private View view;
private int eid; // Execution ID up to which the sender needs to be updated
private int type; // Message type
private int regency; // Current regency
private int leader; // Current leader
public final boolean TRIGGER_SM_LOCALLY; // indicates that the replica should
// initiate the SM protocol locally
/**
* Constructs a SMMessage
* @param sender Process Id of the sender
* @param eid Execution ID up to which the sender needs to be updated
* @param type Message type
* @param replica Replica that should send the state
* @param state State log
*/
protected SMMessage(int sender, int eid, int type, ApplicationState state, View view, int regency, int leader) {
super(sender);
this.state = state;
this.view = view;
this.eid = eid;
this.type = type;
this.sender = sender;
this.regency = regency;
this.leader = leader;
if (type == TOMUtil.TRIGGER_SM_LOCALLY && sender == -1) this.TRIGGER_SM_LOCALLY = true;
else this.TRIGGER_SM_LOCALLY = false;
}
protected SMMessage() {
this.TRIGGER_SM_LOCALLY = false;
}
/**
* Retrieves the state log
* @return The state Log
*/
public ApplicationState getState() {
return state;
}
/**
* Retrieves the state log
* @return The state Log
*/
public View getView() {
return view;
}
/**
* Retrieves the type of the message
* @return The type of the message
*/
public int getType() {
return type;
}
/**
* Retrieves the execution ID up to which the sender needs to be updated
* @return The execution ID up to which the sender needs to be updated
*/
public int getEid() {
return eid;
}
/**
* Retrieves the regency that the replica had when sending the state
* @return The regency that the replica had when sending the state
*/
public int getRegency() {
return regency;
}
/**
* Retrieves the leader that the replica had when sending the state
* @return The leader that the replica had when sending the state
*/
public int getLeader() {
return leader;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException{
super.writeExternal(out);
out.writeInt(sender);
out.writeInt(eid);
out.writeInt(type);
out.writeInt(regency);
out.writeInt(leader);
out.writeObject(state);
out.writeObject(view);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
super.readExternal(in);
sender = in.readInt();
eid = in.readInt();
type = in.readInt();
regency = in.readInt();
leader = in.readInt();
state = (ApplicationState) in.readObject();
view = (View) in.readObject();
}
}
/**
* Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags
*
* This file is part of BFT-SMaRt.
*
* BFT-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.
*
* BFT-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.statemanagement;
import bftsmart.tom.core.DeliveryThread;
import bftsmart.tom.core.TOMLayer;
/**
* TODO: Don't know if this class will be used. For now, leave it here
*
* Check if the changes for supporting dynamicity are correct
*
* @author Joao Sousa
*/
public interface StateManager {
public void requestAppState(int eid);
public void analyzeState(int eid);
public void stateTimeout();
public void init(TOMLayer tomLayer, DeliveryThread dt);
public void SMRequestDeliver(SMMessage msg);
public void SMReplyDeliver(SMMessage msg);
public boolean isRetrievingState();
}
package bftsmart.statemanagement.strategy;
import java.util.Collection;
import java.util.HashMap;
import bftsmart.reconfiguration.ServerViewManager;
import bftsmart.reconfiguration.views.View;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.statemanagement.SMMessage;
import bftsmart.statemanagement.StateManager;
import bftsmart.tom.core.DeliveryThread;
import bftsmart.tom.core.TOMLayer;
import bftsmart.tom.util.Logger;
public abstract class BaseStateManager implements StateManager {
protected TOMLayer tomLayer;
protected ServerViewManager SVManager;
protected HashMap<Integer, ApplicationState> senderStates = null;
protected HashMap<Integer, View> senderViews = null;
protected HashMap<Integer, Integer> senderRegencies = null;
protected HashMap<Integer, Integer> senderLeaders = null;
protected boolean appStateOnly;
protected int waitingEid = -1;
protected int lastEid;
protected ApplicationState state;
public BaseStateManager() {
senderStates = new HashMap<Integer, ApplicationState>();
senderViews = new HashMap<Integer, View>();
senderRegencies = new HashMap<Integer, Integer>();
senderLeaders = new HashMap<Integer, Integer>();
}
protected int getReplies() {
return senderStates.size();
}
protected boolean moreThanF_Replies() {
return senderStates.size() > SVManager.getCurrentViewF();
}
protected boolean moreThan2F_Regencies(int regency) {
return senderRegencies.size() > SVManager.getQuorum2F();
}
protected boolean moreThan2F_Leaders(int leader) {
return senderLeaders.size() > SVManager.getQuorum2F();
}
protected boolean moreThan2F_Views(View view) {
Collection<View> views = senderViews.values();
int counter = 0;
for(View v : views) {
if(view.equals(v))
counter++;
}
boolean result = counter > SVManager.getQuorum2F();
views = null;
return result;
}
/**
* Clear the collections and state hold by this object.
* Calls clear() in the States, Leaders, Regenviews and Views collections.
* Sets the state to null;
*/
protected void reset() {
senderStates.clear();
senderLeaders.clear();
senderRegencies.clear();
senderViews.clear();
state = null;
}
public Collection<ApplicationState> receivedStates() {
return senderStates.values();
}
public void setLastEID(int eid) {
lastEid = eid;
}
public int getLastEID() {
return lastEid;
}
@Override
public void requestAppState(int eid) {
lastEid = eid + 1;
waitingEid = eid;
System.out.println("waitingeid is now " + eid);
appStateOnly = true;
requestState();
}
@Override
public void analyzeState(int eid) {
Logger.println("(TOMLayer.analyzeState) The state transfer protocol is enabled");
if (waitingEid == -1) {
Logger.println("(TOMLayer.analyzeState) I'm not waiting for any state, so I will keep record of this message");
if (tomLayer.execManager.isDecidable(eid)) {
System.out.println("(TOMLayer.analyzeState) I have now more than " + SVManager.getCurrentViewF() + " messages for EID " + eid + " which are beyond EID " + lastEid);
lastEid = eid;
waitingEid = eid - 1;
System.out.println("analyzeState " + waitingEid);
requestState();
}
}
}
@Override
public abstract void init(TOMLayer tomLayer, DeliveryThread dt);
@Override
public boolean isRetrievingState() {
return waitingEid > -1;
}
protected abstract void requestState();
@Override
public abstract void stateTimeout();
@Override
public abstract void SMRequestDeliver(SMMessage msg);
@Override
public abstract void SMReplyDeliver(SMMessage msg);
}
package bftsmart.statemanagement.strategy;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import bftsmart.reconfiguration.views.View;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.statemanagement.SMMessage;
public class StandardSMMessage extends SMMessage {
private int replica;
public StandardSMMessage(int sender, int eid, int type, int replica, ApplicationState state, View view, int regency, int leader) {
super(sender, eid, type, state, view, regency, leader);
this.replica = replica;
}
public StandardSMMessage() {
super();
}
/**
* Retrieves the replica that should send the state
* @return The replica that should send the state
*/
public int getReplica() {
return replica;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException{
super.writeExternal(out);
out.writeInt(replica);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
super.readExternal(in);
replica = in.readInt();
}
}
package bftsmart.statemanagement.strategy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.ReentrantLock;
import bftsmart.paxosatwar.executionmanager.ExecutionManager;
import bftsmart.paxosatwar.messages.PaxosMessage;
import bftsmart.reconfiguration.views.View;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.statemanagement.SMMessage;
import bftsmart.tom.core.DeliveryThread;
import bftsmart.tom.core.TOMLayer;
import bftsmart.tom.leaderchange.LCManager;
import bftsmart.tom.util.Logger;
import bftsmart.tom.util.TOMUtil;
public class StandardStateManager extends BaseStateManager {
private int replica;
private ReentrantLock lockTimer = new ReentrantLock();
private Timer stateTimer = null;
private final static long INIT_TIMEOUT = 40000;
private long timeout = INIT_TIMEOUT;
private DeliveryThread dt;
private LCManager lcManager;
private ExecutionManager execManager;
@Override
public void init(TOMLayer tomLayer, DeliveryThread dt) {
SVManager = tomLayer.reconfManager;
this.tomLayer = tomLayer;
this.dt = dt;
this.lcManager = tomLayer.getLCManager();
this.execManager = tomLayer.execManager;
this.replica = 0;
if (replica == SVManager.getStaticConf().getProcessId())
changeReplica();
state = null;
lastEid = 1;
waitingEid = -1;
appStateOnly = false;
}
private void changeReplica() {
int pos = -1;
do {
pos = this.SVManager.getCurrentViewPos(replica);
replica = this.SVManager.getCurrentViewProcesses()[(pos + 1) % SVManager.getCurrentViewN()];
} while (replica == SVManager.getStaticConf().getProcessId());
}
@Override
protected void requestState() {
if (tomLayer.requestsTimer != null)
tomLayer.requestsTimer.clearAll();
SMMessage smsg = new StandardSMMessage(SVManager.getStaticConf().getProcessId(),
waitingEid, TOMUtil.SM_REQUEST, replica, null, null, -1, -1);
tomLayer.getCommunication().send(SVManager.getCurrentViewOtherAcceptors(), smsg);
System.out.println("(TOMLayer.requestState) I just sent a request to the other replicas for the state up to EID " + waitingEid);
TimerTask stateTask = new TimerTask() {
public void run() {
System.out.println("Timeout to retrieve state");
int[] myself = new int[1];
myself[0] = SVManager.getStaticConf().getProcessId();
tomLayer.getCommunication().send(myself, new StandardSMMessage(-1, waitingEid, TOMUtil.TRIGGER_SM_LOCALLY, -1, null, null, -1, -1));
}
};
stateTimer = new Timer("state timer");
timeout = timeout * 2;
stateTimer.schedule(stateTask,timeout);
}
@Override
public void stateTimeout() {
lockTimer.lock();
Logger.println("(StateManager.stateTimeout) Timeout for the replica that was supposed to send the complete state. Changing desired replica.");
System.out.println("Timeout no timer do estado!");
if (stateTimer != null)
stateTimer.cancel();
changeReplica();
reset();
requestState();
lockTimer.unlock();
}
@Override
public void SMRequestDeliver(SMMessage msg) {
if (SVManager.getStaticConf().isStateTransferEnabled() && dt.getRecoverer() != null) {
StandardSMMessage stdMsg = (StandardSMMessage)msg;
boolean sendState = stdMsg.getReplica() == SVManager.getStaticConf().getProcessId();
ApplicationState thisState = dt.getRecoverer().getState(msg.getEid(), sendState);
if (thisState == null) {
thisState = dt.getRecoverer().getState(-1, sendState);
}
int[] targets = { msg.getSender() };
SMMessage smsg = new StandardSMMessage(SVManager.getStaticConf().getProcessId(),
msg.getEid(), TOMUtil.SM_REPLY, -1, thisState, SVManager.getCurrentView(), lcManager.getLastReg(), tomLayer.lm.getCurrentLeader());
System.out.println("Sending state");
tomLayer.getCommunication().send(targets, smsg);
System.out.println("Sent");
}
}
@Override
public void SMReplyDeliver(SMMessage msg) {
lockTimer.lock();
if (SVManager.getStaticConf().isStateTransferEnabled()) {
if (waitingEid != -1 && msg.getEid() == waitingEid) {
int currentRegency = -1;
int currentLeader = -1;
View currentView = null;
if (!appStateOnly) {
senderRegencies.put(msg.getSender(), msg.getRegency());
senderLeaders.put(msg.getSender(), msg.getLeader());
senderViews.put(msg.getSender(), msg.getView());
if (moreThan2F_Regencies(msg.getRegency())) currentRegency = msg.getRegency();
if (moreThan2F_Leaders(msg.getLeader())) currentLeader = msg.getLeader();
if (moreThan2F_Views(msg.getView())) {
currentView = msg.getView();
}
} else {
currentLeader = tomLayer.lm.getCurrentLeader();
currentRegency = lcManager.getLastReg();
currentView = SVManager.getCurrentView();
}
if (msg.getSender() == replica && msg.getState().getSerializedState() != null) {
System.out.println("Expected replica sent state. Setting it to state");
state = msg.getState();
if (stateTimer != null) stateTimer.cancel();
}
senderStates.put(msg.getSender(), msg.getState());
System.out.println("Verifying more than F replies");
if (moreThanF_Replies()) {
System.out.println("More than F confirmed");
ApplicationState otherReplicaState = getOtherReplicaState();
System.out.println("State != null: " + (state != null) + ", recvState != null: " + (otherReplicaState != null));
int haveState = 0;
if(state != null) {
byte[] hash = null;
hash = tomLayer.computeHash(state.getSerializedState());
if (otherReplicaState != null) {
if (Arrays.equals(hash, otherReplicaState.getStateHash())) haveState = 1;
else if (getNumEqualStates() > SVManager.getCurrentViewF())
haveState = -1;
}
}
System.out.println("haveState: " + haveState);
if (otherReplicaState != null && haveState == 1 && currentRegency > -1 &&
currentLeader > -1 && currentView != null) {
System.out.println("Received state. Will install it");
lcManager.setLastReg(currentRegency);
lcManager.setNextReg(currentRegency);
lcManager.setNewLeader(currentLeader);
tomLayer.lm.setNewLeader(currentLeader);
dt.deliverLock();
waitingEid = -1;
dt.update(state);
if (!appStateOnly && execManager.stopped()) {
Queue<PaxosMessage> stoppedMsgs = execManager.getStoppedMsgs();
for (PaxosMessage stopped : stoppedMsgs) {
if (stopped.getNumber() > state.getLastEid() /*msg.getEid()*/)
execManager.addOutOfContextMessage(stopped);
}
execManager.clearStopped();
execManager.restart();
}
tomLayer.processOutOfContext();
if (SVManager.getCurrentViewId() != currentView.getId()) {
System.out.println("Installing current view!");
SVManager.reconfigureTo(currentView);
}
dt.canDeliver();
dt.deliverUnlock();
reset();
System.out.println("I updated the state!");
tomLayer.requestsTimer.Enabled(true);
tomLayer.requestsTimer.startTimer();
if (stateTimer != null) stateTimer.cancel();
if (appStateOnly) {
appStateOnly = false;
tomLayer.resumeLC();
}
} else if (otherReplicaState == null && (SVManager.getCurrentViewN() / 2) < getReplies()) {
waitingEid = -1;
reset();
if (stateTimer != null) stateTimer.cancel();
if (appStateOnly) {
requestState();
}
} else if (haveState == -1) {
Logger.println("(TOMLayer.SMReplyDeliver) The replica from which I expected the state, sent one which doesn't match the hash of the others, or it never sent it at all");
changeReplica();
reset();
requestState();
if (stateTimer != null) stateTimer.cancel();
}
}
}
}
lockTimer.unlock();
}
/**
* Search in the received states table for a state that was not sent by the expected
* replica. This is used to compare both states after received the state from expected
* and other replicas.
* @return The state sent from other replica
*/
private ApplicationState getOtherReplicaState() {
int[] processes = SVManager.getCurrentViewProcesses();
for(int process : processes) {
if(process == replica)
continue;
else {
ApplicationState otherState = senderStates.get(process);
if(otherState != null)
return otherState;
}
}
return null;
}
private int getNumEqualStates() {
List<ApplicationState> states = new ArrayList<ApplicationState>(receivedStates());
int match = 0;
for (ApplicationState st1 : states) {
int count = 0;
for (ApplicationState st2 : states) {
if(st1 != null && st1.equals(st2))
count++;
}
if(count > match)
match = count;
}
return match;
}
}
package bftsmart.statemanagement.strategy.durability;
import java.io.Serializable;
/**
* This class is used to define the roles in the Collaborative State Transfer protocol.
* The recovering replica uses this class to define which replicas should send the
* checkpoint, log of opperations lower and higher portions
*
* @author Marcel Santos
*/
public abstract class CSTRequest implements Serializable {
private static final long serialVersionUID = 7463498141366035002L;
protected int eid;
/** id of the replica responsible for sending the checkpoint;*/
protected int checkpointReplica;
public CSTRequest(int eid) {
this.eid = eid;
}
public int getEid() {
return eid;
}
public int getCheckpointReplica() {
return checkpointReplica;
}
public abstract void defineReplicas(int[] processes, int globalCkpPeriod, int replicaId);
}
package bftsmart.statemanagement.strategy.durability;
import java.net.InetSocketAddress;
/**
* This class is used to define the roles in the Collaborative State Transfer protocol.
* The recovering replica uses this class to define which replicas should send the
* checkpoint, log of operations lower and higher portions
*
* @author Marcel Santos
*/
public class CSTRequestF1 extends CSTRequest {
private static final long serialVersionUID = 6298204287341984504L;
/** id of the replica responsible for sending the upper portion of the log;*/
private int logUpper;
/** id of the replica responsible for sending the lower portion of the log;*/
private int logLower;
private int ckpPeriod;
private int logUpperSize;
// private int logLowerSkip;
private int logLowerSize;
private InetSocketAddress address;
public CSTRequestF1(int eid) {
super(eid);
}
// public int getCkpPeriod() {
// return this.ckpPeriod;
// }
//
public int getLogUpper() {
return logUpper;
}
public void setLogUpper(int logUpper) {
this.logUpper = logUpper;
}
public int getLogLower() {
return logLower;
}
public void setLogLower(int logLower) {
this.logLower = logLower;
}
public int getLogUpperSize() {
return logUpperSize;
}
/**
* Define and set the attributes of this CST Request according to the
* algorithm described in the durability state transfer paper.
* In summary, the algorithm defines that, in a situation with three
* seeders, the seeder in the middle (the one that took the checkpoint
* just after the oldest) must send the checkpoint. The oldest must
* send the log of the period between the middle checkpoint until the
* checkpoint of the newest replica. The newest replica must send the
* log from the begging to the eid requested.
*/
public void defineReplicas(int[] otherReplicas, int globalCkpPeriod, int me) {
int N = otherReplicas.length + 1; // The total number of replicas is the others plus me
ckpPeriod = globalCkpPeriod / N;
// logLowerSkip = ckpPeriod;
logLowerSize = ckpPeriod;
logUpperSize = (eid + 1) % ckpPeriod;
// position of the replica with the oldest checkpoint in the others array
int oldestReplicaPosition = getOldest(otherReplicas, eid, globalCkpPeriod, me);
logLower = otherReplicas[oldestReplicaPosition];
checkpointReplica = otherReplicas[(oldestReplicaPosition + 1) % otherReplicas.length];
logUpper = otherReplicas[(oldestReplicaPosition + 2) % otherReplicas.length];
}
/**
* Iterates over the others array to find the oldest replica to generate the
* checkpoint. In the case where the oldest replica to generate the checkpoint
* is me, and therefore, it is not in the others array, it is returned the
* replica with id immediate before me
* @param others the other replicas in BFT-SMaRt
* @param eid the eid that I am requesting
* @param globalCheckpointPeriod the global checkpoint period in which all replicas
* should perform the checkpoint
* @param me my id
* @return the position of the replica with the latest checkpoint in the others array
*/
private int getOldest(int[] others, int eid, int globalCheckpointPeriod, int me) {
int N = others.length + 1;
int oldestCkpReplica = (eid % globalCheckpointPeriod) / (globalCheckpointPeriod / N);
if(oldestCkpReplica == me) {
oldestCkpReplica = (oldestCkpReplica + 1) % N;
} else if((oldestCkpReplica + 3) % N == me) {
logUpperSize = ((eid + 1) % ckpPeriod) + ckpPeriod;
} else if((oldestCkpReplica + 2) % N == me) {
logLowerSize = 2 * ckpPeriod;
} else {
}
for(int i = 0; i < others.length; i++) {
if(others[i] == oldestCkpReplica)
return i;
}
return -1;
}
public InetSocketAddress getAddress() {
return address;
}
public void setAddress(InetSocketAddress address) {
this.address = address;
}
// public int getLogLowerSkip() {
// return logLowerSkip;
// }
public int getLogLowerSize() {
return logLowerSize;
}
}
package bftsmart.statemanagement.strategy.durability;
/**
* This class is used to define the roles in the Collaborative State Transfer protocol.
* The recovering replica uses this class to define which replicas should send the
* checkpoint, log of opperations lower and higher portions
*
* @author Marcel Santos
*/
public class CSTRequestFGT1 extends CSTRequest {
private static final long serialVersionUID = 7661647491651173164L;
private int hashesReplica;
/** number of requests to be processed in the recovering replica before validate the ckp hash */
private int nbrHashesBeforeCkp;
/** number of messages that should be in the batch
* if the replica is the one to send the checkpoint it will correspond to the actual log
*/
private int logSize;
public CSTRequestFGT1(int eid) {
super(eid);
}
public int getHashesReplica() {
return hashesReplica;
}
public int getNbrHashesBeforeCkp() {
return nbrHashesBeforeCkp;
}
public int getLogSize() {
return logSize;
}
@Override
public void defineReplicas(int[] processes, int globalCkpPeriod, int replicaId) {
int N = processes.length;
int ckpPeriod = globalCkpPeriod / N;
int logSize = (eid + 1) % ckpPeriod;
// Next replica that performed the checkpoint
// The last checkpoint replica plus all replicas minus one to get the imediate replica before the
// checkpoint
int indexCkpReplica = (((getEid() - ckpPeriod) % globalCkpPeriod) / ckpPeriod) % N;
this.hashesReplica = processes[indexCkpReplica];
this.checkpointReplica = processes[(indexCkpReplica + (N - 1)) % N];
this.nbrHashesBeforeCkp = ckpPeriod;
logSize += ckpPeriod;
if(this.checkpointReplica == replicaId) { // me
this.checkpointReplica = processes[(indexCkpReplica + (N - 2)) % N];
this.nbrHashesBeforeCkp = 2 * ckpPeriod;
logSize += ckpPeriod;
} else if(this.hashesReplica == replicaId) {
this.hashesReplica = processes[(indexCkpReplica + (N - 1)) % N];
this.checkpointReplica = processes[(indexCkpReplica + (N - 2)) % N];
logSize += ckpPeriod;
}
this.logSize = logSize;
}
}
package bftsmart.statemanagement.strategy.durability;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import bftsmart.reconfiguration.views.View;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.statemanagement.SMMessage;
public class CSTSMMessage extends SMMessage {
private CSTRequestF1 cstConfig;
public CSTSMMessage(int sender, int eid, int type, CSTRequestF1 cstConfig, ApplicationState state, View view, int regency, int leader) {
super(sender, eid, type, state, view, regency, leader);
this.cstConfig = cstConfig;
}
public CSTSMMessage() {
super();
}
public CSTRequestF1 getCstConfig() {
return cstConfig;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException{
super.writeExternal(out);
out.writeObject(cstConfig);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
super.readExternal(in);
cstConfig = (CSTRequestF1)in.readObject();
}
}
package bftsmart.statemanagement.strategy.durability;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.tom.server.defaultservices.CommandsInfo;
/**
* Stores the data used to transfer the state to a recovering replica.
* This class serves the three different seeders defined in the CST optimized
* version for f=1.
* In that version, the newest replica to take the checkpoint is expected to send
* the hash of the checkpoint plus the upper portion of the log. The replica which
* took the checkpoint before that, i.e., the middle replica is expected to send
* the checkpoint it has plus hashes of the lower and upper portions of the log.
* The oldest replica to take the checkpoint must send the lower portion of the
* log.
* This object must be passed to the state manager class which will combine the
* replies from the seeders, validating the values and updating the state in the
* leecher.
*
* @author mhsantos
*
*/
public class CSTState implements ApplicationState {
private static final long serialVersionUID = -7624656762922101703L;
private final byte[] hashLogUpper;
private final byte[] hashLogLower;
private final byte[] hashCheckpoint;
private final int checkpointEid;
private final int lastEid;
private final CommandsInfo[] logUpper;
private final CommandsInfo[] logLower;
private byte[] state;
public CSTState(byte[] state, byte[] hashCheckpoint, CommandsInfo[] logLower, byte[] hashLogLower,
CommandsInfo[] logUpper, byte[] hashLogUpper, int checkpointEid, int lastEid) {
setSerializedState(state);
this.hashLogUpper = hashLogUpper;
this.hashLogLower = hashLogLower;
this.hashCheckpoint = hashCheckpoint;
this.logUpper = logUpper;
this.logLower = logLower;
this.checkpointEid = checkpointEid;
this.lastEid = lastEid;
}
@Override
public boolean hasState() {
return this.getSerializedState() != null;
}
@Override
public byte[] getSerializedState() {
return state;
}
@Override
public byte[] getStateHash() {
return hashCheckpoint;
}
@Override
public void setSerializedState(byte[] state) {
this.state = state;
}
@Override
public int getLastEid() {
return lastEid;
}
public int getCheckpointEid() {
return checkpointEid;
}
/**
* Retrieves the specified batch of messages
* @param eid Execution ID associated with the batch to be fetched
* @return The batch of messages associated with the batch correspondent execution ID
*/
public CommandsInfo getMessageBatch(int eid) {
if (eid >= checkpointEid && eid <= lastEid) {
if(logLower != null) {
return logLower[eid - checkpointEid - 1];
} else {
return logUpper[eid - checkpointEid - 1];
}
} else {
return null;
}
}
public byte[] getHashLogUpper() {
return hashLogUpper;
}
public byte[] getHashLogLower() {
return hashLogLower;
}
public CommandsInfo[] getLogUpper() {
return logUpper;
}
public CommandsInfo[] getLogLower() {
return logLower;
}
public byte[] getHashCheckpoint() {
return hashCheckpoint;
}
}
package bftsmart.statemanagement.strategy.durability;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Queue;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.ReentrantLock;
import bftsmart.paxosatwar.executionmanager.ExecutionManager;
import bftsmart.paxosatwar.messages.PaxosMessage;
import bftsmart.reconfiguration.views.View;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.statemanagement.SMMessage;
import bftsmart.statemanagement.strategy.BaseStateManager;
import bftsmart.statemanagement.strategy.durability.CSTState;
import bftsmart.tom.core.DeliveryThread;
import bftsmart.tom.core.TOMLayer;
import bftsmart.tom.leaderchange.LCManager;
import bftsmart.tom.server.defaultservices.CommandsInfo;
import bftsmart.tom.server.defaultservices.durability.DurabilityCoordinator;
import bftsmart.tom.util.Logger;
import bftsmart.tom.util.TOMUtil;
public class DurableStateManager extends BaseStateManager {
private DeliveryThread dt;
private LCManager lcManager;
private ExecutionManager execManager;
private ReentrantLock lockTimer = new ReentrantLock();
private Timer stateTimer = null;
private final static long INIT_TIMEOUT = 40000;
private long timeout = INIT_TIMEOUT;
private CSTRequestF1 cstRequest;
private CSTState stateCkp;
private CSTState stateLower;
private CSTState stateUpper;
@Override
public void init(TOMLayer tomLayer, DeliveryThread dt) {
SVManager = tomLayer.reconfManager;
this.tomLayer = tomLayer;
this.dt = dt;
this.lcManager = tomLayer.getLCManager();
this.execManager = tomLayer.execManager;
state = null;
lastEid = 1;
waitingEid = -1;
System.out.println("waitingeid is -1");
appStateOnly = false;
}
@Override
protected void requestState() {
if (tomLayer.requestsTimer != null)
tomLayer.requestsTimer.clearAll();
int myProcessId = SVManager.getStaticConf().getProcessId();
int[] otherProcesses = SVManager.getCurrentViewOtherAcceptors();
int globalCkpPeriod = SVManager.getStaticConf()
.getGlobalCheckpointPeriod();
CSTRequestF1 cst = new CSTRequestF1(waitingEid);
cst.defineReplicas(otherProcesses, globalCkpPeriod, myProcessId);
this.cstRequest = cst;
CSTSMMessage cstMsg = new CSTSMMessage(myProcessId, waitingEid,
TOMUtil.SM_REQUEST, cst, null, null, -1, -1);
tomLayer.getCommunication().send(
SVManager.getCurrentViewOtherAcceptors(), cstMsg);
System.out
.println("(TOMLayer.requestState) I just sent a request to the other replicas for the state up to EID "
+ waitingEid);
TimerTask stateTask = new TimerTask() {
public void run() {
int[] myself = new int[1];
myself[0] = SVManager.getStaticConf().getProcessId();
tomLayer.getCommunication().send(
myself,
new CSTSMMessage(-1, waitingEid,
TOMUtil.TRIGGER_SM_LOCALLY, null, null, null,
-1, -1));
}
};
stateTimer = new Timer("state timer");
timeout = timeout * 2;
stateTimer.schedule(stateTask, timeout);
}
@Override
public void stateTimeout() {
lockTimer.lock();
Logger.println("(StateManager.stateTimeout) Timeout for the replica that was supposed to send the complete state. Changing desired replica.");
System.out.println("Timeout no timer do estado!");
if (stateTimer != null)
stateTimer.cancel();
reset();
requestState();
lockTimer.unlock();
}
@Override
public void SMRequestDeliver(SMMessage msg) {
System.out.println("(TOMLayer.SMRequestDeliver) invoked method");
Logger.println("(TOMLayer.SMRequestDeliver) invoked method");
if (SVManager.getStaticConf().isStateTransferEnabled()
&& dt.getRecoverer() != null) {
Logger.println("(TOMLayer.SMRequestDeliver) The state transfer protocol is enabled");
Logger.println("(TOMLayer.SMRequestDeliver) I received a state request for EID "
+ msg.getEid() + " from replica " + msg.getSender());
CSTSMMessage cstMsg = (CSTSMMessage) msg;
CSTRequestF1 cstConfig = cstMsg.getCstConfig();
boolean sendState = cstConfig.getCheckpointReplica() == SVManager
.getStaticConf().getProcessId();
if (sendState)
Logger.println("(TOMLayer.SMRequestDeliver) I should be the one sending the state");
System.out.println("--- state asked");
int[] targets = { msg.getSender() };
InetSocketAddress address = SVManager.getCurrentView().getAddress(
SVManager.getStaticConf().getProcessId());
String myIp = address.getHostName();
int myId = SVManager.getStaticConf().getProcessId();
int port = 4444 + myId;
address = new InetSocketAddress(myIp, port);
cstConfig.setAddress(address);
CSTSMMessage reply = new CSTSMMessage(myId, msg.getEid(),
TOMUtil.SM_REPLY, cstConfig, null,
SVManager.getCurrentView(), lcManager.getLastReg(),
tomLayer.lm.getCurrentLeader());
StateSenderServer stateServer = new StateSenderServer(port);
stateServer.setRecoverable(dt.getRecoverer());
stateServer.setRequest(cstConfig);
new Thread(stateServer).start();
tomLayer.getCommunication().send(targets, reply);
}
}
@Override
public void SMReplyDeliver(SMMessage msg) {
lockTimer.lock();
CSTSMMessage reply = (CSTSMMessage) msg;
if (SVManager.getStaticConf().isStateTransferEnabled()) {
Logger.println("(TOMLayer.SMReplyDeliver) The state transfer protocol is enabled");
System.out
.println("(TOMLayer.SMReplyDeliver) I received a state reply for EID "
+ reply.getEid()
+ " from replica "
+ reply.getSender());
System.out.println("--- Received eid: " + reply.getEid()
+ ". Waiting " + waitingEid);
if (waitingEid != -1 && reply.getEid() == waitingEid) {
int currentRegency = -1;
int currentLeader = -1;
View currentView = null;
if (!appStateOnly) {
senderRegencies.put(reply.getSender(), reply.getRegency());
senderLeaders.put(reply.getSender(), reply.getLeader());
senderViews.put(reply.getSender(), reply.getView());
if (moreThan2F_Regencies(reply.getRegency()))
currentRegency = reply.getRegency();
if (moreThan2F_Leaders(reply.getLeader()))
currentLeader = reply.getLeader();
if (moreThan2F_Views(reply.getView())) {
currentView = reply.getView();
if (!currentView.isMember(SVManager.getStaticConf()
.getProcessId())) {
System.out.println("Not a member!");
}
}
} else {
currentLeader = tomLayer.lm.getCurrentLeader();
currentRegency = lcManager.getLastReg();
currentView = SVManager.getCurrentView();
}
Logger.println("(TOMLayer.SMReplyDeliver) The reply is for the EID that I want!");
InetSocketAddress address = reply.getCstConfig().getAddress();
Socket clientSocket;
ApplicationState stateReceived = null;
try {
clientSocket = new Socket(address.getHostName(),
address.getPort());
ObjectInputStream in = new ObjectInputStream(
clientSocket.getInputStream());
stateReceived = (ApplicationState) in.readObject();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (stateReceived instanceof CSTState) {
senderStates.put(reply.getSender(), stateReceived);
if (reply.getSender() == cstRequest.getCheckpointReplica())
this.stateCkp = (CSTState) stateReceived;
if (reply.getSender() == cstRequest.getLogLower())
this.stateLower = (CSTState) stateReceived;
if (reply.getSender() == cstRequest.getLogUpper())
this.stateUpper = (CSTState) stateReceived;
}
if (senderStates.size() == 3) {
CommandsInfo[] lowerLog = stateLower.getLogLower();
CommandsInfo[] upperLog = stateUpper.getLogUpper();
System.out.print("lowerLog ");
if (lowerLog != null)
System.out.println(lowerLog.length);
System.out.print("upperLog ");
if (upperLog != null)
System.out.println(upperLog.length);
boolean haveState = false;
byte[] lowerbytes = TOMUtil.getBytes(lowerLog);
System.out.println("Log lower bytes size: "
+ lowerbytes.length);
byte[] upperbytes = TOMUtil.getBytes(upperLog);
System.out.println("Log upper bytes size: "
+ upperbytes.length);
byte[] lowerLogHash = TOMUtil.computeHash(lowerbytes);
byte[] upperLogHash = TOMUtil.computeHash(upperbytes);
// validate lower log
if (Arrays.equals(stateCkp.getHashLogLower(), lowerLogHash))
haveState = true;
else
System.out.println("Lower log don't match");
// validate upper log
if (!haveState || !Arrays.equals(stateCkp.getHashLogUpper(), upperLogHash)) {
haveState = false;
System.out.println("Upper log don't match");
}
CSTState statePlusLower = new CSTState(stateCkp.getSerializedState(),
TOMUtil.getBytes(stateCkp.getSerializedState()),
stateLower.getLogLower(), stateCkp.getHashLogLower(), null, null,
stateCkp.getCheckpointEid(), stateUpper.getCheckpointEid());
if (haveState) { // validate checkpoint
System.out.println("validating checkpoint!!!");
dt.getRecoverer().setState(statePlusLower);
byte[] currentStateHash = ((DurabilityCoordinator) dt.getRecoverer()).getCurrentStateHash();
if (!Arrays.equals(currentStateHash, stateUpper.getHashCheckpoint())) {
System.out.println("ckp hash don't match");
haveState = false;
}
}
System.out.println("-- current regency: " + currentRegency);
System.out.println("-- current leader: " + currentLeader);
System.out.println("-- current view: " + currentView);
if (currentRegency > -1 && currentLeader > -1
&& currentView != null && haveState) {
System.out.println("---- RECEIVED VALID STATE ----");
Logger.println("(TOMLayer.SMReplyDeliver) The state of those replies is good!");
Logger.println("(TOMLayer.SMReplyDeliver) EID State requested: " + reply.getEid());
Logger.println("(TOMLayer.SMReplyDeliver) EID State received: " + stateUpper.getLastEid());
lcManager.setLastReg(currentRegency);
lcManager.setNextReg(currentRegency);
lcManager.setNewLeader(currentLeader);
tomLayer.lm.setNewLeader(currentLeader);
System.out.print("trying to acquire deliverlock");
dt.deliverLock();
System.out.println("acquired");
// this makes the isRetrievingState() evaluates to false
waitingEid = -1;
dt.update(stateUpper);
// Deal with stopped messages that may come from
// synchronization phase
if (!appStateOnly && execManager.stopped()) {
Queue<PaxosMessage> stoppedMsgs = execManager.getStoppedMsgs();
for (PaxosMessage stopped : stoppedMsgs) {
if (stopped.getNumber() > state.getLastEid())
execManager.addOutOfContextMessage(stopped);
}
execManager.clearStopped();
execManager.restart();
}
System.out.println("Processing out of context messages");
tomLayer.processOutOfContext();
if (SVManager.getCurrentViewId() != currentView.getId()) {
System.out.println("Installing current view!");
SVManager.reconfigureTo(currentView);
}
dt.canDeliver();
dt.deliverUnlock();
reset();
System.out.println("I updated the state!");
tomLayer.requestsTimer.Enabled(true);
tomLayer.requestsTimer.startTimer();
if (stateTimer != null)
stateTimer.cancel();
if (appStateOnly) {
appStateOnly = false;
tomLayer.resumeLC();
}
} else if (state == null
&& (SVManager.getCurrentViewN() / 2) < getReplies()) {
System.out.println("---- DIDNT RECEIVE STATE ----");
Logger.println("(TOMLayer.SMReplyDeliver) I have more than "
+ (SVManager.getCurrentViewN() / 2)
+ " messages that are no good!");
waitingEid = -1;
reset();
if (stateTimer != null)
stateTimer.cancel();
if (appStateOnly) {
requestState();
}
} else if (!haveState) {
System.out.println("---- RECEIVED INVALID STATE ----");
Logger.println("(TOMLayer.SMReplyDeliver) The replica from which I expected the state, sent one which doesn't match the hash of the others, or it never sent it at all");
reset();
requestState();
if (stateTimer != null)
stateTimer.cancel();
}
}
}
}
lockTimer.unlock();
}
}
package bftsmart.statemanagement.strategy.durability;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import bftsmart.statemanagement.ApplicationState;
public class StateSender implements Runnable {
private final Socket socket;
private ApplicationState state;
public StateSender(Socket socket) {
this.socket = socket;
}
public void setState(ApplicationState state) {
this.state = state;
}
@Override
public void run() {
try {
OutputStream os = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
System.out.print("--- Sending state in different socket");
oos.writeObject(state);
System.out.print("--- Sent state in different socket");
oos.close();
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
package bftsmart.statemanagement.strategy.durability;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.tom.server.Recoverable;
import bftsmart.tom.server.defaultservices.durability.DurabilityCoordinator;
public class StateSenderServer implements Runnable {
private ServerSocket server;
private ApplicationState state;
private Recoverable recoverable;
private DurabilityCoordinator coordinator;
private CSTRequest request;
public void setState(ApplicationState state) {
this.state = state;
}
public void setRecoverable(Recoverable recoverable) {
this.recoverable = recoverable;
coordinator = (DurabilityCoordinator)(recoverable);
}
public void setRequest(CSTRequest request) {
this.request = request;
}
public StateSenderServer(int port) {
try {
server = new ServerSocket(port);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
try {
Socket socket = server.accept();
StateSender sender = new StateSender(socket);
state = coordinator.getState(request);
sender.setState(state);
new Thread(sender).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
......@@ -47,6 +47,7 @@ public class ServiceProxy extends TOMSender {
private ReentrantLock canSendLock = new ReentrantLock();
private Semaphore sm = new Semaphore(0);
private int reqId = -1; // request id
private int operationId = -1; // request id
private TOMMessageType requestType;
private int replyQuorum = 0; // size of the reply quorum
private TOMMessage replies[] = null; // Replies from replicas are stored here
......@@ -140,24 +141,27 @@ public class ServiceProxy extends TOMSender {
return invoke(request, TOMMessageType.UNORDERED_REQUEST);
}
public void invokeAsynchronous(byte[] request, ReplyListener listener, int[] targets) {
reqId = generateRequestId(TOMMessageType.UNORDERED_REQUEST);
requestType = TOMMessageType.UNORDERED_REQUEST;
public void invokeAsynchronous(byte[] request, ReplyListener listener, int[] targets, TOMMessageType type) {
canSendLock.lock();
reqId = generateRequestId(type);
operationId = generateOperationId();
requestType = type;
replyQuorum = (int) Math.ceil((getViewManager().getCurrentViewN()
+ getViewManager().getCurrentViewF()) / 2) + 1;
this.replyListener = listener;
if(this.getViewManager().getStaticConf().isTheTTP()) {
requestType = TOMMessageType.STATUS_REPLY;
type = TOMMessageType.STATUS_REPLY;
try {
sendMessageToTargets(request, reqId, targets);
sendMessageToTargets(request, reqId, operationId, targets, type);
} catch(RuntimeException re) {
if(re.getMessage().equals("Server not connected")) {
TOMMessage tm = new TOMMessage(targets[0], 0, reqId, TOMUtil.getBytes(StatusReply.OFFLINE.toString()), 0, requestType);
TOMMessage tm = new TOMMessage(targets[0], 0, reqId, TOMUtil.getBytes(StatusReply.OFFLINE.toString()), 0, type);
listener.replyReceived(tm);
}
}
} else
sendMessageToTargets(request, reqId, targets);
sendMessageToTargets(request, reqId, operationId, targets, type);
canSendLock.unlock();
}
/**
......@@ -183,8 +187,9 @@ public class ServiceProxy extends TOMSender {
// Send the request to the replicas, and get its ID
reqId = generateRequestId(reqType);
requestType = reqType;
TOMulticast(request, reqId, reqType);
operationId = generateOperationId();
requestType = reqType;
TOMulticast(request, reqId, operationId, reqType);
Logger.println("Sending request (" + reqType + ") with reqId=" + reqId);
Logger.println("Expected number of matching replies: " + replyQuorum);
......
......@@ -39,6 +39,7 @@ import bftsmart.tom.core.messages.TOMMessage;
import bftsmart.tom.core.messages.TOMMessageType;
import bftsmart.tom.server.BatchExecutable;
import bftsmart.tom.server.Executable;
import bftsmart.tom.server.FIFOExecutable;
import bftsmart.tom.server.Recoverable;
import bftsmart.tom.server.Replier;
import bftsmart.tom.server.SingleExecutable;
......@@ -48,12 +49,15 @@ import bftsmart.tom.util.TOMUtil;
/**
* This class implements a TOMReceiver, and also a replica for the server side of the application.
* It receives requests from the clients, runs a TOM layer, and sends a reply back to the client
* Applications must create a class that extends this one, and implement the executeOrdered method
*
* This class receives messages from DeliveryThread and manages the execution
* from the application and reply to the clients. For applications where the
* ordered messages are executed one by one, ServiceReplica receives the batch
* decided in a consensus, deliver one by one and reply with the batch of replies.
* In cases where the application executes the messages in batches, the batch of
* messages is delivered to the application and ServiceReplica doesn't need to
* organize the replies in batches.
*/
public class ServiceReplica implements TOMReceiver {
public class ServiceReplica {
class MessageContextPair {
......@@ -135,7 +139,7 @@ public class ServiceReplica implements TOMReceiver {
try {
cs = new ServerCommunicationSystem(this.SVManager, this);
} catch (Exception ex) {
Logger.getLogger(TOMReceiver.class.getName()).log(Level.SEVERE, null, ex);
Logger.getLogger(ServiceReplica.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException("Unable to build a communication system.");
}
......@@ -205,164 +209,100 @@ public class ServiceReplica implements TOMReceiver {
//******* EDUARDO END **************//
/**
* This is the method invoked to deliver a totally ordered request.
* This message delivers a readonly message, i.e., a message that was not
* ordered to the replica and gather the reply to forward to the client
*
* @param msg The request delivered by the delivery thread
* @param message the request received from the delivery thread
*/
@Override
public final void receiveReadonlyMessage(TOMMessage tomMsg, MessageContext msgCtx) {
public final void receiveReadonlyMessage(TOMMessage message, MessageContext msgCtx) {
byte[] response = null;
response = executor.executeUnordered(tomMsg.getContent(), msgCtx);
if(executor instanceof FIFOExecutable) {
response = ((FIFOExecutable)executor).executeUnorderedFIFO(message.getContent(), msgCtx, message.getSender(), message.getOperationId());
} else
response = executor.executeUnordered(message.getContent(), msgCtx);
// build the reply and send it to the client
tomMsg.reply = new TOMMessage(id, tomMsg.getSession(), tomMsg.getSequence(),
response, SVManager.getCurrentViewId(), TOMMessageType.UNORDERED_REQUEST);
cs.send(new int[]{tomMsg.getSender()}, tomMsg.reply);
message.reply = new TOMMessage(id, message.getSession(), message.getSequence(),
response, SVManager.getCurrentViewId(), TOMMessageType.UNORDERED_REQUEST);
cs.send(new int[]{message.getSender()}, message.reply);
}
public void receiveMessages(int consId, int regency, boolean fromConsensus, TOMMessage[] requests, byte[] decision) {
TOMMessage firstRequest = requests[0];
public void receiveMessages(int consId[], int regency, TOMMessage[][] requests) {
int numRequests = 0;
int consensusCount = 0;
List<TOMMessage> toBatch = new ArrayList<TOMMessage>();
List<MessageContext> msgCtxts = new ArrayList<MessageContext>();
if(executor instanceof BatchExecutable) {
//DEBUG
bftsmart.tom.util.Logger.println("BATCHEXECUTOR");
int numRequests = 0;
//Messages to put in the batch
List<TOMMessage> toBatch = new ArrayList<TOMMessage>();
//Message Contexts (one Context per message in the batch)
List<MessageContext> msgCtxts = new ArrayList<MessageContext>();
for (TOMMessage request : requests) {
if (!fromConsensus || request.getViewID() == SVManager.getCurrentViewId()) {
//If message is a request, put message in the toBatch list
for(TOMMessage[] requestsFromConsensus : requests) {
TOMMessage firstRequest = requestsFromConsensus[0];
for(TOMMessage request : requestsFromConsensus) {
if (request.getViewID() == SVManager.getCurrentViewId()) {
if (request.getReqType() == TOMMessageType.ORDERED_REQUEST) {
numRequests++;
//Make new message context
MessageContext msgCtx = new MessageContext(
firstRequest.timestamp, firstRequest.nonces,
regency, consId, request.getSender(),
firstRequest);
//Put context in the message context list
msgCtxts.add(msgCtx);
MessageContext msgCtx = new MessageContext(firstRequest.timestamp, firstRequest.nonces, regency, consId[consensusCount], request.getSender(), firstRequest);
msgCtx.setBatchSize(requestsFromConsensus.length);
request.deliveryTime = System.nanoTime();
//Add message to the ToBatch list
toBatch.add(request);
if(executor instanceof BatchExecutable) {
msgCtxts.add(msgCtx);
toBatch.add(request);
} else if(executor instanceof FIFOExecutable) {
byte[]response = ((FIFOExecutable)executor).executeOrderedFIFO(request.getContent(), msgCtx, request.getSender(), request.getOperationId());
request.reply = new TOMMessage(id, request.getSession(),
request.getSequence(), response, SVManager.getCurrentViewId());
bftsmart.tom.util.Logger.println("(ServiceReplica.receiveMessages) sending reply to " + request.getSender());
replier.manageReply(request, msgCtx);
} else if(executor instanceof SingleExecutable) {
byte[]response = ((SingleExecutable)executor).executeOrdered(request.getContent(), msgCtx);
request.reply = new TOMMessage(id, request.getSession(),
request.getSequence(), response, SVManager.getCurrentViewId());
bftsmart.tom.util.Logger.println("(ServiceReplica.receiveMessages) sending reply to " + request.getSender());
replier.manageReply(request, msgCtx);
} else {
throw new UnsupportedOperationException("Interface not existent");
}
} else if (request.getReqType() == TOMMessageType.RECONFIG) {
// Reconfiguration request to be processed after the
// batch
SVManager.enqueueUpdate(request);
} else {
throw new RuntimeException("Should never reach here!");
}
} else if (fromConsensus && request.getViewID() < SVManager.getCurrentViewId()) {
} else if (request.getViewID() < SVManager.getCurrentViewId()) {
// message sender had an old view, resend the message to
// him (but only if it came from consensus an not state transfer)
tomLayer.getCommunication().send(
new int[] { request.getSender() },
new TOMMessage(SVManager.getStaticConf()
.getProcessId(), request.getSession(),
request.getSequence(), TOMUtil
.getBytes(SVManager
.getCurrentView()),
SVManager.getCurrentViewId()));
tomLayer.getCommunication().send(new int[] { request.getSender() }, new TOMMessage(SVManager.getStaticConf().getProcessId(), request.getSession(), request.getSequence(), TOMUtil.getBytes(SVManager.getCurrentView()), SVManager.getCurrentViewId()));
}
}
//In the end, if there are messages in the Batch
if(numRequests > 0){
//Make new batch to deliver
byte[][] batch = new byte[numRequests][];
//Put messages in the batch
int line = 0;
for(TOMMessage m : toBatch){
batch[line] = m.getContent();
line++;
}
MessageContext[] msgContexts = new MessageContext[msgCtxts.size()];
msgContexts = msgCtxts.toArray(msgContexts);
//Deliver the batch and wait for replies
byte[][] replies = ((BatchExecutable) executor).executeBatch(batch, msgContexts);
//Send the replies back to the client
if (fromConsensus) {
for(int index = 0; index < toBatch.size(); index++){
TOMMessage request = toBatch.get(index);
request.reply = new TOMMessage(id,
request.getSession(), request.getSequence(),
replies[index], SVManager.getCurrentViewId());
cs.send(new int[] { request.getSender() }, request.reply);
}
}
//DEBUG
bftsmart.tom.util.Logger.println("BATCHEXECUTOR END");
consensusCount++;
}
if(executor instanceof BatchExecutable && numRequests > 0){
//Make new batch to deliver
byte[][] batch = new byte[numRequests][];
//Put messages in the batch
int line = 0;
for(TOMMessage m : toBatch){
batch[line] = m.getContent();
line++;
}
} else {
bftsmart.tom.util.Logger.println("(ServiceReplica.receiveMessages) singe executor for consensus " + consId);
for (TOMMessage request: requests) {
if (!fromConsensus || request.getViewID() == SVManager.getCurrentViewId()) {
bftsmart.tom.util.Logger.println("(ServiceReplica.receiveMessages) same view");
if (request.getReqType() == TOMMessageType.ORDERED_REQUEST) {
bftsmart.tom.util.Logger.println("(ServiceReplica.receiveMessages) this is a REQUEST type message");
byte[] response = null;
//normal request execution
//create a context for the batch of messages to be delivered
MessageContext msgCtx = new MessageContext(firstRequest.timestamp,
firstRequest.nonces, regency, consId, request.getSender(), firstRequest);
msgCtx.setBatchSize(requests.length);
request.deliveryTime = System.nanoTime();
bftsmart.tom.util.Logger.println("(ServiceReplica.receiveMessages) executing message " + request.getSequence() + " from " + request.getSender() + " decided in consensus " + consId);
response = ((SingleExecutable)executor).executeOrdered(request.getContent(), msgCtx);
// build the reply and send it to the client
if (fromConsensus) {
request.reply = new TOMMessage(id, request.getSession(),
request.getSequence(), response, SVManager.getCurrentViewId());
bftsmart.tom.util.Logger.println("(ServiceReplica.receiveMessages) sending reply to " + request.getSender());
replier.manageReply(request, msgCtx);
}
} else if (request.getReqType() == TOMMessageType.RECONFIG) {
//Reconfiguration request to be processed after the batch
bftsmart.tom.util.Logger.println("(ServiceReplica.receiveMessages) Enqueing an update");
SVManager.enqueueUpdate(request);
} else {
throw new RuntimeException("Should never reach here!");
}
} else if (fromConsensus && request.getViewID() < SVManager.getCurrentViewId()) {
MessageContext[] msgContexts = new MessageContext[msgCtxts.size()];
msgContexts = msgCtxts.toArray(msgContexts);
bftsmart.tom.util.Logger.println("(ServiceReplica.receiveMessages) sending current view to " + request.getSender());
//message sender had an old view, resend the message to him
tomLayer.getCommunication().send(new int[]{request.getSender()},
new TOMMessage(SVManager.getStaticConf().getProcessId(),
request.getSession(), request.getSequence(),
TOMUtil.getBytes(SVManager.getCurrentView()), SVManager.getCurrentViewId()));
} else {
//Deliver the batch and wait for replies
byte[][] replies = ((BatchExecutable) executor).executeBatch(batch, msgContexts);
System.out.println("WTF no consenso numero " + consId);
}
//Send the replies back to the client
for(int index = 0; index < toBatch.size(); index++){
TOMMessage request = toBatch.get(index);
request.reply = new TOMMessage(id, request.getSession(), request.getSequence(),
replies[index], SVManager.getCurrentViewId());
cs.send(new int[] { request.getSender() }, request.reply);
}
//DEBUG
bftsmart.tom.util.Logger.println("BATCHEXECUTOR END");
}
}
/**
* This method makes the replica leave the group
*/
......
......@@ -19,6 +19,7 @@
package bftsmart.tom;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
......@@ -37,139 +38,157 @@ import bftsmart.tom.core.messages.TOMMessageType;
*/
public abstract class TOMSender implements ReplyReceiver {
private int me; // process id
//******* EDUARDO BEGIN **************//
//private int[] group; // group of replicas
private ClientViewManager viewManager;
//******* EDUARDO END **************//
private int session = 0; // session id
private int sequence = 0; // sequence number
private int unorderedMessageSequence = 0; // sequence number for readonly messages
private CommunicationSystemClientSide cs; // Client side comunication system
private Lock lock = new ReentrantLock(); // lock to manage concurrent access to this object by other threads
private boolean useSignatures = false;
/**
* Creates a new instance of TOMulticastSender
*
* TODO: This may really be empty?
*/
public TOMSender() {
}
public void close(){
cs.close();
}
public CommunicationSystemClientSide getCommunicationSystem() {
return this.cs;
}
//******* EDUARDO BEGIN **************//
public ClientViewManager getViewManager(){
return this.viewManager;
}
/**
* This method initializes the object
* TODO: Ask if this method cannot be protected (compiles, but....)
*
* @param processId ID of the process
*/
public void init(int processId) {
this.viewManager = new ClientViewManager(processId);
startsCS();
}
public void init(int processId, String configHome) {
this.viewManager = new ClientViewManager(processId,configHome);
startsCS();
}
private void startsCS() {
this.cs = CommunicationSystemClientSideFactory.getCommunicationSystemClientSide(this.viewManager);
this.cs.setReplyReceiver(this); // This object itself shall be a reply receiver
this.me = this.viewManager.getStaticConf().getProcessId();
this.useSignatures = this.viewManager.getStaticConf().getUseSignatures()==1?true:false;
this.session = new Random().nextInt();
}
//******* EDUARDO END **************//
public int getProcessId() {
return me;
}
public int generateRequestId(TOMMessageType type) {
lock.lock();
int id;
if(type == TOMMessageType.ORDERED_REQUEST)
id = sequence++;
else
id = unorderedMessageSequence++;
lock.unlock();
return id;
}
//******* EDUARDO BEGIN **************//
/**
* Multicast data to the group of replicas
*
* @param m Data to be multicast
*/
//public void TOMulticast(byte[] m) {
// TOMulticast(new TOMMessage(me, session, generateRequestId(), m,
// this.viewManager.getCurrentViewId()));
//}
/**
* Multicast a TOMMessage to the group of replicas
*
* @param sm Message to be multicast
*/
public void TOMulticast(TOMMessage sm) {
cs.send(useSignatures, this.viewManager.getCurrentViewProcesses(), sm);
}
/**
* Multicast data to the group of replicas
*
* @param m Data to be multicast
* @param reqId unique integer that identifies this request
* @param reqType TOM_NORMAL, TOM_READONLY or TOM_RECONFIGURATION
*/
public void TOMulticast(byte[] m, int reqId, TOMMessageType reqType) {
cs.send(useSignatures, viewManager.getCurrentViewProcesses(),
new TOMMessage(me, session, reqId, m, viewManager.getCurrentViewId(),
reqType));
}
public void sendMessageToTargets(byte[] m, int reqId, int[] targets) {
TOMMessageType type = TOMMessageType.UNORDERED_REQUEST;
if(this.getViewManager().getStaticConf().isTheTTP()) {
type = TOMMessageType.ASK_STATUS;
}
cs.send(useSignatures, targets,
new TOMMessage(me, session, reqId, m, viewManager.getCurrentViewId(), type));
}
/**
* Create TOMMessage and sign it
*
* @param m Data to be included in TOMMessage
*
* @return TOMMessage with serializedMsg and serializedMsgSignature fields filled
*/
//public TOMMessage sign(byte[] m) {
// TOMMessage tm = new TOMMessage(me, session, generateRequestId(), m,
// this.viewManager.getCurrentViewId());
// cs.sign(tm);
// return tm;
//}
//******* EDUARDO END **************//
private int me; // process id
//******* EDUARDO BEGIN **************//
//private int[] group; // group of replicas
private ClientViewManager viewManager;
//******* EDUARDO END **************//
private int session = 0; // session id
private int sequence = 0; // sequence number
private int unorderedMessageSequence = 0; // sequence number for readonly messages
private CommunicationSystemClientSide cs; // Client side comunication system
private Lock lock = new ReentrantLock(); // lock to manage concurrent access to this object by other threads
private boolean useSignatures = false;
private AtomicInteger opCounter = new AtomicInteger(0);
/**
* Creates a new instance of TOMulticastSender
*
* TODO: This may really be empty?
*/
public TOMSender() {
}
public void close(){
cs.close();
}
public CommunicationSystemClientSide getCommunicationSystem() {
return this.cs;
}
//******* EDUARDO BEGIN **************//
public ClientViewManager getViewManager(){
return this.viewManager;
}
/**
* This method initializes the object
* TODO: Ask if this method cannot be protected (compiles, but....)
*
* @param processId ID of the process
*/
public void init(int processId) {
this.viewManager = new ClientViewManager(processId);
startsCS();
}
public void init(int processId, String configHome) {
this.viewManager = new ClientViewManager(processId,configHome);
startsCS();
}
private void startsCS() {
this.cs = CommunicationSystemClientSideFactory.getCommunicationSystemClientSide(this.viewManager);
this.cs.setReplyReceiver(this); // This object itself shall be a reply receiver
this.me = this.viewManager.getStaticConf().getProcessId();
this.useSignatures = this.viewManager.getStaticConf().getUseSignatures()==1?true:false;
this.session = new Random().nextInt();
}
//******* EDUARDO END **************//
public int getProcessId() {
return me;
}
public int generateRequestId(TOMMessageType type) {
lock.lock();
int id;
if(type == TOMMessageType.ORDERED_REQUEST)
id = sequence++;
else
id = unorderedMessageSequence++;
lock.unlock();
return id;
}
public int generateOperationId() {
return opCounter.getAndIncrement();
}
//******* EDUARDO BEGIN **************//
/**
* Multicast data to the group of replicas
*
* @param m Data to be multicast
*/
//public void TOMulticast(byte[] m) {
// TOMulticast(new TOMMessage(me, session, generateRequestId(), m,
// this.viewManager.getCurrentViewId()));
//}
/**
* Multicast a TOMMessage to the group of replicas
*
* @param sm Message to be multicast
*/
public void TOMulticast(TOMMessage sm) {
cs.send(useSignatures, this.viewManager.getCurrentViewProcesses(), sm);
}
/**
* Multicast data to the group of replicas
*
* @param m Data to be multicast
* @param reqId unique integer that identifies this request
* @param reqType TOM_NORMAL, TOM_READONLY or TOM_RECONFIGURATION
*/
public void TOMulticast(byte[] m, int reqId, TOMMessageType reqType) {
cs.send(useSignatures, viewManager.getCurrentViewProcesses(),
new TOMMessage(me, session, reqId, m, viewManager.getCurrentViewId(),
reqType));
}
public void TOMulticast(byte[] m, int reqId, int operationId, TOMMessageType reqType) {
cs.send(useSignatures, viewManager.getCurrentViewProcesses(),
new TOMMessage(me, session, reqId, operationId, m, viewManager.getCurrentViewId(),
reqType));
}
public void sendMessageToTargets(byte[] m, int reqId, int[] targets, TOMMessageType type) {
if(this.getViewManager().getStaticConf().isTheTTP()) {
type = TOMMessageType.ASK_STATUS;
}
cs.send(useSignatures, targets,
new TOMMessage(me, session, reqId, m, viewManager.getCurrentViewId(), type));
}
public void sendMessageToTargets(byte[] m, int reqId, int operationId, int[] targets, TOMMessageType type) {
if(this.getViewManager().getStaticConf().isTheTTP()) {
type = TOMMessageType.ASK_STATUS;
}
cs.send(useSignatures, targets,
new TOMMessage(me, session, reqId, operationId, m, viewManager.getCurrentViewId(), type));
}
/**
* Create TOMMessage and sign it
*
* @param m Data to be included in TOMMessage
*
* @return TOMMessage with serializedMsg and serializedMsgSignature fields filled
*/
//public TOMMessage sign(byte[] m) {
// TOMMessage tm = new TOMMessage(me, session, generateRequestId(), m,
// this.viewManager.getCurrentViewId());
// cs.sign(tm);
// return tm;
//}
//******* EDUARDO END **************//
}
......@@ -17,17 +17,18 @@
*/
package bftsmart.tom.core;
import java.util.ArrayList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import bftsmart.paxosatwar.Consensus;
import bftsmart.reconfiguration.ServerViewManager;
import bftsmart.statemanagment.ApplicationState;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.tom.MessageContext;
import bftsmart.tom.TOMReceiver;
import bftsmart.tom.ServiceReplica;
import bftsmart.tom.core.messages.TOMMessage;
import bftsmart.tom.core.messages.TOMMessageType;
import bftsmart.tom.server.Recoverable;
......@@ -42,9 +43,11 @@ public final class DeliveryThread extends Thread {
private LinkedBlockingQueue<Consensus> decided = new LinkedBlockingQueue<Consensus>(); // decided consensus
private TOMLayer tomLayer; // TOM layer
private TOMReceiver receiver; // Object that receives requests from clients
private ServiceReplica receiver; // Object that receives requests from clients
private Recoverable recoverer; // Object that uses state transfer
private ServerViewManager manager;
private Lock decidedLock = new ReentrantLock();
private Condition notEmptyQueue = decidedLock.newCondition();
/**
* Creates a new instance of DeliveryThread
......@@ -52,7 +55,7 @@ public final class DeliveryThread extends Thread {
* @param receiver Object that receives requests from clients
* @param conf TOM configuration
*/
public DeliveryThread(TOMLayer tomLayer, TOMReceiver receiver, Recoverable recoverer, ServerViewManager manager) {
public DeliveryThread(TOMLayer tomLayer, ServiceReplica receiver, Recoverable recoverer, ServerViewManager manager) {
super("Delivery Thread");
this.tomLayer = tomLayer;
......@@ -64,10 +67,6 @@ public final class DeliveryThread extends Thread {
}
public TOMReceiver getReceiver() {
return receiver;
}
public Recoverable getRecoverer() {
return recoverer;
}
......@@ -86,7 +85,10 @@ public final class DeliveryThread extends Thread {
tomLayer.setInExec(-1);
}
try {
decidedLock.lock();
decided.put(cons);
notEmptyQueue.signalAll();
decidedLock.unlock();
Logger.println("(DeliveryThread.delivery) Consensus " + cons.getId() + " finished. Decided size=" + decided.size());
} catch (Exception e) {
e.printStackTrace(System.out);
......@@ -102,7 +104,6 @@ public final class DeliveryThread extends Thread {
return true;
}
}
return false;
}
......@@ -111,13 +112,16 @@ public final class DeliveryThread extends Thread {
private Condition canDeliver = deliverLock.newCondition();
public void deliverLock() {
// release the delivery lock to avoid blocking on state transfer
decidedLock.lock();
notEmptyQueue.signalAll();
decidedLock.unlock();
deliverLock.lock();
//Logger.println("(DeliveryThread.deliverLock) Deliver lock obtained");
}
public void deliverUnlock() {
deliverLock.unlock();
//Logger.println("(DeliveryThread.deliverUnlock) Deliver Released");
}
public void canDeliver() {
......@@ -145,9 +149,10 @@ public final class DeliveryThread extends Thread {
//stateManager.setWaiting(-1);
tomLayer.setNoExec();
System.out.print("Current decided size: " + decided.size());
decided.clear();
Logger.println("(DeliveryThread.update) All finished from up to " + lastEid);
System.out.println("(DeliveryThread.update) All finished up to " + lastEid);
}
/**
......@@ -157,100 +162,112 @@ public final class DeliveryThread extends Thread {
@Override
public void run() {
while (true) {
/** THIS IS JOAO'S CODE, TO HANDLE STATE TRANSFER */
deliverLock();
while (tomLayer.isRetrievingState()) {
Logger.println("(DeliveryThread.run) Retrieving State.");
canDeliver.awaitUninterruptibly();
}
/******************************************************************/
try { //no exception should stop the batch delivery thread
// take a decided consensus
Consensus cons = decided.poll(1500, TimeUnit.MILLISECONDS);
if (cons == null) {
deliverUnlock();
continue; //go back to the start of the loop
}
Logger.println("(DeliveryThread.run) Consensus " + cons.getId() + " was delivered.");
TOMMessage[] requests = extractMessagesFromDecision(cons);
if (requests != null && requests.length > 0) {
//cons.firstMessageProposed contains the performance counters
if (requests[0].equals(cons.firstMessageProposed)) {
long time = requests[0].timestamp;
requests[0] = cons.firstMessageProposed;
requests[0].timestamp = time;
}
//clean the ordered messages from the pending buffer
tomLayer.clientsManager.requestsOrdered(requests);
deliverMessages(cons.getId(), tomLayer.getLCManager().getLastReg(), true, requests, cons.getDecision());
//******* EDUARDO BEGIN **************//
if (manager.hasUpdates()) {
processReconfigMessages(cons.getId(), cons.getDecisionRound().getNumber());
//set this consensus as the last executed
tomLayer.setLastExec(cons.getId());
//define that end of this execution
tomLayer.setInExec(-1);
}
//******* EDUARDO END **************//
}
/** THIS IS JOAO'S CODE, TO HANDLE CHECKPOINTS */
//logDecision(cons);
/********************************************************/
//define the last stable consensus... the stable consensus can
//be removed from the leaderManager and the executionManager
//TODO: Is this part necessary? If it is, can we put it inside setLastExec
if (cons.getId() > 2) {
int stableConsensus = cons.getId() - 3;
tomLayer.lm.removeStableConsenusInfos(stableConsensus);
tomLayer.execManager.removeExecution(stableConsensus);
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
/** THIS IS JOAO'S CODE, TO HANDLE STATE TRANSFER */
deliverUnlock();
/******************************************************************/
}
/** THIS IS JOAO'S CODE, TO HANDLE STATE TRANSFER */
deliverLock();
while (tomLayer.isRetrievingState()) {
System.out.println("(DeliveryThread.run) Retrieving State.");
canDeliver.awaitUninterruptibly();
System.out.println("(DeliveryThread.run) canDeliver unleashed.");
}
try {
ArrayList<Consensus> consensuses = new ArrayList<Consensus>();
decidedLock.lock();
if(decided.isEmpty()) {
notEmptyQueue.await();
}
decided.drainTo(consensuses);
decidedLock.unlock();
if (consensuses.size() > 0) {
TOMMessage[][] requests = new TOMMessage[consensuses.size()][];
int[] consensusIds = new int[requests.length];
int count = 0;
for (Consensus c : consensuses) {
requests[count] = extractMessagesFromDecision(c);
consensusIds[count] = c.getId();
// cons.firstMessageProposed contains the performance counters
if (requests[count][0].equals(c.firstMessageProposed)) {
long time = requests[count][0].timestamp;
requests[count][0] = c.firstMessageProposed;
requests[count][0].timestamp = time;
}
count++;
}
Consensus lastConsensus = consensuses.get(consensuses.size() - 1);
if (requests != null && requests.length > 0) {
// clean the ordered messages from the pending buffer
for(int i = 0; i < requests.length; i++) {
tomLayer.clientsManager.requestsOrdered(requests[i]);
}
deliverMessages(consensusIds, tomLayer.getLCManager().getLastReg(), requests);
// ******* EDUARDO BEGIN ***********//
if (manager.hasUpdates()) {
processReconfigMessages(lastConsensus.getId(),
lastConsensus.getDecisionRound()
.getNumber());
// set this consensus as the last executed
tomLayer.setLastExec(lastConsensus.getId());
// define that end of this execution
tomLayer.setInExec(-1);
// ******* EDUARDO END **************//
}
}
// define the last stable consensus... the stable consensus can
// be removed from the leaderManager and the executionManager
// TODO: Is this part necessary? If it is, can we put it
// inside setLastExec
int eid = lastConsensus.getId();
if (eid > 2) {
int stableConsensus = eid - 3;
tomLayer.lm.removeStableConsenusInfos(stableConsensus);
tomLayer.execManager.removeExecution(stableConsensus);
}
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
/** THIS IS JOAO'S CODE, TO HANDLE STATE TRANSFER */
deliverUnlock();
/******************************************************************/
}
}
private TOMMessage[] extractMessagesFromDecision(Consensus cons) {
TOMMessage[] requests = (TOMMessage[]) cons.getDeserializedDecision();
if (requests == null) {
//there are no cached deserialized requests
//this may happen if this batch proposal was not verified
//TODO: this condition is possible?
Logger.println("(DeliveryThread.run) interpreting and verifying batched requests.");
// obtain an array of requests from the taken consensus
BatchReader batchReader = new BatchReader(cons.getDecision(),
manager.getStaticConf().getUseSignatures() == 1);
requests = batchReader.deserialiseRequests(manager);
} else {
Logger.println("(DeliveryThread.run) using cached requests from the propose.");
}
return requests;
TOMMessage[] requests = (TOMMessage[]) cons.getDeserializedDecision();
if (requests == null) {
// there are no cached deserialized requests
// this may happen if this batch proposal was not verified
// TODO: this condition is possible?
Logger.println("(DeliveryThread.run) interpreting and verifying batched requests.");
// obtain an array of requests from the taken consensus
BatchReader batchReader = new BatchReader(cons.getDecision(),
manager.getStaticConf().getUseSignatures() == 1);
requests = batchReader.deserialiseRequests(manager);
} else {
Logger.println("(DeliveryThread.run) using cached requests from the propose.");
}
return requests;
}
public void deliverUnordered(TOMMessage request, int regency) {
MessageContext msgCtx = new MessageContext(System.currentTimeMillis(),
new byte[0], regency, -1, request.getSender(), null);
receiver.receiveReadonlyMessage(request, msgCtx);
}
private void deliverMessages(int consId, int regency, boolean fromConsensus, TOMMessage[] requests, byte[] decision) {
receiver.receiveMessages(consId, regency, fromConsensus, requests, decision);
private void deliverMessages(int consId[], int regency, TOMMessage[][] requests) {
receiver.receiveMessages(consId, regency, requests);
}
private void processReconfigMessages(int consId, int decisionRoundNumber) {
......
......@@ -50,8 +50,8 @@ import bftsmart.paxosatwar.messages.PaxosMessage;
import bftsmart.paxosatwar.roles.Acceptor;
import bftsmart.reconfiguration.ServerViewManager;
import bftsmart.reconfiguration.StatusReply;
import bftsmart.statemanagment.StateManager;
import bftsmart.tom.TOMReceiver;
import bftsmart.statemanagement.StateManager;
import bftsmart.tom.ServiceReplica;
import bftsmart.tom.core.messages.TOMMessage;
import bftsmart.tom.core.messages.TOMMessageType;
import bftsmart.tom.core.timer.ForwardedMessage;
......@@ -110,7 +110,6 @@ public final class TOMLayer extends Thread implements RequestReceiver {
/*************************************************************/
private PrivateKey prk;
public ServerViewManager reconfManager;
/**
......@@ -123,7 +122,7 @@ public final class TOMLayer extends Thread implements RequestReceiver {
* @param recManager Reconfiguration Manager
*/
public TOMLayer(ExecutionManager manager,
TOMReceiver receiver,
ServiceReplica receiver,
Recoverable recoverer,
LeaderModule lm,
Acceptor a,
......@@ -137,7 +136,7 @@ public final class TOMLayer extends Thread implements RequestReceiver {
this.acceptor = a;
this.communication = cs;
this.reconfManager = recManager;
//do not create a timer manager if the timeout is 0
if (reconfManager.getStaticConf().getRequestTimeout() == 0){
this.requestsTimer = null;
......@@ -159,17 +158,11 @@ public final class TOMLayer extends Thread implements RequestReceiver {
}
this.prk = reconfManager.getStaticConf().getRSAPrivateKey();
/** THIS IS JOAO'S CODE, RELATED TO LEADER CHANGE */
this.lcManager = new LCManager(this,recManager, md);
/*************************************************************/
this.dt = new DeliveryThread(this, receiver, recoverer, this.reconfManager); // Create delivery thread
this.dt.start();
/** THIS IS JOAO'S CODE, TO HANDLE CHECKPOINTS AND STATE TRANSFER */
this.stateManager = new StateManager(this.reconfManager, this, dt, lcManager, execManager);
/*******************************************************/
this.stateManager = recoverer.getStateManager();
stateManager.init(this, dt);
}
ReentrantLock hashLock = new ReentrantLock();
......@@ -200,12 +193,12 @@ public final class TOMLayer extends Thread implements RequestReceiver {
/**
* Verifies the signature of a signed object
* @param so Signed object to be verified
* @param sender Replica id that supposably signed this object
* @param sender Replica id that supposedly signed this object
* @return True if the signature is valid, false otherwise
*/
public boolean verifySignature(SignedObject so, int sender) {
try {
return so.verify(reconfManager.getStaticConf().getRSAPublicKey(sender), engine);
return so.verify(reconfManager.getStaticConf().getRSAPublicKey(), engine);
} catch (Exception e) {
e.printStackTrace();
}
......@@ -449,6 +442,7 @@ public final class TOMLayer extends Thread implements RequestReceiver {
return requests;
}
public void forwardRequestToLeader(TOMMessage request) {
int leaderId = lm.getCurrentLeader();
//******* EDUARDO BEGIN **************//
......@@ -462,7 +456,7 @@ public final class TOMLayer extends Thread implements RequestReceiver {
public boolean isRetrievingState() {
//lockTimer.lock();
boolean result = stateManager != null && stateManager.getWaiting() != -1;
boolean result = stateManager != null && stateManager.isRetrievingState();
//lockTimer.unlock();
return result;
......@@ -482,7 +476,6 @@ public final class TOMLayer extends Thread implements RequestReceiver {
for (int nextExecution = getLastExec() + 1;
execManager.receivedOutOfContextPropose(nextExecution);
nextExecution = getLastExec() + 1) {
execManager.processOutOfContextPropose(execManager.getExecution(nextExecution));
}
}
......@@ -823,7 +816,6 @@ public final class TOMLayer extends Thread implements RequestReceiver {
* @param msg Message received from the other replica
*/
public void deliverTimeoutRequest(LCMessage msg) {
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
......@@ -845,7 +837,6 @@ public final class TOMLayer extends Thread implements RequestReceiver {
clientsManager.getClientsLock().lock();
if (hasReqs) {
// Store requests that the other replica did not manage to order
//TODO: The requests have to be verified!
byte[] temp = (byte[]) ois.readObject();
......@@ -874,9 +865,8 @@ public final class TOMLayer extends Thread implements RequestReceiver {
}
}
break;
case TOMUtil.STOPDATA: // STOPDATA messages
{
case TOMUtil.STOPDATA: {
// STOPDATA messages
int regency = msg.getReg();
// Am I the new leader, and am I expecting this messages?
......
......@@ -41,7 +41,10 @@ public class TOMMessage extends SystemMessage implements Externalizable, Compara
//******* EDUARDO END **************//
private int session; // Sequence number defined by the client
private int sequence; // Sequence number defined by the client
// Sequence number defined by the client.
// There is a sequence number for ordered and anothre for unordered messages
private int sequence;
private int operationId; // Sequence number defined by the client
private byte[] content = null; // Content of the message
......@@ -78,6 +81,7 @@ public class TOMMessage extends SystemMessage implements Externalizable, Compara
public TOMMessage() {
}
/**
* Creates a new instance of TOMMessage
*
......@@ -102,9 +106,25 @@ public class TOMMessage extends SystemMessage implements Externalizable, Compara
* @param type Type of the request
*/
public TOMMessage(int sender, int session, int sequence, byte[] content, int view, TOMMessageType type) {
this(sender, session, sequence, -1, content, view, type);
}
/**
* Creates a new instance of TOMMessage. This one has an operationId parameter
* used for FIFO executions
* @param sender The client id
* @param session The session id of the sender
* @param sequence The sequence number created based on the message type
* @param operationId The operation sequence number disregarding message type
* @param content The command to be executed
* @param view The view in which the message was sent
* @param type Ordered or Unordered request
*/
public TOMMessage(int sender, int session, int sequence, int operationId, byte[] content, int view, TOMMessageType type) {
super(sender);
this.session = session;
this.sequence = sequence;
this.operationId = operationId;
this.viewID = view;
buildId();
this.content = content;
......@@ -112,7 +132,6 @@ public class TOMMessage extends SystemMessage implements Externalizable, Compara
}
/** THIS IS JOAO'S CODE, FOR DEBUGGING */
private transient DebugInfo info = null; // Debug information
......@@ -148,6 +167,10 @@ public class TOMMessage extends SystemMessage implements Externalizable, Compara
public int getSequence() {
return sequence;
}
public int getOperationId() {
return operationId;
}
public int getViewID() {
return viewID;
......@@ -192,7 +215,7 @@ public class TOMMessage extends SystemMessage implements Externalizable, Compara
TOMMessage mc = (TOMMessage) o;
return (mc.getSender() == sender) && (mc.getSequence() == sequence);
return (mc.getSender() == sender) && (mc.getSequence() == sequence) && (mc.getOperationId() == operationId);
}
@Override
......@@ -200,6 +223,7 @@ public class TOMMessage extends SystemMessage implements Externalizable, Compara
int hash = 5;
hash = 59 * hash + this.sequence;
hash = 59 * hash + this.getSender();
hash = 59 * hash + this.getOperationId();
return hash;
}
......@@ -214,6 +238,7 @@ public class TOMMessage extends SystemMessage implements Externalizable, Compara
out.writeInt(type.toInt());
out.writeInt(session);
out.writeInt(sequence);
out.writeInt(operationId);
if (content == null) {
out.writeInt(-1);
......@@ -229,6 +254,7 @@ public class TOMMessage extends SystemMessage implements Externalizable, Compara
type = TOMMessageType.fromInt(in.readInt());
session = in.readInt();
sequence = in.readInt();
operationId = in.readInt();
int toRead = in.readInt();
if (toRead != -1) {
......@@ -274,7 +300,7 @@ public class TOMMessage extends SystemMessage implements Externalizable, Compara
try{
m.rExternal(dis);
}catch(Exception e) {
System.out.println("deu merda "+e);
System.out.println("error on bytesToMessage " + e);
return null;
}
......@@ -307,6 +333,11 @@ public class TOMMessage extends SystemMessage implements Externalizable, Compara
if (this.getSequence() > tm.getSequence())
return AFTER;
if(this.getOperationId() < tm.getOperationId())
return BEFORE;
if(this.getOperationId() > tm.getOperationId())
return AFTER;
return EQUAL;
}
}
......@@ -125,7 +125,6 @@ public class LCManager {
}
public void setNewLeader(int leader) {
currentLeader = leader;
}
......
package bftsmart.tom.server;
import bftsmart.tom.MessageContext;
/**
* @author mhsantos
* Deliver messages in FIFO order
*
*/
public interface FIFOExecutable extends SingleExecutable {
public byte[] executeOrderedFIFO(byte[] command, MessageContext msgCtx, int clientId, int operationId);
public byte[] executeUnorderedFIFO(byte[] command, MessageContext msgCtx, int clientId, int operationId);
}
package bftsmart.tom.server;
import bftsmart.statemanagment.ApplicationState;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.statemanagement.StateManager;
import bftsmart.tom.ReplicaContext;
/**
......@@ -29,5 +30,14 @@ public interface Recoverable {
* @return
*/
public int setState(ApplicationState state);
/**
* Recoverers implementing this interface will have to chose among
* different options of state managers like DurableStateManager or
* StandardStateManager. The recoverer class can also define a new
* strategy to manage the state and return it in this method.
* @return the implementation of state manager that suplies the strategy defined
*/
public StateManager getStateManager();
}
......@@ -20,7 +20,9 @@ package bftsmart.tom.server.defaultservices;
import java.util.Arrays;
import bftsmart.statemanagment.ApplicationState;
import bftsmart.tom.server.defaultservices.CommandsInfo;
import bftsmart.statemanagement.ApplicationState;
/**
* This classe represents a state tranfered from a replica to another. The state associated with the last
......@@ -42,6 +44,7 @@ public class DefaultApplicationState implements ApplicationState {
private int lastCheckpointEid; // Execution ID for the last checkpoint
private int lastCheckpointRound; // Round for the last checkpoint
private int lastCheckpointLeader; // Leader for the last checkpoint
private byte[] logHash;
/**
* Constructs a TansferableState
......@@ -62,6 +65,11 @@ public class DefaultApplicationState implements ApplicationState {
this.hasState = true;
}
public DefaultApplicationState(CommandsInfo[] messageBatches, byte[] logHash, int lastCheckpointEid, int lastCheckpointRound, int lastCheckpointLeader, int lastEid, byte[] state, byte[] stateHash) {
this(messageBatches, lastCheckpointEid, lastCheckpointRound, lastCheckpointLeader, lastEid, state, stateHash);
this.logHash = logHash;
}
/**
* Constructs a TansferableState
* This constructor should be used when there isn't a valid state to construct the object with
......@@ -136,6 +144,10 @@ public class DefaultApplicationState implements ApplicationState {
return messageBatches;
}
public void setMessageBatches(CommandsInfo[] messageBatches) {
this.messageBatches = messageBatches;
}
/**
* Retrieves the specified batch of messages
* @param eid Execution ID associated with the batch to be fetched
......
......@@ -10,7 +10,9 @@ import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import bftsmart.reconfiguration.util.TOMConfiguration;
import bftsmart.statemanagment.ApplicationState;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.statemanagement.StateManager;
import bftsmart.statemanagement.strategy.StandardStateManager;
import bftsmart.tom.MessageContext;
import bftsmart.tom.ReplicaContext;
import bftsmart.tom.server.BatchExecutable;
......@@ -35,6 +37,8 @@ public abstract class DefaultRecoverable implements Recoverable, BatchExecutable
private StateLog log;
private StateManager stateManager;
public DefaultRecoverable() {
try {
......@@ -49,17 +53,17 @@ public abstract class DefaultRecoverable implements Recoverable, BatchExecutable
int eid = msgCtxs[0].getConsensusId();
stateLock.lock();
byte[][] replies = executeBatch2(commands, msgCtxs);
byte[][] replies = appExecuteBatch(commands, msgCtxs);
stateLock.unlock();
if ((eid > 0) && ((eid % checkpointPeriod) == 0)) {
Logger.println("(DefaultRecoverable.executeBatch) Performing checkpoint for consensus " + eid);
Logger.println("(DurabilityCoordinator.executeBatch) Performing checkpoint for consensus " + eid);
stateLock.lock();
byte[] snapshot = getSnapshot();
stateLock.unlock();
saveState(snapshot, eid, 0, 0/*tomLayer.lm.getLeader(cons.getId(), cons.getDecisionRound().getNumber())*/);
} else {
Logger.println("(DefaultRecoverable.executeBatch) Storing message batch in the state log for consensus " + eid);
Logger.println("(DurabilityCoordinator.executeBatch) Storing message batch in the state log for consensus " + eid);
saveCommands(commands, eid, 0, 0/*tomLayer.lm.getLeader(cons.getId(), cons.getDecisionRound().getNumber())*/);
}
......@@ -136,7 +140,7 @@ public abstract class DefaultRecoverable implements Recoverable, BatchExecutable
lastEid = state.getLastEid();
//lastEid = lastCheckpointEid + (state.getMessageBatches() != null ? state.getMessageBatches().length : 0);
bftsmart.tom.util.Logger.println("(DefaultRecoverable.setState) I'm going to update myself from EID "
bftsmart.tom.util.Logger.println("(DurabilityCoordinator.setState) I'm going to update myself from EID "
+ lastCheckpointEid + " to EID " + lastEid);
stateLock.lock();
......@@ -149,33 +153,13 @@ public abstract class DefaultRecoverable implements Recoverable, BatchExecutable
for (int eid = lastCheckpointEid + 1; eid <= lastEid; eid++) {
try {
bftsmart.tom.util.Logger.println("(DefaultRecoverable.setState) interpreting and verifying batched requests for eid " + eid);
if (state.getMessageBatch(eid) == null) System.out.println("(DefaultRecoverable.setState) " + eid + " NULO!!!");
bftsmart.tom.util.Logger.println("(DurabilityCoordinator.setState) interpreting and verifying batched requests for eid " + eid);
if (state.getMessageBatch(eid) == null) System.out.println("(DurabilityCoordinator.setState) " + eid + " NULO!!!");
byte[][] commands = state.getMessageBatch(eid).commands; // take a batch
if (commands == null || commands.length <= 0) continue;
// INUTIL??????
//tomLayer.lm.addLeaderInfo(eid, state.getMessageBatch(eid).round,
// state.getMessageBatch(eid).leader);
//TROCAR POR EXECUTE E ARRAY DE MENSAGENS!!!!!!
//TOMMessage[] requests = new BatchReader(batch,
// manager.getStaticConf().getUseSignatures() == 1).deserialiseRequests(manager);
executeBatch2(commands, null);
// ISTO E UM PROB A RESOLVER!!!!!!!!!!!!
//tomLayer.clientsManager.requestsOrdered(requests);
// INUTIL??????
//deliverMessages(eid, tomLayer.getLCManager().getLastReg(), false, requests, batch);
// IST E UM PROB A RESOLVER!!!!
//******* EDUARDO BEGIN **************//
/*if (manager.hasUpdates()) {
processReconfigMessages(lastCheckpointEid, state.getLastCheckpointRound());
}*/
//******* EDUARDO END **************//
appExecuteBatch(commands, null);
} catch (Exception e) {
e.printStackTrace(System.err);
if (e instanceof ArrayIndexOutOfBoundsException) {
......@@ -211,7 +195,14 @@ public abstract class DefaultRecoverable implements Recoverable, BatchExecutable
}
}
@Override
public StateManager getStateManager() {
if(stateManager == null)
stateManager = new StandardStateManager();
return stateManager;
}
public abstract void installSnapshot(byte[] state);
public abstract byte[] getSnapshot();
public abstract byte[][] executeBatch2(byte[][] commands, MessageContext[] msgCtxs);
public abstract byte[][] appExecuteBatch(byte[][] commands, MessageContext[] msgCtxs);
}
......@@ -5,7 +5,9 @@ import java.security.NoSuchAlgorithmException;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import bftsmart.statemanagment.ApplicationState;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.statemanagement.StateManager;
import bftsmart.statemanagement.strategy.StandardStateManager;
import bftsmart.tom.MessageContext;
import bftsmart.tom.server.Recoverable;
import bftsmart.tom.server.SingleExecutable;
......@@ -17,7 +19,7 @@ import bftsmart.tom.util.Logger;
*/
public abstract class DefaultSingleRecoverable implements Recoverable, SingleExecutable {
public static final int CHECKPOINT_PERIOD = 50;
public static final int CHECKPOINT_PERIOD = 10000;
private ReentrantLock logLock = new ReentrantLock();
private ReentrantLock hashLock = new ReentrantLock();
......@@ -29,6 +31,8 @@ public abstract class DefaultSingleRecoverable implements Recoverable, SingleExe
private int messageCounter;
private byte[][] commands;
private StateManager stateManager;
public DefaultSingleRecoverable() {
try {
......@@ -36,8 +40,7 @@ public abstract class DefaultSingleRecoverable implements Recoverable, SingleExe
} catch (NoSuchAlgorithmException ex) {
java.util.logging.Logger.getLogger(DefaultSingleRecoverable.class.getName()).log(Level.SEVERE, null, ex);
}
byte[] state = getSnapshot();
log = new StateLog(CHECKPOINT_PERIOD, state, computeHash(state));
log = new StateLog(CHECKPOINT_PERIOD);
}
public byte[] executeOrdered(byte[] command, MessageContext msgCtx) {
......@@ -56,20 +59,19 @@ public abstract class DefaultSingleRecoverable implements Recoverable, SingleExe
if(messageCounter == msgCtx.getBatchSize()) {
if ((eid > 0) && ((eid % CHECKPOINT_PERIOD) == 0)) {
Logger.println("(DefaultRecoverable.executeBatch) Performing checkpoint for consensus " + eid);
Logger.println("(DurabilityCoordinator.executeBatch) Performing checkpoint for consensus " + eid);
stateLock.lock();
byte[] snapshot = getSnapshot();
stateLock.unlock();
saveState(snapshot, eid, 0, 0/*tomLayer.lm.getLeader(cons.getId(), cons.getDecisionRound().getNumber())*/);
} else {
Logger.println("(DefaultRecoverable.executeBatch) Storing message batch in the state log for consensus " + eid);
saveCommands(commands, eid, 0, 0/*tomLayer.lm.getLeader(cons.getId(), cons.getDecisionRound().getNumber())*/);
Logger.println("(DurabilityCoordinator.executeBatch) Storing message batch in the state log for consensus " + eid);
saveCommands(commands, eid, 0, 0);
}
messageCounter = 0;
}
return reply;
}
public final byte[] computeHash(byte[] data) {
byte[] ret = null;
......@@ -83,7 +85,8 @@ public abstract class DefaultSingleRecoverable implements Recoverable, SingleExe
private StateLog getLog() {
return log;
}
public void saveState(byte[] snapshot, int lastEid, int decisionRound, int leader) {
private void saveState(byte[] snapshot, int lastEid, int decisionRound, int leader) {
StateLog thisLog = getLog();
......@@ -104,7 +107,7 @@ public abstract class DefaultSingleRecoverable implements Recoverable, SingleExe
Logger.println("(TOMLayer.saveState) Finished saving state of EID " + lastEid + ", round " + decisionRound + " and leader " + leader);
}
public void saveCommands(byte[][] commands, int lastEid, int decisionRound, int leader) {
private void saveCommands(byte[][] commands, int lastEid, int decisionRound, int leader) {
StateLog thisLog = getLog();
logLock.lock();
......@@ -137,61 +140,33 @@ public abstract class DefaultSingleRecoverable implements Recoverable, SingleExe
DefaultApplicationState state = (DefaultApplicationState) recvState;
System.out.println("(DefaultRecoverable.setState) last eid in state: " + state.getLastEid());
System.out.println("(DurabilityCoordinator.setState) last eid in state: " + state.getLastEid());
getLog().update(state);
int lastCheckpointEid = state.getLastCheckpointEid();
lastEid = state.getLastEid();
//lastEid = lastCheckpointEid + (state.getMessageBatches() != null ? state.getMessageBatches().length : 0);
bftsmart.tom.util.Logger.println("(DefaultRecoverable.setState) I'm going to update myself from EID "
bftsmart.tom.util.Logger.println("(DurabilityCoordinator.setState) I'm going to update myself from EID "
+ lastCheckpointEid + " to EID " + lastEid);
stateLock.lock();
installSnapshot(state.getState());
// INUTIL??????
//tomLayer.lm.addLeaderInfo(lastCheckpointEid, state.getLastCheckpointRound(),
// state.getLastCheckpointLeader());
for (int eid = lastCheckpointEid + 1; eid <= lastEid; eid++) {
try {
bftsmart.tom.util.Logger.println("(DefaultRecoverable.setState) interpreting and verifying batched requests for eid " + eid);
if (state.getMessageBatch(eid) == null) System.out.println("(DefaultRecoverable.setState) " + eid + " NULO!!!");
bftsmart.tom.util.Logger.println("(DurabilityCoordinator.setState) interpreting and verifying batched requests for eid " + eid);
if (state.getMessageBatch(eid) == null) System.out.println("(DurabilityCoordinator.setState) " + eid + " NULO!!!");
byte[][] commands = state.getMessageBatch(eid).commands; // take a batch
if (commands == null || commands.length <= 0) continue;
// INUTIL??????
//tomLayer.lm.addLeaderInfo(eid, state.getMessageBatch(eid).round,
// state.getMessageBatch(eid).leader);
//TROCAR POR EXECUTE E ARRAY DE MENSAGENS!!!!!!
//TOMMessage[] requests = new BatchReader(batch,
// manager.getStaticConf().getUseSignatures() == 1).deserialiseRequests(manager);
for(byte[] command : commands)
appExecuteOrdered(command, null);
// ISTO E UM PROB A RESOLVER!!!!!!!!!!!!
//tomLayer.clientsManager.requestsOrdered(requests);
// INUTIL??????
//deliverMessages(eid, tomLayer.getLCManager().getLastReg(), false, requests, batch);
// IST E UM PROB A RESOLVER!!!!
//******* EDUARDO BEGIN **************//
/*if (manager.hasUpdates()) {
processReconfigMessages(lastCheckpointEid, state.getLastCheckpointRound());
}*/
//******* EDUARDO END **************//
} catch (Exception e) {
e.printStackTrace(System.err);
if (e instanceof ArrayIndexOutOfBoundsException) {
System.out.println("Eid do ultimo checkpoint: " + state.getLastCheckpointEid());
System.out.println("Eid do ultimo consenso: " + state.getLastEid());
System.out.println("numero de mensagens supostamente no batch: " + (state.getLastEid() - state.getLastCheckpointEid() + 1));
......@@ -206,7 +181,14 @@ public abstract class DefaultSingleRecoverable implements Recoverable, SingleExe
return lastEid;
}
@Override
public StateManager getStateManager() {
if(stateManager == null)
stateManager = new StandardStateManager();
return stateManager;
}
public abstract void installSnapshot(byte[] state);
public abstract byte[] getSnapshot();
public abstract byte[] appExecuteOrdered(byte[] command, MessageContext msgCtx);
......
......@@ -8,6 +8,8 @@ import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
public class DiskStateLog extends StateLog {
......@@ -25,6 +27,7 @@ public class DiskStateLog extends StateLog {
private boolean syncCkp;
private boolean isToLog;
private ReentrantLock checkpointLock = new ReentrantLock();
private Map<Integer, Long> logPointers;
public DiskStateLog(int id, byte[] initialState, byte[] initialHash,
boolean isToLog, boolean syncLog, boolean syncCkp) {
......@@ -33,6 +36,7 @@ public class DiskStateLog extends StateLog {
this.isToLog = isToLog;
this.syncLog = syncLog;
this.syncCkp = syncCkp;
this.logPointers = new HashMap<Integer, Long>();
if (isToLog)
createLogFile();
}
......@@ -211,6 +215,20 @@ public class DiskStateLog extends StateLog {
// }
}
public void setLastEid(int eid, int checkpointPeriod, int checkpointPortion) {
super.setLastEid(eid);
// save the file pointer to retrieve log information later
if((eid % checkpointPeriod) % checkpointPortion == checkpointPortion -1) {
int ckpReplicaIndex = (((eid % checkpointPeriod) + 1) / checkpointPortion) -1;
try {
System.out.println(" --- Replica " + ckpReplicaIndex + " took checkpoint. My current log pointer is " + log.getFilePointer());
logPointers.put(ckpReplicaIndex, log.getFilePointer());
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Updates this log, according to the information contained in the
* TransferableState object
......
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package bftsmart.tom.server;
package bftsmart.tom.server.defaultservices;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import bftsmart.statemanagment.ApplicationState;
import bftsmart.statemanagement.ApplicationState;
import bftsmart.statemanagement.StateManager;
import bftsmart.statemanagement.strategy.StandardStateManager;
import bftsmart.tom.MessageContext;
import bftsmart.tom.server.defaultservices.DefaultApplicationState;
import bftsmart.tom.server.defaultservices.StateLog;
import bftsmart.tom.server.FIFOExecutable;
import bftsmart.tom.server.Recoverable;
import bftsmart.tom.util.Logger;
/**
*
* @author Joao Sousa
* @author mhsantos
*/
public abstract class DefaultRecoverable implements Recoverable, BatchExecutable {
public static final int CHECKPOINT_PERIOD = 50;
public abstract class FIFOExecutableRecoverable implements Recoverable, FIFOExecutable {
public static final int CHECKPOINT_PERIOD = 10000;
private ReentrantLock logLock = new ReentrantLock();
private ReentrantLock hashLock = new ReentrantLock();
private ReentrantLock stateLock = new ReentrantLock();
private MessageDigest md;
private StateLog log;
public DefaultRecoverable() {
log = new StateLog(CHECKPOINT_PERIOD);
private int messageCounter;
private byte[][] commands;
private StateManager stateManager;
private ConcurrentMap<Integer, Integer> clientOperations;
private Lock fifoLock = new ReentrantLock();
private Condition updatedState = fifoLock.newCondition();
public FIFOExecutableRecoverable() {
clientOperations = new ConcurrentHashMap<Integer, Integer>();
try {
md = MessageDigest.getInstance("MD5"); // TODO: shouldn't it be SHA?
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException ex) {
java.util.logging.Logger.getLogger(DefaultRecoverable.class.getName()).log(Level.SEVERE, null, ex);
java.util.logging.Logger.getLogger(FIFOExecutableRecoverable.class.getName()).log(Level.SEVERE, null, ex);
}
log = new StateLog(CHECKPOINT_PERIOD);
}
public byte[][] executeBatch(byte[][] commands, MessageContext[] msgCtxs) {
int eid = msgCtxs[0].getConsensusId();
stateLock.lock();
byte[][] replies = executeBatch2(commands, msgCtxs);
stateLock.unlock();
if ((eid > 0) && ((eid % CHECKPOINT_PERIOD) == 0)) {
Logger.println("(DefaultRecoverable.executeBatch) Performing checkpoint for consensus " + eid);
@Override
public byte[] executeOrderedFIFO(byte[] command, MessageContext msgCtx, int clientId, int operationId) {
int eid = msgCtx.getConsensusId();
byte[] reply = null;
fifoLock.lock();
if(operationId == 0) {
stateLock.lock();
byte[] snapshot = getSnapshot();
reply = executeOrdered(command, msgCtx);
stateLock.unlock();
saveState(snapshot, eid, 0, 0/*tomLayer.lm.getLeader(cons.getId(), cons.getDecisionRound().getNumber())*/);
clientOperations.put(clientId, operationId + 1);
} else {
Logger.println("(DefaultRecoverable.executeBatch) Storing message batch in the state log for consensus " + eid);
saveCommands(commands, eid, 0, 0/*tomLayer.lm.getLeader(cons.getId(), cons.getDecisionRound().getNumber())*/);
while(clientOperations.get(clientId) == null || clientOperations.get(clientId) < operationId) {
try {
updatedState.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
stateLock.lock();
reply = executeOrdered(command, msgCtx);
stateLock.unlock();
clientOperations.put(clientId, operationId + 1);
}
updatedState.signalAll();
fifoLock.unlock();
return replies;
if(messageCounter == 0) { //first message of the batch
commands = new byte[msgCtx.getBatchSize()][];
}
commands[messageCounter] = command;
messageCounter++;
if(messageCounter == msgCtx.getBatchSize()) {
if ((eid > 0) && ((eid % CHECKPOINT_PERIOD) == 0)) {
Logger.println("(DurabilityCoordinator.executeBatch) Performing checkpoint for consensus " + eid);
stateLock.lock();
byte[] snapshot = getSnapshot();
stateLock.unlock();
saveState(snapshot, eid, 0, 0/*tomLayer.lm.getLeader(cons.getId(), cons.getDecisionRound().getNumber())*/);
} else {
Logger.println("(DurabilityCoordinator.executeBatch) Storing message batch in the state log for consensus " + eid);
saveCommands(commands, eid, 0, 0);
}
messageCounter = 0;
}
return reply;
}
@Override
public byte[] executeUnorderedFIFO(byte[] command, MessageContext msgCtx, int clientId, int operationId) {
byte[] reply = null;
fifoLock.lock();
if(operationId == 0) {
reply = executeUnordered(command, msgCtx);
clientOperations.put(clientId, operationId + 1);
} else {
while(clientOperations.get(clientId) == null || clientOperations.get(clientId) < operationId) {
try {
updatedState.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
reply = executeUnordered(command, msgCtx);
clientOperations.put(clientId, operationId + 1);
}
updatedState.signalAll();
fifoLock.unlock();
return reply;
}
public final byte[] computeHash(byte[] data) {
byte[] ret = null;
hashLock.lock();
......@@ -71,11 +134,12 @@ public abstract class DefaultRecoverable implements Recoverable, BatchExecutable
return ret;
}
private StateLog getLog() {
return log;
}
public void saveState(byte[] snapshot, int lastEid, int decisionRound, int leader) {
private void saveState(byte[] snapshot, int lastEid, int decisionRound, int leader) {
StateLog thisLog = getLog();
......@@ -96,8 +160,7 @@ public abstract class DefaultRecoverable implements Recoverable, BatchExecutable
Logger.println("(TOMLayer.saveState) Finished saving state of EID " + lastEid + ", round " + decisionRound + " and leader " + leader);
}
public void saveCommands(byte[][] commands, int lastEid, int decisionRound, int leader) {
private void saveCommands(byte[][] commands, int lastEid, int decisionRound, int leader) {
StateLog thisLog = getLog();
logLock.lock();
......@@ -108,7 +171,7 @@ public abstract class DefaultRecoverable implements Recoverable, BatchExecutable
thisLog.setLastEid(lastEid);
logLock.unlock();
/*System.out.println("guardei comandos");
System.out.println("tamanho do log: " + thisLog.getNumBatches());*/
Logger.println("(TOMLayer.saveBatch) Finished saving batch of EID " + lastEid + ", round " + decisionRound + " and leader " + leader);
......@@ -117,75 +180,46 @@ public abstract class DefaultRecoverable implements Recoverable, BatchExecutable
@Override
public ApplicationState getState(int eid, boolean sendState) {
logLock.lock();
System.out.println(" EID: " + eid + "sendstate: " + sendState);
ApplicationState ret = (eid > -1 ? getLog().getApplicationState(eid, sendState) : new DefaultApplicationState());
logLock.unlock();
return ret;
}
@Override
public int setState(ApplicationState recvState) {
int lastEid = -1;
if (recvState instanceof DefaultApplicationState) {
DefaultApplicationState state = (DefaultApplicationState) recvState;
System.out.println("(DefaultRecoverable.setState) last eid in state: " + state.getLastEid());
System.out.println("(DurabilityCoordinator.setState) last eid in state: " + state.getLastEid());
getLog().update(state);
int lastCheckpointEid = state.getLastCheckpointEid();
lastEid = state.getLastEid();
//lastEid = lastCheckpointEid + (state.getMessageBatches() != null ? state.getMessageBatches().length : 0);
bftsmart.tom.util.Logger.println("(DefaultRecoverable.setState) I'm going to update myself from EID "
bftsmart.tom.util.Logger.println("(DurabilityCoordinator.setState) I'm going to update myself from EID "
+ lastCheckpointEid + " to EID " + lastEid);
stateLock.lock();
installSnapshot(state.getState());
// INUTIL??????
//tomLayer.lm.addLeaderInfo(lastCheckpointEid, state.getLastCheckpointRound(),
// state.getLastCheckpointLeader());
for (int eid = lastCheckpointEid + 1; eid <= lastEid; eid++) {
try {
bftsmart.tom.util.Logger.println("(DefaultRecoverable.setState) interpreting and verifying batched requests for eid " + eid);
System.out.println("(DefaultRecoverable.setState) interpreting and verifying batched requests for eid " + eid);
if (state.getMessageBatch(eid) == null) System.out.println("(DefaultRecoverable.setState) " + eid + " NULO!!!");
bftsmart.tom.util.Logger.println("(DurabilityCoordinator.setState) interpreting and verifying batched requests for eid " + eid);
if (state.getMessageBatch(eid) == null) System.out.println("(DurabilityCoordinator.setState) " + eid + " NULO!!!");
byte[][] commands = state.getMessageBatch(eid).commands; // take a batch
// INUTIL??????
//tomLayer.lm.addLeaderInfo(eid, state.getMessageBatch(eid).round,
// state.getMessageBatch(eid).leader);
//TROCAR POR EXECUTE E ARRAY DE MENSAGENS!!!!!!
//TOMMessage[] requests = new BatchReader(batch,
// manager.getStaticConf().getUseSignatures() == 1).deserialiseRequests(manager);
executeBatch2(commands, null);
// ISTO E UM PROB A RESOLVER!!!!!!!!!!!!
//tomLayer.clientsManager.requestsOrdered(requests);
// INUTIL??????
//deliverMessages(eid, tomLayer.getLCManager().getLastReg(), false, requests, batch);
// IST E UM PROB A RESOLVER!!!!
//******* EDUARDO BEGIN **************//
/*if (manager.hasUpdates()) {
processReconfigMessages(lastCheckpointEid, state.getLastCheckpointRound());
}*/
//******* EDUARDO END **************//
if (commands == null || commands.length <= 0) continue;
for(byte[] command : commands)
executeOrdered(command, null);
} catch (Exception e) {
e.printStackTrace(System.err);
if (e instanceof ArrayIndexOutOfBoundsException) {
System.out.println("Eid do ultimo checkpoint: " + state.getLastCheckpointEid());
System.out.println("Eid do ultimo consenso: " + state.getLastEid());
System.out.println("numero de mensagens supostamente no batch: " + (state.getLastEid() - state.getLastCheckpointEid() + 1));
......@@ -201,7 +235,13 @@ public abstract class DefaultRecoverable implements Recoverable, BatchExecutable
return lastEid;
}
@Override
public StateManager getStateManager() {
if(stateManager == null)
stateManager = new StandardStateManager();
return stateManager;
}
public abstract void installSnapshot(byte[] state);
public abstract byte[] getSnapshot();
public abstract byte[][] executeBatch2(byte[][] commands, MessageContext[] msgCtxs);
}
......@@ -101,7 +101,6 @@ public class StateLog {
* @param lastCheckpointEid Execution ID for the last checkpoint
*/
public void setLastCheckpointEid(int lastCheckpointEid) {
this.lastCheckpointEid = lastCheckpointEid;
}
......@@ -238,9 +237,7 @@ public class StateLog {
int lastEid = -1;
if (/*lastCheckpointEid > -1 && */eid >= lastCheckpointEid && eid <= this.lastEid) {
//if (eid <= this.lastEid) {
if (eid >= lastCheckpointEid && eid <= this.lastEid) {
int size = eid - lastCheckpointEid ;
if (size > 0) {
......@@ -250,11 +247,6 @@ public class StateLog {
batches[i] = messageBatches[i];
}
lastEid = eid;
//} else if (this.lastEid > -1) {
// batches = messageBatches;
// lastEid = this.lastEid;
//}
return new DefaultApplicationState(batches, lastCheckpointEid, lastCheckpointRound, lastCheckpointLeader, lastEid, (setState ? state : null), stateHash);
}
......
package bftsmart.tom.server.defaultservices.durability;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import bftsmart.statemanagement.strategy.durability.CSTRequest;
import bftsmart.statemanagement.strategy.durability.CSTRequestF1;
import bftsmart.statemanagement.strategy.durability.CSTState;
import bftsmart.tom.server.defaultservices.CommandsInfo;
import bftsmart.tom.server.defaultservices.FileRecoverer;
import bftsmart.tom.server.defaultservices.StateLog;
import bftsmart.tom.util.TOMUtil;
public class DurableStateLog extends StateLog {
private int id;
public final static String DEFAULT_DIR = "files".concat(System
.getProperty("file.separator"));
private static final int INT_BYTE_SIZE = 4;
private static final int EOF = 0;
private RandomAccessFile log;
private boolean syncLog;
private String logPath;
private String lastCkpPath;
private boolean syncCkp;
private boolean isToLog;
private ReentrantLock checkpointLock = new ReentrantLock();
private Map<Integer, Long> logPointers;
public DurableStateLog(int id, byte[] initialState, byte[] initialHash,
boolean isToLog, boolean syncLog, boolean syncCkp) {
super(initialState, initialHash);
this.id = id;
this.isToLog = isToLog;
this.syncLog = syncLog;
this.syncCkp = syncCkp;
this.logPointers = new HashMap<Integer, Long>();
if (isToLog)
createLogFile();
}
private void createLogFile() {
logPath = DEFAULT_DIR + String.valueOf(id) + "."
+ System.currentTimeMillis() + ".log";
try {
log = new RandomAccessFile(logPath, (syncLog ? "rwd" : "rw"));
// PreAllocation
/*
* log.setLength(TEN_MB); log.seek(0);
*/
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
/**
* Adds a message batch to the log. This batches should be added to the log
* in the same order in which they are delivered to the application. Only
* the 'k' batches received after the last checkpoint are supposed to be
* kept
*
* @param batch
* The batch of messages to be kept.
*/
public void addMessageBatch(byte[][] commands, int round, int leader) {
CommandsInfo command = new CommandsInfo(commands, round, leader);
if (isToLog)
writeCommandToDisk(command);
}
private void writeCommandToDisk(CommandsInfo commandsInfo) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(commandsInfo);
oos.flush();
byte[] batchBytes = bos.toByteArray();
ByteBuffer bf = ByteBuffer.allocate(2 * INT_BYTE_SIZE
+ batchBytes.length);
bf.putInt(batchBytes.length);
bf.put(batchBytes);
bf.putInt(EOF);
log.write(bf.array());
log.seek(log.length() - INT_BYTE_SIZE);// Next write will overwrite
// the EOF mark
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void newCheckpoint(byte[] state, byte[] stateHash) {
String ckpPath = DEFAULT_DIR + String.valueOf(id) + "."
+ System.currentTimeMillis() + ".tmp";
try {
checkpointLock.lock();
RandomAccessFile ckp = new RandomAccessFile(ckpPath,
(syncCkp ? "rwd" : "rw"));
ByteBuffer bf = ByteBuffer.allocate(state.length + stateHash.length
+ 3 * INT_BYTE_SIZE);
bf.putInt(state.length);
bf.put(state);
bf.putInt(stateHash.length);
bf.put(stateHash);
bf.putInt(EOF);
byte[] ckpState = bf.array();
ckp.write(ckpState);
if (isToLog)
deleteLogFile();
deleteLastCkp();
renameCkp(ckpPath);
if (isToLog)
createLogFile();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
checkpointLock.unlock();
}
}
private void renameCkp(String ckpPath) {
String finalCkpPath = ckpPath.replace(".tmp", ".ckp");
new File(ckpPath).renameTo(new File(finalCkpPath));
lastCkpPath = finalCkpPath;
}
private void deleteLastCkp() {
if (lastCkpPath != null)
new File(lastCkpPath).delete();
}
private void deleteLogFile() {
try {
log.close();
new File(logPath).delete();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public CSTState getState(CSTRequest cstRequest) {
int eid = cstRequest.getEid();
int lastCheckpointEid = getLastCheckpointEid();
int lastEid = getLastEid();
System.out.println("LAST CKP EID = " + lastCheckpointEid);
System.out.println("EID = " + eid);
System.out.println("LAST EID = " + lastEid);
FileRecoverer fr = new FileRecoverer(id, DEFAULT_DIR);
if(cstRequest instanceof CSTRequestF1) {
CSTRequestF1 requestF1 = (CSTRequestF1)cstRequest;
if(id == requestF1.getCheckpointReplica()) {
// This replica is expected to send the checkpoint plus the hashes of lower and upper log portions
checkpointLock.lock();
byte[] ckpState = fr.getCkpState();
checkpointLock.unlock();
System.out.println("--- sending checkpoint: " + ckpState.length);
CommandsInfo[] logLower = fr.getLogState(requestF1.getLogLowerSize());
CommandsInfo[] logUpper = fr.getLogState(logPointers.get(requestF1.getLogUpper()), 0, requestF1.getLogUpperSize());
byte[] logLowerBytes = TOMUtil.getBytes(logLower);
System.out.println(logLower.length + " Log lower bytes size: " + logLowerBytes.length);
byte[] logLowerHash = TOMUtil.computeHash(logLowerBytes);
byte[] logUpperBytes = TOMUtil.getBytes(logUpper);
System.out.println(logUpper.length + " Log upper bytes size: " + logUpperBytes.length);
byte[] logUpperHash = TOMUtil.computeHash(logUpperBytes);
CSTState cstState = new CSTState(ckpState, null, null, logLowerHash, null, logUpperHash, lastCheckpointEid, lastEid);
return cstState;
} else if(id == requestF1.getLogLower()) {
// This replica is expected to send the lower part of the log
System.out.print("--- sending lower log: " + requestF1.getLogLowerSize() + " from " + logPointers.get(requestF1.getCheckpointReplica())) ;
CommandsInfo[] logLower = fr.getLogState(logPointers.get(requestF1.getCheckpointReplica()), 0, requestF1.getLogLowerSize());
System.out.println(" " + TOMUtil.getBytes(logLower).length + " bytes");
CSTState cstState = new CSTState(null, null, logLower, null, null, null, lastCheckpointEid, lastEid);
return cstState;
} else {
// This replica is expected to send the upper part of the log plus the hash for its checkpoint
System.out.println("--- sending upper log: " + requestF1.getLogUpperSize());
checkpointLock.lock();
fr.recoverCkpHash();
byte[] ckpHash = fr.getCkpStateHash();
byte[] ckpState = fr.getCkpState();
checkpointLock.unlock();
CommandsInfo[] logUpper = fr.getLogState(requestF1.getLogUpperSize());
System.out.println(" " + TOMUtil.getBytes(logUpper).length + " bytes");
System.out.println("--- State size: " + ckpState.length + " Current state Hash: " + ckpHash);
int lastEidInState = lastCheckpointEid + requestF1.getLogUpperSize();
CSTState cstState = new CSTState(null, ckpHash, null, null, logUpper, null, lastCheckpointEid, lastEidInState);
return cstState;
}
}
// else if(cstRequest instanceof CSTRequestFGT1) {
// CSTRequestFGT1 requestFGT1 = (CSTRequestFGT1)cstRequest;
// if(id == requestFGT1.getCheckpointReplica()) {
// checkpointLock.lock();
// byte[] ckpState = fr.getCkpState();
// checkpointLock.unlock();
// batches = fr.getLogState(requestFGT1.getLogSize());
// System.out.println("--- sending checkpoint: " + ckpState.length);
// return new DefaultApplicationState(batches, lastCheckpointEid, getLastCheckpointRound(), getLastCheckpointLeader(), eid, ckpState, null);
// } else { // Replica should send the checkpoint and log hashes
// batches = fr.getLogState(requestFGT1.getLogSize() - requestFGT1.getNbrHashesBeforeCkp());
// byte[] logBytes = TOMUtil.getBytes(batches);
// byte[] logHash = TOMUtil.computeHash(logBytes);
// fr.recoverCkpHash();
// byte[] ckpHash = fr.getCkpStateHash();
// return new DefaultApplicationState(null, logHash, lastCheckpointEid, getLastCheckpointRound(), getLastCheckpointLeader(), eid, null, ckpHash);
// }
//
// }
return null;
}
public void transferApplicationState(SocketChannel sChannel, int eid) {
FileRecoverer fr = new FileRecoverer(id, DEFAULT_DIR);
fr.transferCkpState(sChannel);
// int lastCheckpointEid = getLastCheckpointEid();
// int lastEid = getLastEid();
// if (eid >= lastCheckpointEid && eid <= lastEid) {
// int size = eid - lastCheckpointEid;
// fr.transferLog(sChannel, size);
// }
}
public void setLastEid(int eid, int checkpointPeriod, int checkpointPortion) {
super.setLastEid(eid);
// save the file pointer to retrieve log information later
if((eid % checkpointPeriod) % checkpointPortion == checkpointPortion -1) {
int ckpReplicaIndex = (((eid % checkpointPeriod) + 1) / checkpointPortion) -1;
try {
System.out.println(" --- Replica " + ckpReplicaIndex + " took checkpoint. My current log pointer is " + log.getFilePointer());
logPointers.put(ckpReplicaIndex, log.getFilePointer());
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Updates this log, according to the information contained in the
* TransferableState object
*
* @param transState
* TransferableState object containing the information which is
* used to updated this log
*/
public void update(CSTState state) {
newCheckpoint(state.getSerializedState(), state.getStateHash());
setLastCheckpointEid(state.getCheckpointEid());
}
}
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册