/******************************************************************************* * 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.comm; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.util.ArrayList; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import uk.ac.imperial.lsds.seep.comm.serialization.DataTuple; import uk.ac.imperial.lsds.seep.comm.serialization.messages.BatchTuplePayload; import uk.ac.imperial.lsds.seep.comm.serialization.messages.Payload; import uk.ac.imperial.lsds.seep.comm.serialization.messages.TuplePayload; import uk.ac.imperial.lsds.seep.comm.serialization.serializers.ArrayListSerializer; import uk.ac.imperial.lsds.seep.infrastructure.NodeManager; import uk.ac.imperial.lsds.seep.runtimeengine.CoreRE; import uk.ac.imperial.lsds.seep.runtimeengine.DataStructureAdapter; import uk.ac.imperial.lsds.seep.runtimeengine.DataStructureI; import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.io.Input; public class IncomingDataHandlerWorker implements Runnable{ final private Logger LOG = LoggerFactory.getLogger(IncomingDataHandlerWorker.class); private Socket upstreamSocket = null; private CoreRE owner = null; private boolean goOn; private Map<String, Integer> idxMapper; private DataStructureAdapter dsa; private Kryo k = null; public IncomingDataHandlerWorker(Socket upstreamSocket, CoreRE owner, Map<String, Integer> idxMapper, DataStructureAdapter dsa){ //upstream id this.upstreamSocket = upstreamSocket; this.owner = owner; this.goOn = true; this.idxMapper = idxMapper; this.dsa = dsa; this.k = initializeKryo(); } private Kryo initializeKryo(){ //optimize here kryo Kryo k = new Kryo(); k.setClassLoader(owner.getRuntimeClassLoader()); k.register(ArrayList.class, new ArrayListSerializer()); k.register(Payload.class); k.register(TuplePayload.class); k.register(BatchTuplePayload.class); return k; } public void run() { /** Experimental asyn **/ // try{ // //Get inputQueue from owner // DataStructureAdapter dsa = owner.getDSA(); // //Get inputStream of incoming connection // InputStream is = upstreamSocket.getInputStream(); // BufferedInputStream bis = new BufferedInputStream(is, 8192); // Input i = new Input(bis); // // while(goOn){ // TuplePayload tp = k.readObject(i, TuplePayload.class); // DataTuple reg = new DataTuple(idxMapper, tp); // dsa.push(reg); // } // } // catch(IOException io){ // NodeManager.nLogger.severe("-> IncDataHandlerWorker. IO Error "+io.getMessage()); // io.printStackTrace(); // } /** experimental sync **/ try{ // Get incomingOp id int opId = owner.getOpIdFromInetAddress(((InetSocketAddress)upstreamSocket.getRemoteSocketAddress()).getAddress()); int originalOpId = owner.getOriginalUpstreamFromOpId(opId); DataStructureI dso = null; if(dsa.getUniqueDso() != null){ dso = dsa.getUniqueDso(); LOG.info("-> Unique data adapter in this node: "+dso); } else{ dso = dsa.getDataStructureIForOp(originalOpId); LOG.info("-> Multiple data adapters in this node"); } //Get inputStream of incoming connection InputStream is = upstreamSocket.getInputStream(); BufferedInputStream bis = new BufferedInputStream(is); Input i = new Input(bis); BatchTuplePayload batchTuplePayload = null; long lastIncomingTs = -1; while(goOn){ batchTuplePayload = k.readObject(i, BatchTuplePayload.class); ArrayList<TuplePayload> batch = batchTuplePayload.batch; for(TuplePayload t_payload : batch){ long incomingTs = t_payload.timestamp; // Check for already processed data /// \todo{should be <= but the problem is that logical clock in java has ms granularity. This means that once you /// send more than 1000 events per second, some events are discarded here, since their ts is the same...} if(incomingTs < lastIncomingTs){ System.out.println("Duplicate"); continue; } owner.setTsData(opId, incomingTs); lastIncomingTs = incomingTs; //Put data in inputQueue if(owner.checkSystemStatus()){ DataTuple reg = new DataTuple(idxMapper, t_payload); dso.push(reg); } else{ ///\todo{check for garbage in the tcp buffers} } } } LOG.error("-> Data connection closing..."); upstreamSocket.close(); } catch(IOException io){ LOG.error("-> IncDataHandlerWorker. IO Error "+io.getMessage()); io.printStackTrace(); } } }