package com.neocoretechs.bigsack.io.cluster; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.util.concurrent.CountDownLatch; import com.neocoretechs.bigsack.io.IOWorker; import com.neocoretechs.bigsack.io.ThreadPoolManager; import com.neocoretechs.bigsack.io.pooled.GlobalDBIO; import com.neocoretechs.bigsack.io.request.IoResponseInterface; import com.neocoretechs.bigsack.io.request.cluster.AbstractClusterWork; import com.neocoretechs.bigsack.io.request.cluster.CompletionLatchInterface; import com.neocoretechs.bigsack.io.request.cluster.IoResponse; /** * This class functions as the remote IOWorker * Multiple threads on each node, one for each database, an Fopen spawns * additional instances of these so it acts as its own master in a sense. * Presumably, there is an instance of this present on each of the 8 * tablespace worker nodes. * When a block comes down it gets written, if a block comes up it gets read. * the request comes down as a serialized object. * Instances of these are started by the WorkBoot controller node * @author jg * */ public class UDPWorker extends IOWorker implements DistributedWorkerResponseInterface, NodeBlockBufferInterface { private static final boolean DEBUG = true; boolean shouldRun = true; public int MASTERPORT = 9876; public int SLAVEPORT = 9876; public static String remoteMaster = "AMIMASTER"; private byte[] receiveData = new byte[10000]; private byte[] sendData; private InetAddress IPAddress = null; DatagramSocket responseSocket = null; private WorkerRequestProcessor workerRequestProcessor; private NodeBlockBuffer blockBuffer; public UDPWorker(String dbname, int tablespace, String masterport, String slaveport, int L3Cache) throws IOException { super(dbname, tablespace, L3Cache); MASTERPORT= Integer.valueOf(masterport); SLAVEPORT = Integer.valueOf(slaveport); try { if(UDPMaster.TEST) { IPAddress = InetAddress.getLocalHost(); } else { IPAddress = InetAddress.getByName(remoteMaster); } } catch (UnknownHostException e) { throw new RuntimeException("Bad remote master address:"+remoteMaster); } try { responseSocket = new DatagramSocket(); responseSocket.connect(IPAddress, MASTERPORT); } catch (SocketException e) { System.out.println("Exception setting up socket "+IPAddress+" to remote master port "+MASTERPORT+" on local port "+SLAVEPORT+" "+e); responseSocket = null; return; } // spin the request processor thread for the worker ThreadPoolManager.getInstance().spin(workerRequestProcessor = new WorkerRequestProcessor(this)); blockBuffer = new NodeBlockBuffer(this); if( DEBUG ) { System.out.println("Worker on port "+SLAVEPORT+" with master "+MASTERPORT+" database:"+dbname+ " tablespace "+tablespace+" address:"+IPAddress); } } public NodeBlockBuffer getBlockBuffer() { return blockBuffer; } /** * Queue a request on this worker, the request is assumed to be on this tablespace * Instead of queuing to a running thread request queue, queue this for outbound message * The type is IOResponseInterface and contains the Id and the payload * back to master * @param irf */ public synchronized void queueResponse(IoResponseInterface irf) { if( DEBUG ) { System.out.println("UDPWorker Adding response "+irf+" to outbound from worker to "+IPAddress+" port:"+MASTERPORT); } // set up send try { sendData = GlobalDBIO.getObjectAsBytes(irf); } catch (IOException e) { System.out.println("UDPWorker queueResponse "+irf+" cant get serialized form due to "+e); if( responseSocket != null ) responseSocket.close(); responseSocket = null; } DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, MASTERPORT); try { responseSocket.send(sendPacket); } catch (IOException e) { if( DEBUG ) System.out.println("Socket send error "+e+" to address "+IPAddress+" on port "+MASTERPORT); if( responseSocket != null ) responseSocket.close(); responseSocket = null; } } /** * Spin the worker, get the tablespace from the cmdl param * @param args * @throws Exception */ public static void main(String args[]) throws Exception { if( args.length < 4 ) { System.out.println("Usage: java com.neocoretechs.bigsack.io.cluster.UDPWorker [database] [tablespace] [master port] [slave port]"); } // Use mmap mode 0 ThreadPoolManager.getInstance().spin(new UDPWorker(args[0], Integer.valueOf(args[1]), args[2], args[3], 0)); } @Override public void run() { DatagramSocket serverSocket = null; try { serverSocket = new DatagramSocket(SLAVEPORT); } catch (SocketException e) { System.out.println("UDPWorker Cannot construct DatagramSocket to worker port "+SLAVEPORT); return; } DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); while(shouldRun) { try { serverSocket.receive(receivePacket); byte[] databytes = receivePacket.getData(); if( DEBUG ) { System.out.println("UDPWorker FROM REMOTE on port:"+SLAVEPORT+" size:"+databytes.length); } // extract the serialized request final CompletionLatchInterface iori = (CompletionLatchInterface) GlobalDBIO.deserializeObject(databytes); iori.setIoInterface(this); // put the received request on the processing stack getRequestQueue().put(iori); } catch(IOException ioe) { // most likely a broken pipe due to master break System.out.println("UDPWorker receive exception "+ioe+" on port "+SLAVEPORT); if( serverSocket != null ) serverSocket.close(); if( responseSocket != null ) responseSocket.close(); responseSocket = null; break; } catch (InterruptedException e) { // Executor shutdown while waiting for request queue to obtain a free slot if( serverSocket != null ) serverSocket.close(); if( responseSocket != null ) responseSocket.close(); responseSocket = null; break; } } // shut down buffer, write outstanding blocks workerRequestProcessor.stop(); } @Override public String getMasterPort() { return String.valueOf(MASTERPORT); } @Override public String getSlavePort() { return String.valueOf(SLAVEPORT); } }