package smartkv.server;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import javax.print.attribute.IntegerSyntax;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.primitives.Ints;
import bftsmart.tom.MessageContext;
import bftsmart.tom.ReplicaContext;
import bftsmart.tom.ServiceReplica;
import bftsmart.tom.server.defaultservices.DefaultSingleRecoverable;
public class MapSmart extends DefaultSingleRecoverable{
//TODO extract these methods to a standalone package.
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(b);
o.writeObject(obj);
o.flush();
o.close();
return b.toByteArray();
}
public static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream b = new ByteArrayInputStream(bytes);
ObjectInputStream o = new ObjectInputStream(b);
return o.readObject();
}
private Datastore keyValue = new KeyValueStore();
private ColumnDatastore columns = new KeyValueColumnStore();
public static void main(String[] args){
new MapSmart(0);
new MapSmart(1);
new MapSmart(2);
new MapSmart(3);
/*File f = new File("./config/currentView");
if (f.exists()){
f.delete();
}*/
}
ServiceReplica replica = null;
@SuppressWarnings("unused")
private ReplicaContext replicaContext;
private Logger log = LoggerFactory.getLogger(MapSmart.class);
public MapSmart(int id) {
replica = new ServiceReplica(id, this, this);
}
@Override
public void setReplicaContext(ReplicaContext replicaContext) {
this.replicaContext = replicaContext;
}
@Override
public byte[] executeUnordered(byte[] command, MessageContext msgCtx) {
return execute(command);
//TODO cleanup.
}
@Override
public byte[] appExecuteOrdered(byte[] command, MessageContext msgCtx) {
return execute(command);
}
/**
* @param command
* @return
*/
private byte[] execute(byte[] command) {
//FIXME: Proper serialization/deserialization of messages.
ByteArrayInputStream in = new ByteArrayInputStream(command);
try {
DataInputStream dis = new DataInputStream(in);
//XXX bad in so many different ways... :/
//byte[] version_b = new byte[4];
//dis.read(version_b);
DataStoreVersion version = DataStoreVersion.values()[dis.readInt()];
Datastore ds = version == DataStoreVersion.COLUMN_KEY_VALUE ? this.columns : this.keyValue;
RequestType reqType = RequestType.values()[dis.readInt()];
//XXX- remember to convince yourself again that this shouldn't go in the enum itfself.
switch(reqType){
case GET_AND_INCREMENT:
return ds.get_and_increment(dis);
case CREATE_TABLE:
return ds.create_table(dis);
case CREATE_TABLE_MAX_SIZE:
return ds.create_table_max_size(dis);
case REMOVE_TABLE:
return ds.remove_table(dis);
case CONTAINS_TABLE:
return ds.contains_table(dis);
case CLEAR_DATASTORE:
ds.clear();
return null;
case CLEAR_TABLE:
return ds.clear_table(dis);
case CONTAINS_KEY_IN_TABLE:
return ds.contains_key_in_table(dis);
case GET_TABLE:
return ds.get_table(dis);
case GET_VALUE_IN_TABLE:
return ds.get_value_in_table(dis);
case IS_DATASTORE_EMPTY:
return ds.is_datastore_empty();
case IS_TABLE_EMPTY:
return ds.is_table_empty(dis);
case PUT_VALUE_IN_TABLE:
return ds.put_value_in_table( dis);
case INSERT_VALUE_IN_TABLE:
return ds.insert_value_in_table(dis);
case PUT_VALUES_IN_TABLE:
return ds.put_Values_in_table(dis);
case REMOVE_VALUE_FROM_TABLE:
return ds.remove_value_from_table(dis);
case SIZE_OF_TABLE:
return ds.size_of_table(dis);
case ATOMIC_REPLACE_VALUE_IN_TABLE:
return ds.atomic_replace_value_in_table(dis);
case ATOMIC_REMOVE_IF_VALUE:
return ds.atomic_remove_if_value(dis);
case ATOMIC_PUT_IF_ABSENT:
return ds.atomic_put_if_absent(dis);
case GET_COLUMN:
if (version != DataStoreVersion.COLUMN_KEY_VALUE) throw new UnsupportedOperationException("This is operation is not supported for the specified version");
return this.columns.get_column(dis);
case SET_COLUMN:
if (version != DataStoreVersion.COLUMN_KEY_VALUE) throw new UnsupportedOperationException("This is operation is not supported for the specified version");
return this.columns.put_column(dis);
case VALUES:
return ds.values(dis);
case CREATE_POINTER_TABLE:
return ds.create_pointer_table(dis);
case GET_COLUMN_BY_REFERENCE:
if (version != DataStoreVersion.COLUMN_KEY_VALUE) throw new UnsupportedOperationException("This is operation is not supported for the specified version");
return this.columns.get_column_by_reference(dis);
case GET_VALUE_IN_TABLE_BY_REFERENCE:
return ds.get_referenced_value(dis);
default:
break;
}
} catch (IOException e) {
System.err.println("Exception reading data in the replica: " + e.getMessage());
e.printStackTrace();
return null;
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public void installSnapshot(byte[] state) {
ByteArrayInputStream bis = new ByteArrayInputStream(state);
try {
ObjectInputStream in = new ObjectInputStream(bis);
this.columns = (ColumnDatastore) in.readObject();
this.keyValue = (Datastore) in.readObject();
in.close();
bis.close();
} catch (ClassNotFoundException e) {
System.err.print("Coudn't find Map: " + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
System.err.print("Exception installing the application state: " + e.getMessage());
e.printStackTrace();
}
}
@Override
public byte[] getSnapshot() {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(this.columns);
out.writeObject(this.keyValue);
out.flush();
out.close();
bos.close();
return bos.toByteArray();
} catch (IOException e) {
System.out.println("Exception when trying to take a + " +
"snapshot of the application state" + e.getMessage());
e.printStackTrace();
return null; //FIXME
} // TODO Auto-generated method stub
}
}