package com.neocoretechs.bigsack.io.cluster;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import com.neocoretechs.bigsack.io.IOWorker;
import com.neocoretechs.bigsack.io.request.IoRequestInterface;
import com.neocoretechs.bigsack.io.request.cluster.CompletionLatchInterface;
import com.neocoretechs.bigsack.io.request.cluster.IoResponse;
/**
* Once requests from master are queued we extract them here and process them
* This class functions as a generic threaded request processor for entries on a BlockingQueue of
* CompletionLatchInterface implementors managed by a DistributeWorkerResponseInterface implementation.
* This request processor is spun up in conjunction with IO workers such as TCPMaster and UDPMaster.
* The intent is to separate the processing of requests, the maintenance of latches, etc from the communication
* processing. In addition, increased parallelism can be achieved by separation of these tasks.
* The WorkerRequestProcessors are responsible for setting the fields for the ioUnit and countdownlatch.
* Essentially, the transient fields of outbound cluster requests, and the template fields in standalone
* requests are filled in by methods invoked by this processor before 'process' is called on the request.
* @see IoRequestInterface
* Copyright (C) NeoCoreTechs 2014,2015
* @author jg
*
*/
public final class WorkerRequestProcessor implements Runnable {
private static boolean DEBUG = false;
private BlockingQueue<IoRequestInterface> requestQueue;
private DistributedWorkerResponseInterface worker;
private boolean shouldRun = true;
public WorkerRequestProcessor(DistributedWorkerResponseInterface worker) {
this.worker = worker;
requestQueue = ((IOWorker)worker).getRequestQueue();
}
public void stop() {
shouldRun = false;
}
@Override
public void run() {
while(shouldRun) {
IoRequestInterface iori = null;
try {
iori = requestQueue.take();
} catch (InterruptedException e1) {
// Executor has requested shutdown during take
// quit the processing thread
break;
}
// Down here at the worker level we only need to set the countdown latch to 1
// because all operations are taking place on 1 tablespace and thread with coordination
// at the Master level otherwise
CountDownLatch cdl = new CountDownLatch(1);
((CompletionLatchInterface)iori).setCountDownLatch(cdl);
if( DEBUG ) {
System.out.println("port:"+worker.getSlavePort()+" data:"+iori);
}
// tablespace set before request comes down
try {
iori.process();
try {
if( DEBUG )
System.out.println("port:"+worker.getSlavePort()+" avaiting countdown latch...");
cdl.await();
} catch (InterruptedException e) {
// most likely executor shutdown request during latching, be good and bail
// quit the processing thread
break;
}
// we have flipped the latch from the request to the thread waiting here, so send an outbound response
// with the result of our work if a response is required
if( DEBUG ) {
System.out.println("Local processing complete, queuing response to "+worker.getMasterPort());
}
IoResponse ioresp = new IoResponse(iori);
// And finally, send the package back up the line
worker.queueResponse(ioresp);
if( DEBUG ) {
System.out.println("Response queued:"+ioresp);
}
} catch (IOException e1) {
if( DEBUG ) {
System.out.println("***Local processing EXCEPTION "+e1+", queuing fault to "+worker.getMasterPort());
}
((CompletionLatchInterface)iori).setObjectReturn(e1);
IoResponse ioresp = new IoResponse(iori);
// And finally, send the package back up the line
worker.queueResponse(ioresp);
//if( DEBUG ) {
System.out.println("***FAULT Response queued:"+ioresp);
//}
}
} //shouldRun
}
}