package org.voltdb.regressionsuites; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import org.junit.Test; import org.voltdb.BackendTarget; import org.voltdb.VoltTable; import org.voltdb.catalog.Column; import org.voltdb.catalog.Database; import org.voltdb.catalog.Table; import org.voltdb.client.Client; import org.voltdb.client.ClientResponse; import org.voltdb.client.ProcCallException; import org.voltdb.compiler.VoltProjectBuilder; import org.voltdb.regressionsuites.LocalCluster; import org.voltdb.regressionsuites.LocalSingleProcessServer; import org.voltdb.regressionsuites.MultiConfigSuiteBuilder; import org.voltdb.regressionsuites.RegressionSuite; import org.voltdb.regressionsuites.VoltServerConfig; import edu.brown.catalog.CatalogUtil; import edu.brown.hstore.Hstoreservice.Status; import edu.brown.optimizer.BasePlanOptimizerTestCase; import edu.brown.utils.StringUtil; /** * Special test cases for checking complex operations in the PlanOptimizer * @author pavlo */ public class TestPlanOptimizerSuite extends RegressionSuite { private static final String PREFIX = "planopt"; @Test public void testSingleAggregate() throws IOException, ProcCallException { int num_partitions = this.getServerConfig().getPartitionCount(); Client client = this.getClient(); final VoltTable vt = this.loadTable(client); Database catalog_db = CatalogUtil.getDatabase(this.getCatalog()); Table catalog_tbl = catalog_db.getTables().get("TABLEC"); assertNotNull(catalog_tbl); Column catalog_col = catalog_tbl.getColumns().get("C_VALUE0"); assertNotNull(catalog_col); // Compute the AVG in Java so that we can compare Map<Integer, List<Integer>> values = new HashMap<Integer, List<Integer>>(); vt.resetRowPosition(); while (vt.advanceRow()) { int c_b_a_id = (int)vt.getLong(2) % num_partitions; if (values.containsKey(c_b_a_id) == false) { values.put(c_b_a_id, new ArrayList<Integer>()); } values.get(c_b_a_id).add((int)vt.getLong(catalog_col.getIndex())); } // WHILE Map<Integer, Double> expectedValues = new HashMap<Integer, Double>(); for (Integer c_b_a_id : values.keySet()) { int total = 0; for (Integer val : values.get(c_b_a_id)) total += val.intValue(); expectedValues.put(c_b_a_id, total / (double)values.get(c_b_a_id).size()); } // FOR System.err.println("EXPECTED AVERAGES (C_VALUE0)\n" + StringUtil.formatMaps(expectedValues)); VoltTable result = null; ClientResponse cr = client.callProcedure("SimpleAggregate"); assertEquals(Status.OK, cr.getStatus()); assertEquals(cr.toString(), 1, cr.getResults().length); result = cr.getResults()[0]; assertNotNull(result); System.err.println(result); while (result.advanceRow()) { Integer c_b_a_id = Integer.valueOf((int)result.getLong(0)); double actual = result.getDouble(1); Double expected = expectedValues.get(c_b_a_id); assertNotNull(c_b_a_id.toString(), expected); assertEquals(c_b_a_id.toString(), expected.doubleValue(), actual, 0.1); } // WHILE } @Test public void testMultipleAggregates() throws IOException, ProcCallException { int num_partitions = this.getServerConfig().getPartitionCount(); Client client = this.getClient(); final VoltTable vt = this.loadTable(client); VoltTable result = null; // Compute the AVG in Java so that we can compare Map<Integer, List<List<Integer>>> values = new HashMap<Integer, List<List<Integer>>>(); vt.resetRowPosition(); int num_cols = vt.getColumnCount(); boolean first = false; while (vt.advanceRow()) { int c_b_a_id = (int)vt.getLong(2) % num_partitions; if (values.containsKey(c_b_a_id) == false) { values.put(c_b_a_id, new ArrayList<List<Integer>>()); first = true; } for (int i = 0; i < num_cols; i++) { if (first) { values.get(c_b_a_id).add(new ArrayList<Integer>()); } values.get(c_b_a_id).get(i).add((int)vt.getLong(i)); } // FOR first = false; } // WHILE Map<Integer, List<Double>> expectedValues = new HashMap<Integer, List<Double>>(); for (Integer c_b_a_id : values.keySet()) { for (List<Integer> vals : values.get(c_b_a_id)) { List<Double> colValues = expectedValues.get(c_b_a_id); if (colValues == null) { colValues = new ArrayList<Double>(); expectedValues.put(c_b_a_id, colValues); } int total = 0; for (Integer val : vals) { total += val.intValue(); } // FOR colValues.add(total / (double)vals.size()); } // FOR } // FOR ClientResponse cr = client.callProcedure("MultiAggregate"); assertEquals(Status.OK, cr.getStatus()); assertEquals(cr.toString(), 1, cr.getResults().length); result = cr.getResults()[0]; assertNotNull(result); System.err.println(result); int query_offsets[] = { 3, 4 }; int expected_offsets[] = { 3, 4 }; while (result.advanceRow()) { Integer c_b_a_id = Integer.valueOf((int)result.getLong(0)); for (int i = 0; i < query_offsets.length; i++) { double actual = result.getDouble(query_offsets[i]); Double expected = expectedValues.get(c_b_a_id).get(expected_offsets[i]); assertNotNull(c_b_a_id.toString(), expected); System.err.printf("[%d] => EXPECTED:%.1f / ACTUAL:%.1f\n", c_b_a_id, expected, actual); assertEquals(c_b_a_id.toString(), expected.doubleValue(), actual, 0.1); } // FOR } // WHILE } protected VoltTable loadTable(Client client) throws IOException, ProcCallException { int num_partitions = this.getServerConfig().getPartitionCount(); int num_tuples = num_partitions * 10; Database catalog_db = CatalogUtil.getDatabase(this.getCatalog()); Table catalog_tbl = catalog_db.getTables().get("TABLEC"); assertNotNull(catalog_tbl); Random rand = new Random(0); VoltTable vt = CatalogUtil.getVoltTable(catalog_tbl); int col_cnt = vt.getColumnCount(); for (int i = 0; i < num_tuples; i++) { Object row[] = new Object[col_cnt]; int col = 0; row[col++] = i; row[col++] = i % 5; row[col++] = i % num_partitions; for ( ; col < col_cnt; col++) { int val = rand.nextInt(100); row[col] = val; } // FOR vt.addRow(row); } // FOR ClientResponse cr = client.callProcedure("@LoadMultipartitionTable", catalog_tbl.getName(), vt); assertEquals(Status.OK, cr.getStatus()); return (vt); } /** * JUnit / RegressionSuite Boilerplate Constructor * @param name The name of this test suite */ public TestPlanOptimizerSuite(String name) { super(name); } static public junit.framework.Test suite() { MultiConfigSuiteBuilder builder = new MultiConfigSuiteBuilder(TestPlanOptimizerSuite.class); VoltProjectBuilder project = new BasePlanOptimizerTestCase.PlanOptimizerTestProjectBuilder(PREFIX); VoltServerConfig config = null; // Single Statement Procedures project.addStmtProcedure("SimpleAggregate", "SELECT C_B_A_ID, AVG(C_VALUE0) " + "FROM TABLEC GROUP BY C_B_A_ID"); project.addStmtProcedure("MultiAggregate", "SELECT C_B_A_ID, SUM(C_VALUE0), SUM(C_VALUE1), " + " AVG(C_VALUE0), AVG(C_VALUE1) " + "FROM TABLEC GROUP BY C_B_A_ID"); // CLUSTER CONFIG #1 // One site with four partitions running in this JVM config = new LocalSingleProcessServer(PREFIX + "-twoPart.jar", 4, BackendTarget.NATIVE_EE_JNI); config.compile(project); builder.addServerConfig(config); // CLUSTER CONFIG #2 // Two sites, each with two partitions running in separate JVMs config = new LocalCluster(PREFIX + "-twoSiteTwoPart.jar", 2, 2, 1, BackendTarget.NATIVE_EE_JNI); config.compile(project); builder.addServerConfig(config); return builder; } }