/* This file is part of VoltDB. * Copyright (C) 2008-2017 VoltDB Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ package org.voltdb; import java.io.IOException; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import junit.framework.TestCase; import org.voltdb.VoltDB.Configuration; import org.voltdb.client.Client; import org.voltdb.client.ClientFactory; import org.voltdb.client.ClientResponse; import org.voltdb.client.NoConnectionsException; import org.voltdb.client.ProcCallException; import org.voltdb.client.ProcedureCallback; import org.voltdb.client.SyncCallback; import org.voltdb.compiler.VoltProjectBuilder; import org.voltdb.regressionsuites.LocalCluster; import org.voltdb.sysprocs.AdHoc_RO_MP; import org.voltdb.sysprocs.GC; import org.voltdb.sysprocs.UpdateApplicationCatalog; import org.voltdb.utils.MiscUtils; import org.voltdb.utils.VoltTableUtil; public class TestNTProcs extends TestCase { public static class TrivialNTProc extends VoltNonTransactionalProcedure { public long run() throws InterruptedException, ExecutionException { assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); //System.out.println("Ran trivial proc!"); return -1; } } public static class TrivialNTProcPriority extends VoltNonTransactionalProcedure { public long run() throws InterruptedException, ExecutionException { assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); assertTrue(Thread.currentThread().getName().contains(NTProcedureService.NTPROC_THREADPOOL_PRIORITY_SUFFIX)); System.out.println("Ran trivial priority proc!"); return -1; } } public static class NestedNTProc extends VoltNonTransactionalProcedure { public long run() throws InterruptedException, ExecutionException { assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); // call a real transactional proc System.out.println("Calling transaction!"); CompletableFuture<ClientResponse> pf = callProcedure("@AdHoc", "select * from blah"); // NB: blocking on a response keeps the thread in the pool wasted. // don't do this in prod ClientResponseImpl cr = (ClientResponseImpl) pf.get(); System.out.println("Got response 1!"); System.out.println(cr.toJSONString()); // call an NT proc (should run on priority exec service) System.out.println("Calling nt proc!"); pf = callProcedure("TestNTProcs$TrivialNTProcPriority"); // NB: blocking on a response keeps the thread in the pool wasted. // don't do this in prod cr = (ClientResponseImpl) pf.get(); System.out.println("Got response 2!"); System.out.println(cr.toJSONString()); return -1; } } public static class AsyncNTProc extends VoltNonTransactionalProcedure { long nextStep(ClientResponse cr) { System.out.printf("AsyncNTProc.nextStep running in thread: %s\n", Thread.currentThread().getName()); System.out.flush(); assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); assertTrue(Thread.currentThread().getName().contains(NTProcedureService.NTPROC_THREADPOOL_PRIORITY_SUFFIX)); System.out.println("Got to nextStep!"); return 0; } public CompletableFuture<Long> run() throws InterruptedException, ExecutionException { assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); System.out.println("Did it!"); CompletableFuture<ClientResponse> pf = callProcedure("@AdHoc", "select * from blah"); return pf.thenApply(this::nextStep); } } public static class RunEverywhereNTProc extends VoltNTSystemProcedure { public long run() throws InterruptedException, ExecutionException { assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); System.out.println("Running on one!"); CompletableFuture<Map<Integer,ClientResponse>> pf = callNTProcedureOnAllHosts("TestNTProcs$TrivialNTProcPriority"); Map<Integer,ClientResponse> cr = pf.get(); cr.entrySet().stream() .forEach(e -> { assertEquals(ClientResponse.SUCCESS, e.getValue().getStatus()); }); System.out.println("Got responses!"); return -1; } } public static class DelayProc extends VoltProcedure { public long run(int millis) throws InterruptedException { // This comment is left here to remind people this is not an NT proc.. //assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); System.out.println("Starting delay proc"); System.out.flush(); Thread.sleep(millis); System.out.println("Done with delay proc"); System.out.flush(); return -1; } } public static class DelayProcNT extends VoltNonTransactionalProcedure { public long run(int millis) throws InterruptedException { assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); System.out.println("Starting delaynt proc"); System.out.flush(); Thread.sleep(millis); System.out.println("Done with delaynt proc"); System.out.flush(); return -1; } } public static class NTProcWithFutures extends VoltNonTransactionalProcedure { public Long secondPart(ClientResponse response) { System.out.printf("NTProcWithFutures.secondPart running in thread: %s\n", Thread.currentThread().getName()); System.out.flush(); assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); assertTrue(Thread.currentThread().getName().contains(NTProcedureService.NTPROC_THREADPOOL_PRIORITY_SUFFIX)); System.out.println("Did it NT2!"); ClientResponseImpl cr = (ClientResponseImpl) response; System.out.println(cr.toJSONString()); return -1L; } public CompletableFuture<Long> run() throws InterruptedException, ExecutionException { assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); System.out.println("Did it NT1!"); return callProcedure("TestNTProcs$DelayProc", 1).thenApply(this::secondPart); } } public static class RunEverywhereNTProcWithDelay extends VoltNTSystemProcedure { public long run() throws InterruptedException, ExecutionException { assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); System.out.println("Running on one!"); // you can't have two of these outstanding so this is expected to fail CompletableFuture<Map<Integer,ClientResponse>> pf1 = callNTProcedureOnAllHosts("TestNTProcs$DelayProc", 100); callNTProcedureOnAllHosts("TestNTProcs$DelayProcNT", 100); Map<Integer,ClientResponse> cr = pf1.get(); cr.entrySet().stream() .forEach(e -> { assertEquals(ClientResponse.SUCCESS, e.getValue().getStatus()); }); System.out.println("Got responses!"); return -1; } } // This class returns CompletableFuture<String> from run(), which is both invalid, and hard to // check statically. Verify we at least get a runtime error. public static class NTProcWithBadTypeFuture extends VoltNonTransactionalProcedure { public String secondPart(ClientResponse response) { System.out.printf("NTProcWithBadTypeFuture.secondPart running in thread: %s\n", Thread.currentThread().getName()); System.out.flush(); assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); assertTrue(Thread.currentThread().getName().contains(NTProcedureService.NTPROC_THREADPOOL_PRIORITY_SUFFIX)); System.out.println("Did it NT2!"); return "This is spinal tap!"; } public CompletableFuture<String> run() throws InterruptedException, ExecutionException { assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); System.out.println("Did it NT1!"); return callProcedure("TestNTProcs$DelayProc", 1).thenApply(this::secondPart); } } public static class NTProcThatSlams extends VoltNonTransactionalProcedure { final static int COLLECT_BLOCK = 0; final static int COLLECT_RETURN = 1; final static int COLLECT_ASYNC = 2; public ClientResponse secondPart(ClientResponse response) { assertTrue(Thread.currentThread().getName().startsWith(NTProcedureService.NTPROC_THREADPOOL_NAMEPREFIX)); assertTrue(Thread.currentThread().getName().contains(NTProcedureService.NTPROC_THREADPOOL_PRIORITY_SUFFIX)); return response; } public CompletableFuture<ClientResponse> run(String whatToCall, byte[] serializedParams, int howToCollect, int timeToSleep) { CompletableFuture<ClientResponse> cf = null; // sleep for specified time try { Thread.sleep(timeToSleep); } catch (InterruptedException e) {} if (whatToCall == null) { cf = new CompletableFuture<ClientResponse>(); cf.complete(new ClientResponseImpl( ClientResponse.SUCCESS, new VoltTable[0], null, 0)); return cf; } // get parameter sets Object[] params = new Object[0]; if ((serializedParams != null) && (serializedParams.length > 0)) { ByteBuffer paramBuf = ByteBuffer.wrap(serializedParams); ParameterSet pset = null; try { pset = ParameterSet.fromByteBuffer(paramBuf); } catch (IOException e) { e.printStackTrace(); fail(); } params = pset.toArray(); } cf = callProcedure(whatToCall, params); switch (howToCollect) { case COLLECT_BLOCK: ClientResponse r = null; try { r = cf.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); fail(); } cf = new CompletableFuture<ClientResponse>(); cf.complete(r); return cf; case COLLECT_RETURN: return cf; case COLLECT_ASYNC: return cf.thenApply(this::secondPart); default: fail(); } fail(); return null; } } // get the first stats table for any selector final VoltTable getStats(Client client, String selector) { ClientResponse response = null; try { response = client.callProcedure("@Statistics", selector); } catch (IOException | ProcCallException e) { fail(); } assertEquals(ClientResponse.SUCCESS, response.getStatus()); return response.getResults()[0]; } // get the first stats table for any selector // Note this needs to be the FULL proc name from class.getName final Map<String, Long> aggregateProcRow(Client client, final String procName) { VoltTable raw = getStats(client, "PROCEDURE"); long[] rawResult = VoltTableUtil.stream(raw) // find matching rows .filter(r -> r.getString("PROCEDURE").equals(procName)) // filter to six columns of interest .map(r -> new long[] { r.getLong("INVOCATIONS"), r.getLong("MAX_RESULT_SIZE"), r.getLong("MAX_PARAMETER_SET_SIZE"), r.getLong("ABORTS"), r.getLong("FAILURES"), r.getLong("TRANSACTIONAL") }) // aggregate (sum, max, max, sum, sum, identity) .reduce(new long[] {0, 0, 0, 0, 0, 0}, (a, b) -> new long[] { a[0] + b[0], Math.max(a[1], b[1]), Math.max(a[2], b[2]), a[3] + b[3], a[4] + b[4], b[5] } ); Map<String, Long> retval = new HashMap<>(); retval.put("INVOCATIONS", rawResult[0]); retval.put("MAX_RESULT_SIZE", rawResult[1]); retval.put("MAX_PARAMETER_SET_SIZE", rawResult[2]); retval.put("ABORTS", rawResult[3]); retval.put("FAILURES", rawResult[4]); retval.put("TRANSACTIONAL", rawResult[5]); return retval; } final String SCHEMA = "create table blah (pkey integer not null, strval varchar(200), PRIMARY KEY(pkey));\n" + "partition table blah on column pkey;\n" + "create procedure from class org.voltdb.TestNTProcs$TrivialNTProc;\n" + "create procedure from class org.voltdb.TestNTProcs$TrivialNTProcPriority;\n" + "create procedure from class org.voltdb.TestNTProcs$NestedNTProc;\n" + "create procedure from class org.voltdb.TestNTProcs$AsyncNTProc;\n" + "create procedure from class org.voltdb.TestNTProcs$RunEverywhereNTProc;\n" + "create procedure from class org.voltdb.TestNTProcs$NTProcWithFutures;\n" + "create procedure from class org.voltdb.TestNTProcs$DelayProc;\n" + "create procedure from class org.voltdb.TestNTProcs$DelayProcNT;\n" + "create procedure from class org.voltdb.TestNTProcs$RunEverywhereNTProcWithDelay;\n" + "create procedure from class org.voltdb.TestNTProcs$NTProcWithBadTypeFuture;\n" + "create procedure from class org.voltdb.TestNTProcs$NTProcThatSlams;\n" + "partition table blah on column pkey;\n"; private void compile() throws Exception { VoltProjectBuilder pb = new VoltProjectBuilder(); pb.addLiteralSchema(SCHEMA); assertTrue(pb.compile(Configuration.getPathToCatalogForTest("compileNT.jar"))); MiscUtils.copyFile(pb.getPathToDeployment(), Configuration.getPathToCatalogForTest("compileNT.xml")); } private ServerThread start() throws Exception { compile(); VoltDB.Configuration config = new VoltDB.Configuration(); config.m_pathToCatalog = Configuration.getPathToCatalogForTest("compileNT.jar"); config.m_pathToDeployment = Configuration.getPathToCatalogForTest("compileNT.xml"); ServerThread localServer = new ServerThread(config); localServer.start(); localServer.waitForInitialization(); return localServer; } public void testNTCompile() throws Exception { compile(); } public void testTrivialNTRoundTrip() throws Exception { ServerThread localServer = start(); Client client = ClientFactory.createClient(); client.createConnection("localhost"); ClientResponseImpl response; response = (ClientResponseImpl) client.callProcedure("TestNTProcs$TrivialNTProc"); assertEquals(ClientResponse.SUCCESS, response.getStatus()); System.out.println("Client got trivial response"); System.out.println(response.toJSONString()); // CHECK STATS VoltTable statsT = getStats(client, "PROCEDURE"); assertTrue(VoltTableUtil.tableContainsString(statsT, "TrivialNTProc", true)); Map<String, Long> stats = aggregateProcRow(client, TrivialNTProc.class.getName()); assertEquals(1, stats.get("INVOCATIONS").longValue()); localServer.shutdown(); localServer.join(); } public void testNestedNTRoundTrip() throws Exception { ServerThread localServer = start(); Client client = ClientFactory.createClient(); client.createConnection("localhost"); ClientResponseImpl response; response = (ClientResponseImpl) client.callProcedure("TestNTProcs$NestedNTProc"); assertEquals(ClientResponse.SUCCESS, response.getStatus()); System.out.println("Client got trivial response"); System.out.println(response.toJSONString()); // CHECK STATS VoltTable statsT = getStats(client, "PROCEDURE"); System.out.println("STATS: " + statsT.toFormattedString()); assertTrue(VoltTableUtil.tableContainsString(statsT, "NestedNTProc", true)); assertTrue(VoltTableUtil.tableContainsString(statsT, "adhoc", false)); Map<String, Long> stats = aggregateProcRow(client, NestedNTProc.class.getName()); assertEquals(1, stats.get("INVOCATIONS").longValue()); stats = aggregateProcRow(client, AdHoc_RO_MP.class.getName()); assertEquals(1, stats.get("INVOCATIONS").longValue()); localServer.shutdown(); localServer.join(); } public void testRunEverywhereNTRoundTripOneNode() throws Exception { ServerThread localServer = start(); Client client = ClientFactory.createClient(); client.createConnection("localhost"); ClientResponseImpl response; response = (ClientResponseImpl) client.callProcedure("TestNTProcs$RunEverywhereNTProc"); assertEquals(ClientResponse.SUCCESS, response.getStatus()); System.out.println("Client got trivial response"); System.out.println(response.toJSONString()); // CHECK STATS VoltTable statsT = getStats(client, "PROCEDURE"); assertTrue(VoltTableUtil.tableContainsString(statsT, "RunEverywhereNTProc", true)); assertTrue(VoltTableUtil.tableContainsString(statsT, "TrivialNTProcPriority", true)); Map<String, Long> stats = aggregateProcRow(client, RunEverywhereNTProc.class.getName()); assertEquals(1, stats.get("INVOCATIONS").longValue()); stats = aggregateProcRow(client, TrivialNTProcPriority.class.getName()); assertEquals(1, stats.get("INVOCATIONS").longValue()); localServer.shutdown(); localServer.join(); } public void testRunEverywhereNTRoundTripCluster() throws Exception { VoltProjectBuilder pb = new VoltProjectBuilder(); pb.addLiteralSchema(SCHEMA); LocalCluster cluster = new LocalCluster("compileNT.jar", 4, 3, 1, BackendTarget.NATIVE_EE_JNI); boolean success = cluster.compile(pb); assertTrue(success); cluster.startUp(); Client client = ClientFactory.createClient(); client.createConnection(cluster.getListenerAddress(0)); ClientResponseImpl response; response = (ClientResponseImpl) client.callProcedure("TestNTProcs$RunEverywhereNTProc"); assertEquals(ClientResponse.SUCCESS, response.getStatus()); System.out.println("Client got trivial response"); System.out.println(response.toJSONString()); // CHECK STATS VoltTable statsT = getStats(client, "PROCEDURE"); assertTrue(VoltTableUtil.tableContainsString(statsT, "RunEverywhereNTProc", true)); assertTrue(VoltTableUtil.tableContainsString(statsT, "TrivialNTProcPriority", true)); Map<String, Long> stats = aggregateProcRow(client, RunEverywhereNTProc.class.getName()); assertEquals(1, stats.get("INVOCATIONS").longValue()); stats = aggregateProcRow(client, TrivialNTProcPriority.class.getName()); assertEquals(3, stats.get("INVOCATIONS").longValue()); client.close(); cluster.shutDown(); } // // This should stress the callbacks, handles and futures for NT procs // public void testOverlappingNT() throws Exception { ServerThread localServer = start(); Client client = ClientFactory.createClient(); client.createConnection("localhost"); final int CALL_COUNT = 400; ClientResponseImpl response; SyncCallback[] cb = new SyncCallback[CALL_COUNT]; for (int i = 0; i < CALL_COUNT; i++) { cb[i] = new SyncCallback(); boolean success = client.callProcedure(cb[i], "TestNTProcs$NTProcWithFutures"); assert(success); } response = (ClientResponseImpl) client.callProcedure("TestNTProcs$NTProcWithFutures"); System.out.println("1: " + response.toJSONString()); for (int i = 0; i < CALL_COUNT; i++) { cb[i].waitForResponse(); response = (ClientResponseImpl) cb[i].getResponse(); System.out.println("2: " + response.toJSONString()); } Thread.sleep(3000); // CHECK STATS VoltTable statsT = getStats(client, "PROCEDURE"); System.out.println("STATS: " + statsT.toFormattedString()); assertTrue(VoltTableUtil.tableContainsString(statsT, "NTProcWithFutures", true)); System.out.println(statsT.toFormattedString()); // repeatedly call stats until they match long start = System.currentTimeMillis(); boolean found = false; while (System.currentTimeMillis() - start < 20000) { Map<String, Long> stats = aggregateProcRow(client, NTProcWithFutures.class.getName()); if ((CALL_COUNT + 1) == stats.get("INVOCATIONS").longValue()) { found = true; break; } Thread.sleep(1000); } localServer.shutdown(); localServer.join(); if (!found) { fail(); } } // // Make sure you can only run one all host NT proc at a time from a single calling proc // (It's ok to run them from multiple calling procs) // public void testRunOnAllHostsSerialness() throws Exception { ServerThread localServer = start(); Client client = ClientFactory.createClient(); client.createConnection("localhost"); ClientResponseImpl response; try { response = (ClientResponseImpl) client.callProcedure("TestNTProcs$RunEverywhereNTProcWithDelay"); } catch (ProcCallException e) { response = (ClientResponseImpl) e.getClientResponse(); } assertEquals(ClientResponse.USER_ABORT, response.getStatus()); assertTrue(response.getStatusString().contains("can be running at a time")); System.out.println("Client got trivial response"); System.out.println(response.toJSONString()); localServer.shutdown(); localServer.join(); } public void testBadFutureType() throws Exception { ServerThread localServer = start(); Client client = ClientFactory.createClient(); client.createConnection("localhost"); ClientResponseImpl response = null; try { response = (ClientResponseImpl) client.callProcedure("TestNTProcs$NTProcWithBadTypeFuture"); } catch (ProcCallException e) { response = (ClientResponseImpl) e.getClientResponse(); } assertEquals(ClientResponse.GRACEFUL_FAILURE, response.getStatus()); assertTrue(response.getStatusString().contains("was not an acceptible VoltDB return type")); System.out.println("Client got failure response"); System.out.println(response.toJSONString()); localServer.shutdown(); localServer.join(); } // @GC is the fist (to be coded) NT sysproc public void testGCSysproc() throws Exception { ServerThread localServer = start(); Client client = ClientFactory.createClient(); client.createConnection("localhost"); ClientResponseImpl response = (ClientResponseImpl) client.callProcedure("@GC"); assertEquals(ClientResponse.SUCCESS, response.getStatus()); System.out.println(response.getResults()[0].toFormattedString()); // CHECK STATS VoltTable statsT = getStats(client, "PROCEDURE"); System.out.println("STATS: " + statsT.toFormattedString()); assertTrue(VoltTableUtil.tableContainsString(statsT, "GC", true)); System.out.println(statsT.toFormattedString()); Map<String, Long> stats = aggregateProcRow(client, GC.class.getName()); assertEquals(1, stats.get("INVOCATIONS").longValue()); localServer.shutdown(); localServer.join(); } public void testUAC() throws Exception { String pathToCatalog = Configuration.getPathToCatalogForTest("adhocddl.jar"); String pathToDeployment = Configuration.getPathToCatalogForTest("adhocddl.xml"); VoltProjectBuilder builder = new VoltProjectBuilder(); builder.addLiteralSchema("--dont care"); builder.setUseDDLSchema(true); boolean success = builder.compile(pathToCatalog, 2, 1, 0); assertTrue("Schema compilation failed", success); MiscUtils.copyFile(builder.getPathToDeployment(), pathToDeployment); VoltDB.Configuration config = new VoltDB.Configuration(); config.m_pathToCatalog = pathToCatalog; config.m_pathToDeployment = pathToDeployment; ServerThread localServer = new ServerThread(config); localServer.start(); localServer.waitForInitialization(); Client client = ClientFactory.createClient(); client.createConnection("localhost"); ClientResponseImpl response = (ClientResponseImpl) client.callProcedure("@AdHoc", "create table blah (pkey integer not null, strval varchar(200), PRIMARY KEY(pkey));"); assertEquals(ClientResponse.SUCCESS, response.getStatus()); // CHECK STATS VoltTable statsT = getStats(client, "PROCEDURE"); System.out.println("STATS: " + statsT.toFormattedString()); assertTrue(VoltTableUtil.tableContainsString(statsT, "UpdateApplicationCatalog", true)); Map<String, Long> stats = aggregateProcRow(client, UpdateApplicationCatalog.class.getName()); assertEquals(1, stats.get("INVOCATIONS").longValue()); localServer.shutdown(); localServer.join(); } /* final static int CALL_NOTHING = 0; final static int CALL_ADHOC = 1; final static int CALL_WRITE_PROC = 2; final static int CALL_TRIVIALNT = 3; final static int CALL_UAC = 4; final static int CALL_STATS = 5; */ public void testSlamNTProcs() throws Exception { ServerThread localServer = start(); final AtomicLong called = new AtomicLong(0); final AtomicLong responded = new AtomicLong(0); Client client = ClientFactory.createClient(); client.createConnection("localhost"); final Client firehoseClient = ClientFactory.createClient(); firehoseClient.createConnection("localhost"); final AtomicBoolean keepFirehosing = new AtomicBoolean(true); final ProcedureCallback firehoseCallback = new ProcedureCallback() { @Override public void clientCallback(ClientResponse clientResponse) throws Exception { responded.incrementAndGet(); if (clientResponse.getStatus() != ClientResponse.SUCCESS) { ClientResponseImpl cri = (ClientResponseImpl) clientResponse; System.err.println(cri.toJSONString()); System.err.flush(); fail(); } } }; Thread firehoseThread = new Thread() { @Override public void run() { while (keepFirehosing.get()) { try { firehoseClient.callProcedure(firehoseCallback, "TestNTProcs$NTProcThatSlams", "TestNTProcs$TrivialNTProc", new byte[0], // params NTProcThatSlams.COLLECT_ASYNC, 1); called.incrementAndGet(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { firehoseClient.drain(); } catch (NoConnectionsException | InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; firehoseThread.start(); long nanoTime1 = System.nanoTime(); Thread.sleep(5000); long nanoTime2 = System.nanoTime(); long nowCalled = called.get(); long nowResponsed = responded.get(); System.out.printf("Ran for %.2f seconds. Called %d procs with %d responded and %d outstanding.\n", (nanoTime2 - nanoTime1) / 1000000000.0, nowCalled, nowResponsed, nowCalled - nowResponsed); keepFirehosing.set(false); firehoseThread.join(); long nanoTime3 = System.nanoTime(); System.out.printf("Drained for %.2f seconds. %d responded.\n", (nanoTime3 - nanoTime2) / 1000000000.0, nowCalled - nowResponsed); // CHECK STATS VoltTable statsT = getStats(client, "PROCEDURE"); System.out.println("STATS: " + statsT.toFormattedString()); assertTrue(VoltTableUtil.tableContainsString(statsT, "NTProcThatSlams", true)); client.close(); firehoseClient.close(); localServer.shutdown(); localServer.join(); } }