/** * */ package org.voltdb.benchmark; import java.io.IOException; import java.net.UnknownHostException; import java.util.concurrent.Semaphore; import org.apache.log4j.Logger; import org.voltdb.StoredProcedureInvocationHints; import org.voltdb.VoltTable; import org.voltdb.client.Client; import org.voltdb.client.ClientResponse; import org.voltdb.client.ClientStatusListener; import org.voltdb.client.NoConnectionsException; import org.voltdb.client.ProcCallException; import org.voltdb.client.ProcedureCallback; import edu.brown.logging.LoggerUtil; import edu.brown.logging.LoggerUtil.LoggerBoolean; import edu.brown.profilers.ProfileMeasurement; /** * @author pavlo * */ public class BlockingClient extends Semaphore implements Client { static final Logger LOG = Logger.getLogger(BlockingClient.class); private static final LoggerBoolean debug = new LoggerBoolean(); private static final LoggerBoolean trace = new LoggerBoolean(); static { LoggerUtil.attachObserver(LOG, debug, trace); } private static final long serialVersionUID = 1L; private final Client inner; private final ProfileMeasurement idle = new ProfileMeasurement("CLIENT_IDLE"); static { LoggerUtil.setupLogging(); } private class BlockingCallback implements ProcedureCallback { private final ProcedureCallback inner_callback; private final String proc_name; public BlockingCallback(String proc_name, ProcedureCallback inner_callback) { assert(inner_callback != null); this.inner_callback = inner_callback; this.proc_name = proc_name; if (debug.val) LOG.debug("Created a new BlockingCallback around " + inner_callback.getClass().getSimpleName() + " for '" + proc_name + "'"); try { if (debug.val) LOG.debug("Trying to acquire procedure invocation lock: " + BlockingClient.this.availablePermits()); idle.start(); BlockingClient.this.acquire(); idle.stop(); if (debug.val) LOG.debug("We got it! Let's get it on! [proc_name=" + this.proc_name + "]"); } catch (InterruptedException ex) { LOG.fatal("Got interrupted while waiting for lock", ex); System.exit(1); } } @Override public void clientCallback(ClientResponse clientResponse) { if (debug.val) LOG.debug("BlockingCallback is forwarding the client callback for to inner callback [" + "txn=" + clientResponse.getTransactionId() + ", " + "proc=" + this.proc_name + "]"); BlockingClient.this.release(); this.inner_callback.clientCallback(clientResponse); } } /** * */ public BlockingClient(Client inner, int max_concurrent) { super(max_concurrent); this.inner = inner; if (LOG.isDebugEnabled()) LOG.debug("Created new BlockingClient [max_concurrent=" + max_concurrent + "]"); } public Client getClient() { return (this.inner); } /* (non-Javadoc) * @see org.voltdb.client.Client#addClientStatusListener(org.voltdb.client.ClientStatusListener) */ @Override public void addClientStatusListener(ClientStatusListener listener) { this.inner.addClientStatusListener(listener); } /* (non-Javadoc) * @see org.voltdb.client.Client#backpressureBarrier() */ @Override public void backpressureBarrier() throws InterruptedException { this.inner.backpressureBarrier(); } /* (non-Javadoc) * @see org.voltdb.client.Client#blocking() */ @Override public boolean blocking() { return this.inner.blocking(); } /* (non-Javadoc) * @see org.voltdb.client.Client#calculateInvocationSerializedSize(java.lang.String, java.lang.Object[]) */ @Override public int calculateInvocationSerializedSize(String procName, Object... parameters) { return this.inner.calculateInvocationSerializedSize(procName, parameters); } /* (non-Javadoc) * @see org.voltdb.client.Client#callProcedure(java.lang.String, java.lang.Object[]) */ @Override public ClientResponse callProcedure(String procName, Object... parameters) throws IOException, NoConnectionsException, ProcCallException { return this.inner.callProcedure(procName, null, parameters); } @Override public ClientResponse callProcedure(String procName, StoredProcedureInvocationHints hints, Object... parameters) throws IOException, NoConnectionsException, ProcCallException { return this.inner.callProcedure(procName, hints, parameters); } /* (non-Javadoc) * @see org.voltdb.client.Client#callProcedure(org.voltdb.client.ProcedureCallback, java.lang.String, java.lang.Object[]) */ @Override public boolean callProcedure(ProcedureCallback callback, String procName, Object... parameters) throws IOException, NoConnectionsException { return this.inner.callProcedure(new BlockingCallback(procName, callback), procName, null, parameters); } @Override public boolean callProcedure(ProcedureCallback callback, String procName, StoredProcedureInvocationHints hints, Object... parameters) throws IOException, NoConnectionsException { return this.inner.callProcedure(new BlockingCallback(procName, callback), procName, hints, parameters); } /* (non-Javadoc) * @see org.voltdb.client.Client#callProcedure(org.voltdb.client.ProcedureCallback, int, java.lang.String, java.lang.Object[]) */ @Override public boolean callProcedure(ProcedureCallback callback, int expectedSerializedSize, String procName, StoredProcedureInvocationHints hints, Object... parameters) throws IOException, NoConnectionsException { return this.inner.callProcedure(callback, expectedSerializedSize, procName, hints, parameters); } /* (non-Javadoc) * @see org.voltdb.client.Client#close() */ @Override public void close() throws InterruptedException { this.inner.close(); //if (LOG.isDebugEnabled()) LOG.info("Client Idle Time: " + this.idle.debug()); } /* (non-Javadoc) * @see org.voltdb.client.Client#configureBlocking(boolean) */ @Override public void configureBlocking(boolean blocking) { this.inner.configureBlocking(blocking); } @Override public void createConnection(String host, int port) throws UnknownHostException, IOException { this.inner.createConnection(host, port); } /* (non-Javadoc) * @see org.voltdb.client.Client#createConnection(java.lang.String, java.lang.String, java.lang.String) */ @Override public void createConnection(Integer siteId, String host, int port, String username, String password) throws UnknownHostException, IOException { this.inner.createConnection(siteId, host, port, username, password); } /* (non-Javadoc) * @see org.voltdb.client.Client#drain() */ @Override public void drain() throws NoConnectionsException, InterruptedException { this.inner.drain(); } /* (non-Javadoc) * @see org.voltdb.client.Client#getBuildString() */ @Override public String getBuildString() { return this.inner.getBuildString(); } /* (non-Javadoc) * @see org.voltdb.client.Client#getIOStats() */ @Override public VoltTable getIOStats() { return this.inner.getIOStats(); } /* (non-Javadoc) * @see org.voltdb.client.Client#getIOStatsInterval() */ @Override public VoltTable getIOStatsInterval() { return this.inner.getIOStatsInterval(); } /* (non-Javadoc) * @see org.voltdb.client.Client#getInstanceId() */ @Override public Object[] getInstanceId() { return this.inner.getInstanceId(); } /* (non-Javadoc) * @see org.voltdb.client.Client#getProcedureStats() */ @Override public VoltTable getProcedureStats() { return this.inner.getProcedureStats(); } /* (non-Javadoc) * @see org.voltdb.client.Client#getProcedureStatsInterval() */ @Override public VoltTable getProcedureStatsInterval() { return this.inner.getProcedureStatsInterval(); } /* (non-Javadoc) * @see org.voltdb.client.Client#removeClientStatusListener(org.voltdb.client.ClientStatusListener) */ @Override public boolean removeClientStatusListener(ClientStatusListener listener) { return this.inner.removeClientStatusListener(listener); } @Override public ProfileMeasurement getQueueTime() { return this.inner.getQueueTime(); } }