package edu.brown.utils; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.voltdb.CatalogContext; import org.voltdb.catalog.CatalogMap; import org.voltdb.catalog.Column; import org.voltdb.catalog.Database; import org.voltdb.catalog.PlanFragment; import org.voltdb.catalog.ProcParameter; import org.voltdb.catalog.Procedure; import org.voltdb.catalog.Statement; import org.voltdb.catalog.Table; import edu.brown.BaseTestCase; import edu.brown.benchmark.tm1.TM1Constants; import edu.brown.benchmark.tm1.procedures.GetAccessData; import edu.brown.benchmark.tm1.procedures.GetNewDestination; import edu.brown.benchmark.tm1.procedures.UpdateSubscriberData; import edu.brown.catalog.CatalogCloner; import edu.brown.catalog.special.MultiColumn; import edu.brown.catalog.special.MultiProcParameter; import edu.brown.hashing.AbstractHasher; import edu.brown.hashing.DefaultHasher; import edu.brown.hstore.HStoreConstants; import edu.brown.workload.QueryTrace; import edu.brown.workload.TransactionTrace; /** * * @author pavlo * */ public class TestPartitionEstimatorMultiSite extends BaseTestCase { protected static AbstractHasher hasher; protected static final int num_partitions = 10; protected static final int base_partition = 1; private final PartitionSet partitions = new PartitionSet(); @Override protected void setUp() throws Exception { super.setUp(ProjectType.TM1); if (hasher == null) { this.addPartitions(num_partitions); hasher = new DefaultHasher(catalogContext); } } /** * testGetPartitionsTransactionTrace */ public void testGetPartitionsTransactionTrace() throws Exception { Procedure catalog_proc = this.getProcedure(GetNewDestination.class); Object txn_params[] = new Object[] { 1l, 4l, 0l, 5l }; Statement catalog_stmt = this.getStatement(catalog_proc, "GetData"); Object query_params[] = new Object[] { 1l, 1l, 4l, 0l, 5l }; TransactionTrace txn_trace = new TransactionTrace(1001l, catalog_proc, txn_params); QueryTrace query_trace = new QueryTrace(catalog_stmt, query_params, 0); txn_trace.addQuery(query_trace); txn_trace.stop(); p_estimator.getAllPartitions(partitions, txn_trace); assertNotNull(partitions); assertEquals(partitions.toString(), 1, partitions.size()); } /** * testGetPartitionsProcedure */ public void testGetPartitionsProcedure() throws Exception { Procedure catalog_proc = this.getProcedure(UpdateSubscriberData.class); Object params[] = new Object[] { new Long(1000), // S_ID 0l, // BIT_1 0l, // DATA_A 0l, // SF_TYPE }; assert(p_estimator.getBasePartition(catalog_proc, params) != HStoreConstants.NULL_PARTITION_ID); } /** * testGetPartitionsStatement */ public void testGetPartitionsStatement() throws Exception { Procedure catalog_proc = this.getProcedure("InsertCallForwarding"); assertNotNull(catalog_proc); Statement catalog_stmt = catalog_proc.getStatements().get("query1"); assertNotNull(catalog_stmt); Object params[] = new Object[] { new String("Doesn't Matter") }; p_estimator.getAllPartitions(partitions, catalog_stmt, params, base_partition); // System.out.println(catalog_stmt.getName() + " Partitions: " + partitions); assertEquals(num_partitions, partitions.size()); } /** * testGetPartitionsPlanFragment */ public void testGetPartitionsPlanFragment() throws Exception { Procedure catalog_proc = this.getProcedure(GetNewDestination.class); Statement catalog_stmt = catalog_proc.getStatements().get("GetData"); assertNotNull(catalog_stmt); // System.out.println("Num Partitions: " + CatalogUtil.getNumberOfPartitions(catalog_db)); Object params[] = new Object[] { new Long(54), // S_ID new Long(3), // SF_TYPE new Long(0), // START_TIME new Long(22), // END_TIME }; // We should see one PlanFragment with no partitions and then all others need something boolean internal_flag = false; for (PlanFragment catalog_frag : catalog_stmt.getMs_fragments()) { partitions.clear(); p_estimator.getPartitions(partitions, catalog_frag, params, base_partition); if (partitions.isEmpty()) { assertFalse(internal_flag); internal_flag = true; } } // FOR assertTrue(internal_flag); } /** * testGetAllFragmentPartitions */ public void testGetAllFragmentPartitions() throws Exception { Procedure catalog_proc = this.getProcedure(GetNewDestination.class); Statement catalog_stmt = catalog_proc.getStatements().get("GetData"); assertNotNull(catalog_stmt); // System.out.println("Num Partitions: " + CatalogUtil.getNumberOfPartitions(catalog_db)); Object params[] = new Object[] { new Long(54), // S_ID new Long(3), // SF_TYPE new Long(0), // START_TIME new Long(22), // END_TIME }; Map<PlanFragment, PartitionSet> all_partitions = new HashMap<PlanFragment, PartitionSet>(); CatalogMap<PlanFragment> fragments = catalog_stmt.getMs_fragments(); p_estimator.getAllFragmentPartitions(all_partitions, fragments.values(), params, base_partition); // We should see one PlanFragment with that only has our local partition and then all others need something boolean internal_flag = false; for (PlanFragment catalog_frag : fragments) { Collection<Integer> partitions = all_partitions.get(catalog_frag); assertNotNull(catalog_frag.fullName(), partitions); if (partitions.size() == 1 && partitions.contains(base_partition)) { assertFalse(internal_flag); internal_flag = true; } } // FOR assertTrue(internal_flag); } /** * testMultiColumnPartitioning */ public void testMultiColumnPartitioning() throws Exception { Database clone_db = CatalogCloner.cloneDatabase(catalogContext.database); CatalogContext clone_catalogContext = new CatalogContext(clone_db.getCatalog()); PartitionEstimator p_estimator = new PartitionEstimator(clone_catalogContext); Procedure catalog_proc = this.getProcedure(clone_db, GetNewDestination.class); ProcParameter catalog_params[] = new ProcParameter[] { this.getProcParameter(clone_db, catalog_proc, 0), // S_ID this.getProcParameter(clone_db, catalog_proc, 1), // SF_TYPE }; MultiProcParameter mpp = MultiProcParameter.get(catalog_params); assertNotNull(mpp); assert(mpp.getIndex() >= 0); catalog_proc.setPartitionparameter(mpp.getIndex()); // First Test: Only partition one of the tables and make sure that // the MultiColumns don't map to the same partition Table catalog_tbl = this.getTable(clone_db, TM1Constants.TABLENAME_SPECIAL_FACILITY); Column catalog_cols[] = new Column[] { this.getColumn(clone_db, catalog_tbl, "S_ID"), this.getColumn(clone_db, catalog_tbl, "SF_TYPE"), }; MultiColumn mc = MultiColumn.get(catalog_cols); assertNotNull(mc); catalog_tbl.setPartitioncolumn(mc); p_estimator.initCatalog(clone_catalogContext); Statement catalog_stmt = this.getStatement(clone_db, catalog_proc, "GetData"); Long params[] = new Long[] { new Long(1111), // S_ID new Long(1111), // S_ID new Long(2222), // SF_TYPE new Long(3333), // START_TIME new Long(4444), // END_TIME }; Map<String, PartitionSet> partitions = p_estimator.getTablePartitions(catalog_stmt, params, base_partition); assertNotNull(partitions); assertFalse(partitions.isEmpty()); PartitionSet touched = new PartitionSet(); for (String table_key : partitions.keySet()) { assertFalse(table_key, partitions.get(table_key).isEmpty()); touched.addAll(partitions.get(table_key)); } // FOR assertEquals(2, touched.size()); // Second Test: Now make the other table multi-column partitioned and make // sure that the query goes to just one partition catalog_tbl = this.getTable(clone_db, TM1Constants.TABLENAME_CALL_FORWARDING); catalog_cols = new Column[] { this.getColumn(clone_db, catalog_tbl, "S_ID"), this.getColumn(clone_db, catalog_tbl, "SF_TYPE"), }; mc = MultiColumn.get(catalog_cols); assertNotNull(mc); catalog_tbl.setPartitioncolumn(mc); p_estimator.initCatalog(clone_catalogContext); partitions = p_estimator.getTablePartitions(catalog_stmt, params, base_partition); assertNotNull(partitions); assertFalse(partitions.isEmpty()); touched.clear(); for (String table_key : partitions.keySet()) { assertFalse(table_key, partitions.get(table_key).isEmpty()); touched.addAll(partitions.get(table_key)); } // FOR assertEquals(1, touched.size()); } /** * testMultiColumnPartitioningIncomplete */ public void testMultiColumnPartitioningIncomplete() throws Exception { Database clone_db = CatalogCloner.cloneDatabase(catalogContext.database); CatalogContext clone_catalogContext = new CatalogContext(clone_db.getCatalog()); PartitionEstimator p_estimator = new PartitionEstimator(clone_catalogContext); Procedure catalog_proc = this.getProcedure(clone_db, GetAccessData.class); ProcParameter catalog_params[] = new ProcParameter[] { this.getProcParameter(clone_db, catalog_proc, 0), // S_ID this.getProcParameter(clone_db, catalog_proc, 1), // AI_TYPE }; MultiProcParameter mpp = MultiProcParameter.get(catalog_params); assertNotNull(mpp); assert(mpp.getIndex() >= 0); catalog_proc.setPartitionparameter(mpp.getIndex()); p_estimator.initCatalog(clone_catalogContext); Table catalog_tbl = this.getTable(clone_db, TM1Constants.TABLENAME_ACCESS_INFO); Column catalog_cols[] = new Column[] { this.getColumn(clone_db, catalog_tbl, "S_ID"), this.getColumn(clone_db, catalog_tbl, "DATA1"), }; MultiColumn mc = MultiColumn.get(catalog_cols); assertNotNull(mc); catalog_tbl.setPartitioncolumn(mc); p_estimator.initCatalog(clone_catalogContext); Statement catalog_stmt = this.getStatement(clone_db, catalog_proc, "GetData"); Long params[] = new Long[] { new Long(1111), // S_ID new Long(2222), // AI_TYPE }; Map<String, PartitionSet> partitions = p_estimator.getTablePartitions(catalog_stmt, params, base_partition); assertNotNull(partitions); assertFalse(partitions.isEmpty()); // System.err.println("partition = " + partitions); PartitionSet touched = new PartitionSet(); for (String table_key : partitions.keySet()) { assertFalse(table_key, partitions.get(table_key).isEmpty()); touched.addAll(partitions.get(table_key)); } // FOR assertEquals(num_partitions, touched.size()); } }