/*******************************************************************************
* Copyright (c) 2013 Imperial College London.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Raul Castro Fernandez - initial design and implementation
******************************************************************************/
package uk.ac.imperial.lsds.seep.runtimeengine;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.ac.imperial.lsds.seep.GLOBALS;
import uk.ac.imperial.lsds.seep.comm.serialization.ControlTuple;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.Ack;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.BackupNodeState;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.BackupOperatorState;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.BackupRI;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.InitNodeState;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.InitOperatorState;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.InitRI;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.InvalidateState;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.RawData;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.ReconfigureConnection;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.Resume;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.ScaleOutInfo;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.StateAck;
import uk.ac.imperial.lsds.seep.comm.serialization.controlhelpers.StateChunk;
import uk.ac.imperial.lsds.seep.operator.EndPoint;
import uk.ac.imperial.lsds.seep.processingunit.PUContext;
import uk.ac.imperial.lsds.seep.reliable.MemoryChunk;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.MapSerializer;
public class ControlDispatcher {
final private Logger LOG = LoggerFactory.getLogger(ControlDispatcher.class);
private final int BLIND_SOCKET;
private final int CONTROL_SOCKET;
private PUContext puCtx = null;
private Kryo k = null;
///\fixme{remove this variable asap. debugging for now}
// FIXME: REMOVE THIS FROM HERE ASAP
private Output largeOutput = new Output(10000000);
public ControlDispatcher(PUContext puCtx){
this.puCtx = puCtx;
this.BLIND_SOCKET = new Integer(GLOBALS.valueFor("blindSocket"));
this.CONTROL_SOCKET = new Integer(GLOBALS.valueFor("controlSocket"));
this.k = initializeKryo();
}
private Kryo initializeKryo(){
k = new Kryo();
k.register(ControlTuple.class);
k.register(MemoryChunk.class);
k.register(StateChunk.class);
k.register(HashMap.class, new MapSerializer());
k.register(BackupOperatorState.class);
k.register(byte[].class);
k.register(RawData.class);
k.register(Ack.class);
k.register(BackupNodeState.class);
k.register(Resume.class);
k.register(ScaleOutInfo.class);
k.register(StateAck.class);
k.register(ArrayList.class);
k.register(BackupRI.class);
k.register(InitNodeState.class);
k.register(InitOperatorState.class);
k.register(InitRI.class);
k.register(InvalidateState.class);
k.register(ReconfigureConnection.class);
return k;
}
public void sendAllUpstreams(ControlTuple ct){
for(int i = 0; i < puCtx.getUpstreamTypeConnection().size(); i++) {
sendUpstream(ct, i);
}
}
public void sendUpstream(ControlTuple ct, int index){
EndPoint obj = puCtx.getUpstreamTypeConnection().elementAt(index);
Socket socket = ((SynchronousCommunicationChannel) obj).getDownstreamControlSocket();
Output output = null;
try{
output = new Output(socket.getOutputStream());
synchronized(k){
synchronized(socket){
synchronized (output){
k.writeObject(output, ct);
output.flush();
}
}
}
}
catch(IOException io){
LOG.error("-> Dispatcher. While sending control msg "+io.getMessage());
io.printStackTrace();
}
}
public void sendOpenSessionWaitACK(ControlTuple ct, int index){
DisposableCommunicationChannel dcc = (DisposableCommunicationChannel) puCtx.getStarTopology().get(index);
int targetOpId = dcc.getOperatorId();
InetAddress ip_endpoint = dcc.getIp();
Output output = null;
BufferedReader in = null;
try{
Socket socket = new Socket(ip_endpoint, (CONTROL_SOCKET+targetOpId));
output = new Output(socket.getOutputStream());
synchronized(k){
synchronized(socket){
synchronized (output){
k.writeObject(output, ct);
output.flush();
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String reply = null;
System.out.println("waiting to read answer/reply");
reply = in.readLine();
System.out.println("READ");
in.close();
output.close();
}
}
}
}
catch(IOException io){
LOG.error("-> Dispatcher. While sending control msg "+io.getMessage());
io.printStackTrace();
}
}
public void sendCloseSession(ControlTuple ct, int index){
DisposableCommunicationChannel dcc = (DisposableCommunicationChannel) puCtx.getStarTopology().get(index);
int targetOpId = dcc.getOperatorId();
InetAddress ip_endpoint = dcc.getIp();
Output output = null;
try{
Socket socket = new Socket(ip_endpoint, (CONTROL_SOCKET+targetOpId));
output = new Output(socket.getOutputStream());
synchronized(k){
synchronized(socket){
synchronized (output){
k.writeObject(output, ct);
output.flush();
// output.close();
}
}
}
}
catch(IOException io){
LOG.error("-> Dispatcher. While sending control msg "+io.getMessage());
io.printStackTrace();
}
}
public void sendUpstream_blind(ControlTuple ct, int index){
long startSend = System.currentTimeMillis();
// EndPoint obj = puCtx.getUpstreamTypeConnection().elementAt(index);
InetAddress ip_endpoint = ((DisposableCommunicationChannel)puCtx.getStarTopology().get(index)).getIp();
//Reopen socket before sending... only if closed
// Socket socket = ((SynchronousCommunicationChannel) obj).reOpenBlindSocket();
try{
Socket socket = new Socket(ip_endpoint, BLIND_SOCKET);
largeOutput.setOutputStream(socket.getOutputStream());
// output = new Output(socket.getOutputStream());
// System.out.println("WRITING TO: "+socket.toString());
synchronized(k){
synchronized(socket){
synchronized (largeOutput){
long startWrite = System.currentTimeMillis();
System.out.println("Send chunk to: "+socket.toString());
k.writeObject(largeOutput, ct);
// System.out.println("%*% SER SIZE: "+largeOutput.toBytes().length+" bytes");
largeOutput.flush();
largeOutput.close();
long stopWrite = System.currentTimeMillis();
// System.out.println("% Write socket: "+(stopWrite-startWrite));
}
}
}
}
catch(IOException io){
LOG.error("-> Dispatcher. While sending control msg "+io.getMessage());
io.printStackTrace();
}
long stopSend = System.currentTimeMillis();
// System.out.println("% Send : "+(stopSend-startSend));
}
public void sendUpstream_blind_metadata(int data, int index){
EndPoint obj = puCtx.getUpstreamTypeConnection().elementAt(index);
Socket socket = ((SynchronousCommunicationChannel) obj).reOpenBlindSocket();
try{
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeInt(data);
dos.flush();
dos.close();
}
catch(IOException io){
LOG.error("-> Dispatcher. While sending control msg "+io.getMessage());
io.printStackTrace();
}
}
public void sendDownstream(ControlTuple ct, int index){
EndPoint obj = puCtx.getDownstreamTypeConnection().elementAt(index);
if (obj instanceof SynchronousCommunicationChannel){
Socket socket = ((SynchronousCommunicationChannel) obj).getDownstreamControlSocket();
Output output = null;
try{
output = new Output(socket.getOutputStream());
synchronized(k){
synchronized (socket){
k.writeObject(output, ct);
output.flush();
}
}
}
catch(IOException io){
LOG.error("-> Dispatcher. While sending control msg "+io.getMessage());
io.printStackTrace();
}
}
}
public void ackControlMessage(ControlTuple genericAck, OutputStream os){
Output output = new Output(os);
synchronized(k){
k.writeObject(output, genericAck);
}
output.flush();
}
public void initStateMessage(ControlTuple initStateMsg, OutputStream os){
Output output = new Output(os);
synchronized(k){
k.writeObject(output, initStateMsg);
}
output.flush();
}
public Object deepCopy(Object toCopy){
long s = System.currentTimeMillis();
System.out.println("CLASS: "+toCopy.getClass().toString());
synchronized(k){
k.register(toCopy.getClass());
// Object o = k.copy(toCopy);
long e = System.currentTimeMillis();
System.out.println("TOTAL-Kryo-SER: "+(e-s));
return k.copy(toCopy);
}
}
}