package uk.ac.imperial.lsds.seepworker.core.output; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import java.util.concurrent.atomic.AtomicBoolean; import uk.ac.imperial.lsds.seep.api.DataReference; import uk.ac.imperial.lsds.seep.api.RuntimeEventRegister; import uk.ac.imperial.lsds.seep.api.data.OTuple; import uk.ac.imperial.lsds.seep.api.data.TupleInfo; import uk.ac.imperial.lsds.seep.core.EventAPI; import uk.ac.imperial.lsds.seep.core.EventBasedOBuffer; public class OutputBuffer implements EventBasedOBuffer { private final int BATCH_SIZE; private DataReference dr; private EventAPI eAPI; private ByteBuffer buf; private AtomicBoolean completed = new AtomicBoolean(false); private int tuplesInBatch = 0; private int currentBatchSize = 0; public OutputBuffer(DataReference dr, int batchSize) { this.dr = dr; this.BATCH_SIZE = batchSize; int headroomSize = this.BATCH_SIZE * 2; buf = ByteBuffer.allocate(headroomSize); buf.position(TupleInfo.PER_BATCH_OVERHEAD_SIZE); } @Override public DataReference getDataReference() { return dr; } @Override public int id() { return dr.getId(); } @Override public void setEventAPI(EventAPI eAPI) { this.eAPI = eAPI; } @Override public EventAPI getEventAPI() { return eAPI; } @Override public boolean drainTo(WritableByteChannel channel) { boolean fullyWritten = false; if(completed.get()){ int totalBytesToWrite = buf.remaining(); int writtenBytes = 0; try { writtenBytes = channel.write(buf); } catch (IOException e) { e.printStackTrace(); } if(writtenBytes == totalBytesToWrite){ // prepare buffer to be filled again tuplesInBatch = 0; currentBatchSize = 0; //TupleInfo.PER_BATCH_OVERHEAD_SIZE; buf.clear(); buf.position(TupleInfo.PER_BATCH_OVERHEAD_SIZE); boolean success = completed.compareAndSet(true, false); if(!success) { System.out.println("PROB WHEN DRAINING"); System.exit(0); } notifyHere(); return true; } else { return false; } } return fullyWritten; } @Override public boolean write(byte[] data, RuntimeEventRegister reg) { if(completed.get()){ waitHere(); // block } int tupleSize = data.length; buf.putInt(tupleSize); buf.put(data); tuplesInBatch++; currentBatchSize = currentBatchSize + tupleSize + TupleInfo.TUPLE_SIZE_OVERHEAD; if(bufferIsFull()) { int currentPosition = buf.position(); int currentLimit = buf.limit(); buf.position(TupleInfo.NUM_TUPLES_BATCH_OFFSET); buf.putInt(tuplesInBatch); buf.putInt(currentBatchSize); buf.position(currentPosition); buf.limit(currentLimit); buf.flip(); // leave the buffer ready to be read boolean success = completed.compareAndSet(false, true); if(!success){ System.out.println("PROB when writing"); System.exit(0); } } return completed.get(); } @Override public boolean write(OTuple o, RuntimeEventRegister reg) { // TODO Auto-generated method stub return false; } @Override public boolean readyToWrite(){ return completed.get(); } private boolean bufferIsFull(){ return buf.position() >= BATCH_SIZE; } private void notifyHere(){ synchronized(this){ notify(); } } private void waitHere(){ try { synchronized(this){ while(completed.get()){ wait(); } } } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void flush() { // TODO Auto-generated method stub } }