package org.voltdb.regressionsuites; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import junit.framework.Test; import org.voltdb.BackendTarget; import org.voltdb.VoltTable; import org.voltdb.client.Client; import org.voltdb.client.ClientResponse; import org.voltdb.client.ProcedureCallback; import edu.brown.benchmark.voter.VoterConstants; import edu.brown.benchmark.voter.VoterProjectBuilder; import edu.brown.benchmark.voter.procedures.Initialize; import edu.brown.benchmark.voter.procedures.Vote; import edu.brown.hstore.Hstoreservice.Status; /** * Test suite for the CommandLogger using the VOTER benchmark * @author pavlo */ public class TestCommandLoggerSuite extends RegressionSuite { private static final String PREFIX = "commandlog"; private static final long PHONE_NUMBER = 8675309; // Jenny private static final long MAX_VOTES_PER_PHONE_NUMBER = 5; /** * Constructor needed for JUnit. Should just pass on parameters to superclass. * @param name The name of the method to test. This is just passed to the superclass. */ public TestCommandLoggerSuite(String name) { super(name); } private void initializeDatabase(Client client) throws Exception { Object params[] = { VoterConstants.NUM_CONTESTANTS, VoterConstants.CONTESTANT_NAMES_CSV }; System.err.println("Initializing database..."); ClientResponse cresponse = client.callProcedure(Initialize.class.getSimpleName(), params); assertNotNull(cresponse); assertEquals(Status.OK, cresponse.getStatus()); } /** * testConcurrentTxns */ public void testConcurrentTxns() throws Exception { Client client = this.getClient(); this.initializeDatabase(client); final int num_txns = 500; final CountDownLatch latch = new CountDownLatch(num_txns); final AtomicInteger numTotal = new AtomicInteger(0); final AtomicInteger numCompleted = new AtomicInteger(0); final AtomicInteger numFailed = new AtomicInteger(0); ProcedureCallback callback = new ProcedureCallback() { @Override public void clientCallback(ClientResponse cr) { switch (cr.getStatus()) { case OK: if (cr.getResults()[0].asScalarLong() == VoterConstants.VOTE_SUCCESSFUL) { numCompleted.incrementAndGet(); } break; default: numFailed.incrementAndGet(); System.err.printf("UNEXPECTED: %s [%d]\n", cr.getStatus(), numFailed.get()); } // SWITCH numTotal.incrementAndGet(); latch.countDown(); } }; for (int i = 0; i < num_txns; i++) { Object params[] = { new Long(i), PHONE_NUMBER + (i % 10), i % VoterConstants.NUM_CONTESTANTS, MAX_VOTES_PER_PHONE_NUMBER }; client.callProcedure(callback, Vote.class.getSimpleName(), params); } // FOR System.err.printf("Invoked %d txns. Waiting for responses...\n", num_txns); boolean result = latch.await(15, TimeUnit.SECONDS); System.err.println("LATCH RESULT: " + result); System.err.println("TOTAL: " + numTotal.get() + " / " + num_txns); System.err.println("COMPLETED: " + numCompleted.get()); System.err.println("FAILED: " + numFailed.get()); if (result == false) { System.err.println("BAD MOJO"); } assertTrue("Timed out [latch="+latch.getCount() + "]", result); assertEquals(0, numFailed.get()); // At this point we know that all of our txns have been committed to disk // Make sure that our vote is actually in the real table and materialized views String query = "SELECT COUNT(*) FROM votes"; ClientResponse cresponse = client.callProcedure("@AdHoc", query); System.err.println(cresponse); assertEquals(Status.OK, cresponse.getStatus()); VoltTable results[] = cresponse.getResults(); assertEquals(1, results.length); assertEquals(numCompleted.get(), results[0].asScalarLong()); // TODO: We should go through the log and make sure that all of our // transactions are still in there... } public static Test suite() { VoltServerConfig config = null; // the suite made here will all be using the tests from this class MultiConfigSuiteBuilder builder = new MultiConfigSuiteBuilder(TestCommandLoggerSuite.class); builder.setGlobalConfParameter("site.commandlog_enable", true); builder.setGlobalConfParameter("site.commandlog_timeout", 1000); builder.setGlobalConfParameter("site.status_enable", true); builder.setGlobalConfParameter("site.status_exec_info", true); VoterProjectBuilder project = new VoterProjectBuilder(); project.addAllDefaults(); boolean success; ///////////////////////////////////////////////////////////// // CONFIG #1: 1 Local Site/Partition running on JNI backend ///////////////////////////////////////////////////////////// // config = new LocalSingleProcessServer(PREFIX + "-1part.jar", 1, BackendTarget.NATIVE_EE_JNI); // success = config.compile(project); // assert(success); // builder.addServerConfig(config); ///////////////////////////////////////////////////////////// // CONFIG #2: 1 Local Site with 2 Partitions running on JNI backend ///////////////////////////////////////////////////////////// config = new LocalSingleProcessServer(PREFIX + "-2part.jar", 2, BackendTarget.NATIVE_EE_JNI); success = config.compile(project); assert(success); builder.addServerConfig(config); //////////////////////////////////////////////////////////// // CONFIG #3: cluster of 2 nodes running 2 site each, one replica //////////////////////////////////////////////////////////// // config = new LocalCluster(PREFIX + "-cluster.jar", 2, 2, 1, BackendTarget.NATIVE_EE_JNI); // success = config.compile(project); // assert(success); // builder.addServerConfig(config); return builder; } }