Package edu.brown.costmodel

Source Code of edu.brown.costmodel.TestSingleSitedCostModel

package edu.brown.costmodel;

import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.collections15.map.ListOrderedMap;
import org.voltdb.CatalogContext;
import org.voltdb.VoltProcedure;
import org.voltdb.catalog.*;

import edu.brown.BaseTestCase;
import edu.brown.benchmark.tm1.TM1Constants;
import edu.brown.benchmark.tm1.procedures.DeleteCallForwarding;
import edu.brown.benchmark.tm1.procedures.GetAccessData;
import edu.brown.benchmark.tm1.procedures.GetNewDestination;
import edu.brown.benchmark.tm1.procedures.UpdateLocation;
import edu.brown.catalog.CatalogCloner;
import edu.brown.catalog.CatalogUtil;
import edu.brown.catalog.special.MultiColumn;
import edu.brown.catalog.special.MultiProcParameter;
import edu.brown.catalog.special.NullProcParameter;
import edu.brown.costmodel.SingleSitedCostModel.QueryCacheEntry;
import edu.brown.costmodel.SingleSitedCostModel.TransactionCacheEntry;
import edu.brown.hstore.HStoreConstants;
import edu.brown.statistics.Histogram;
import edu.brown.statistics.ObjectHistogram;
import edu.brown.utils.ClassUtil;
import edu.brown.utils.CollectionUtil;
import edu.brown.utils.ProjectType;
import edu.brown.utils.ThreadUtil;
import edu.brown.workload.Workload;
import edu.brown.workload.QueryTrace;
import edu.brown.workload.TransactionTrace;
import edu.brown.workload.filters.ProcedureNameFilter;

public class TestSingleSitedCostModel extends BaseTestCase {

    private static final int PROC_COUNT = 3;
   
    @SuppressWarnings("unchecked")
    private static final Class<? extends VoltProcedure> PROCEDURES[] = new Class[]{
        DeleteCallForwarding.class,
        GetAccessData.class,
        GetNewDestination.class,
    };
    private static final String TARGET_PROCEDURES[] = new String[PROCEDURES.length];
    static {
        for (int i = 0; i < TARGET_PROCEDURES.length; i++) {
            TARGET_PROCEDURES[i] = PROCEDURES[i].getSimpleName();
        } // FOR
    };
    private static final boolean TARGET_PROCEDURES_SINGLEPARTITION_DEFAULT[] = {
        false,  // DeleteCallForwarding
        true,   // GetAccessData
        true,   // GetNewDestination
    };
   
    private static final int NUM_PARTITIONS = 10;
   
    // Reading the workload takes a long time, so we only want to do it once
    private static Workload workload;
   
    @Override
    protected void setUp() throws Exception {
        super.setUp(ProjectType.TM1);
        this.addPartitions(NUM_PARTITIONS);
        ThreadUtil.setMaxGlobalThreads(1);
       
        // Super hack! Walk back the directories and find out workload directory
        if (workload == null) {
            File workload_file = this.getWorkloadFile(ProjectType.TM1);
            workload = new Workload(catalogContext.catalog);
           
            // Workload Filter
            ProcedureNameFilter filter = new ProcedureNameFilter(false);
            long total = 0;
            for (String proc_name : TARGET_PROCEDURES) {
                filter.include(proc_name, PROC_COUNT);
                total += PROC_COUNT;
            }
            ((Workload)workload).load(workload_file, catalogContext.database, filter);
            assertEquals(total, workload.getTransactionCount());
            assertEquals(TARGET_PROCEDURES.length, workload.getProcedureHistogram().getValueCount());
            // System.err.println(workload.getProcedureHistogram());
        }
    }
   
    private TransactionTrace getMultiPartitionTransaction() {
        Procedure catalog_proc = null;
        for (int i = 0; i < TARGET_PROCEDURES.length; i++) {
            if (TARGET_PROCEDURES_SINGLEPARTITION_DEFAULT[i] == false) {
                catalog_proc = this.getProcedure(TARGET_PROCEDURES[i]);
                break;
            }
        } // FOR
        assertNotNull(catalog_proc);
        TransactionTrace multip_txn = null;
        for (TransactionTrace txn_trace : workload) {
            if (txn_trace.getCatalogItem(catalogContext.database).equals(catalog_proc)) {
                multip_txn = txn_trace;
                break;
            }
        } // FOR
        assertNotNull(multip_txn);
        return (multip_txn);
    }
   
    public static Map<Field, Histogram<?>> getHistograms(AbstractCostModel cost_model) throws Exception {
        Map<Field, Histogram<?>> ret = new HashMap<Field, Histogram<?>>();
        Class<?> clazz = cost_model.getClass().getSuperclass();
        for (Field f : clazz.getDeclaredFields()) {
            if (ClassUtil.getInterfaces(f.getType()).contains(Histogram.class)) {
                ret.put(f, (Histogram<?>)f.get(cost_model));
            }
        } // FOR
        assertFalse(ret.isEmpty());
        return (ret);
    }
   
    /**
     * testWeightedTxnEstimation
     */
    public void testWeightedTxnEstimation() throws Exception {
        // Make a new workload that only has multiple copies of the same multi-partition transaction
        Workload new_workload = new Workload(catalogContext.catalog);
        int num_txns = 13;
        TransactionTrace multip_txn = this.getMultiPartitionTransaction();
        Procedure catalog_proc = multip_txn.getCatalogItem(catalogContext.database);
        for (int i = 0; i < num_txns; i++) {
            TransactionTrace clone = (TransactionTrace)multip_txn.clone();
            clone.setTransactionId(i);
            new_workload.addTransaction(catalog_proc, clone);
        } // FOR
        assertEquals(num_txns, new_workload.getTransactionCount());
       
        // We now want to calculate the cost of this new workload
        final SingleSitedCostModel orig_costModel = new SingleSitedCostModel(catalogContext);
        final double orig_cost = orig_costModel.estimateWorkloadCost(catalogContext, new_workload);
        assert(orig_cost > 0);
        // if (orig_costModel.getMultiPartitionProcedureHistogram().isEmpty()) System.err.println(orig_costModel.getTransactionCacheEntry(0).debug());
        assertEquals(num_txns, orig_costModel.getMultiPartitionProcedureHistogram().getSampleCount());
        assertEquals(0, orig_costModel.getSinglePartitionProcedureHistogram().getSampleCount());
       
        // Only the base partition should be touched (2 * num_txns). Everything else should
        // be touched num_txns
        Integer base_partition = CollectionUtil.first(orig_costModel.getQueryPartitionAccessHistogram().getMaxCountValues());
        assertNotNull(base_partition);
        for (Integer p : orig_costModel.getQueryPartitionAccessHistogram().values()) {
            if (p.equals(base_partition)) {
                assertEquals(2 * num_txns, orig_costModel.getQueryPartitionAccessHistogram().get(p).intValue());
            } else {
                assertEquals(num_txns, orig_costModel.getQueryPartitionAccessHistogram().get(p).intValue());
            }
        } // FOR
       
        // Now change make a new workload that has the same multi-partition transaction
        // but this time it only has one but with a transaction weight
        // We should get back the exact same cost
        new_workload = new Workload(catalogContext.catalog);
        TransactionTrace clone = (TransactionTrace)multip_txn.clone();
        clone.setTransactionId(1000);
        clone.setWeight(num_txns);
        new_workload.addTransaction(catalog_proc, clone);
        final SingleSitedCostModel new_costModel = new SingleSitedCostModel(catalogContext);
        final double new_cost = new_costModel.estimateWorkloadCost(catalogContext, new_workload);
        assert(new_cost > 0);
        assertEquals(orig_cost, new_cost, 0.001);
       
        // Now make sure the histograms match up
        Map<Field, Histogram<?>> orig_histograms = getHistograms(orig_costModel);
        assertFalse(orig_histograms.isEmpty());
        Map<Field, Histogram<?>> new_histograms = getHistograms(new_costModel);
        assertFalse(new_histograms.isEmpty());
        for (Field f : orig_histograms.keySet()) {
            Histogram<?> orig_h = orig_histograms.get(f);
            assertNotNull(orig_h);
            Histogram<?> new_h = new_histograms.get(f);
            assert(orig_h != new_h);
            assertNotNull(new_h);
            assertEquals(orig_h, new_h);
        } // FOR
    }
   
    /**
     * testWeightedQueryEstimation
     */
    public void testWeightedQueryEstimation() throws Exception {
        // Make a new workload that has its single queries duplicated multiple times
        Workload new_workload = new Workload(catalogContext.catalog);
        int num_dupes = 7;
        TransactionTrace multip_txn = this.getMultiPartitionTransaction();
        Procedure catalog_proc = multip_txn.getCatalogItem(catalogContext.database);
       
        final TransactionTrace orig_txn = (TransactionTrace)multip_txn.clone();
        List<QueryTrace> clone_queries = new ArrayList<QueryTrace>();
        for (int i = 0; i < num_dupes; i++) {
            for (QueryTrace query_trace : multip_txn.getQueries()) {
                QueryTrace clone_query = (QueryTrace)query_trace.clone();
                clone_queries.add(clone_query);
            } // FOR
        } // FOR
        orig_txn.setQueries(clone_queries);
        new_workload.addTransaction(catalog_proc, orig_txn);
        assertEquals(1, new_workload.getTransactionCount());
        assertEquals(multip_txn.getQueryCount() * num_dupes, orig_txn.getQueryCount());
       
        // We now want to calculate the cost of this new workload
        final SingleSitedCostModel orig_costModel = new SingleSitedCostModel(catalogContext);
        final double orig_cost = orig_costModel.estimateWorkloadCost(catalogContext, new_workload);
        assert(orig_cost > 0);
        TransactionCacheEntry orig_txnEntry = orig_costModel.getTransactionCacheEntry(orig_txn);
        assertNotNull(orig_txnEntry);
        assertEquals(orig_txn.getQueryCount(), orig_txnEntry.getExaminedQueryCount());
//        System.err.println(orig_txnEntry.debug());
//        System.err.println("=========================================");
       
        // Now change make a new workload that has the same multi-partition transaction
        // but this time it only has one but with a transaction weight
        // We should get back the exact same cost
        new_workload = new Workload(catalogContext.catalog);
        final TransactionTrace new_txn = (TransactionTrace)multip_txn.clone();
        clone_queries = new ArrayList<QueryTrace>();
        for (QueryTrace query_trace : multip_txn.getQueries()) {
            QueryTrace clone_query = (QueryTrace)query_trace.clone();
            clone_query.setWeight(num_dupes);
            clone_queries.add(clone_query);
        } // FOR
        new_txn.setQueries(clone_queries);
        new_workload.addTransaction(catalog_proc, new_txn);
        assertEquals(1, new_workload.getTransactionCount());
        assertEquals(multip_txn.getQueryCount(), new_txn.getQueryCount());
        assertEquals(multip_txn.getQueryCount() * num_dupes, new_txn.getWeightedQueryCount());
       
        final SingleSitedCostModel new_costModel = new SingleSitedCostModel(catalogContext);
        final double new_cost = new_costModel.estimateWorkloadCost(catalogContext, new_workload);
        assert(new_cost > 0);
        assertEquals(orig_cost, new_cost, 0.001);
       
       
        // Now make sure the histograms match up
        Map<Field, Histogram<?>> orig_histograms = getHistograms(orig_costModel);
        Map<Field, Histogram<?>> new_histograms = getHistograms(new_costModel);
        for (Field f : orig_histograms.keySet()) {
            Histogram<?> orig_h = orig_histograms.get(f);
            assertNotNull(orig_h);
            Histogram<?> new_h = new_histograms.get(f);
            assert(orig_h != new_h);
            assertNotNull(new_h);
            assertEquals(orig_h, new_h);
        } // FOR
       
        // Compare the TransactionCacheEntries
       
        TransactionCacheEntry new_txnEntry = new_costModel.getTransactionCacheEntry(new_txn);
        assertNotNull(new_txnEntry);
//        System.err.println(new_txnEntry.debug());
       
        assertEquals(orig_txnEntry.getExaminedQueryCount(), new_txnEntry.getExaminedQueryCount());
        assertEquals(orig_txnEntry.getSingleSiteQueryCount(), new_txnEntry.getSingleSiteQueryCount());
        assertEquals(orig_txnEntry.getMultiSiteQueryCount(), new_txnEntry.getMultiSiteQueryCount());
        assertEquals(orig_txnEntry.getUnknownQueryCount(), new_txnEntry.getUnknownQueryCount());
        assertEquals(orig_txnEntry.getTotalQueryCount(), new_txnEntry.getTotalQueryCount());
        assertEquals(orig_txnEntry.getAllTouchedPartitionsHistogram(), new_txnEntry.getAllTouchedPartitionsHistogram());
    }
   
    /**
     * testWeightedTxnInvalidateCache
     */
    public void testWeightedTxnInvalidateCache() throws Throwable {
        // Make a new workload that only has a single weighted copy of our multi-partition transaction
        Workload new_workload = new Workload(catalogContext.catalog);
        int weight = 16;
        TransactionTrace multip_txn = this.getMultiPartitionTransaction();
        Procedure catalog_proc = multip_txn.getCatalogItem(catalogContext.database);
        TransactionTrace clone = (TransactionTrace)multip_txn.clone();
        clone.setTransactionId(1000);
        clone.setWeight(weight);
        new_workload.addTransaction(catalog_proc, clone);
        assertEquals(1, new_workload.getTransactionCount());
       
        SingleSitedCostModel cost_model = new SingleSitedCostModel(catalogContext);
        final double orig_cost = cost_model.estimateWorkloadCost(catalogContext, new_workload);
        assert(orig_cost > 0);
       
        // Only the base partition should be touched (2 * num_txns). Everything else should
        // be touched num_txns
        Integer base_partition = CollectionUtil.first(cost_model.getQueryPartitionAccessHistogram().getMaxCountValues());
        assertNotNull(base_partition);
        for (Integer p : cost_model.getQueryPartitionAccessHistogram().values()) {
            if (p.equals(base_partition)) {
                assertEquals(2 * weight, cost_model.getQueryPartitionAccessHistogram().get(p).intValue());
            } else {
                assertEquals(weight, cost_model.getQueryPartitionAccessHistogram().get(p).intValue());
            }
        } // FOR
       
       
//        System.err.println(cost_model.debugHistograms(catalogContext.database));
//        System.err.println("+++++++++++++++++++++++++++++++++++++++++++++++++");
       
        // Now invalidate the cache for the first query in the procedure
        Statement catalog_stmt = CollectionUtil.first(catalog_proc.getStatements());
        assertNotNull(catalog_stmt);
        Table catalog_tbl = CollectionUtil.first(CatalogUtil.getReferencedTables(catalog_stmt));
        assertNotNull(catalog_tbl);
        try {
            cost_model.invalidateCache(catalog_tbl);
        } catch (Throwable ex) {
            System.err.println(cost_model.debugHistograms(catalogContext));
            throw ex;
        }
        assertEquals(0, cost_model.getMultiPartitionProcedureHistogram().getSampleCount());
        assertEquals(weight, cost_model.getSinglePartitionProcedureHistogram().getSampleCount());
        assertEquals(weight, cost_model.getQueryPartitionAccessHistogram().getSampleCount());
    }
   
    /**
     * testWeightedQueryInvalidateCache
     */
    public void testWeightedQueryInvalidateCache() throws Throwable {
        // Make a new workload that only has a single weighted copy of our multi-partition transaction
        Workload new_workload = new Workload(catalogContext.catalog);
        int weight = 6;
        TransactionTrace multip_txn = this.getMultiPartitionTransaction();
        Procedure catalog_proc = multip_txn.getCatalogItem(catalogContext.database);
        TransactionTrace clone = (TransactionTrace)multip_txn.clone();
        clone.setTransactionId(1000);
        for (QueryTrace qt : clone.getQueries()) {
            qt.setWeight(weight);
        }
        new_workload.addTransaction(catalog_proc, clone);
        assertEquals(1, new_workload.getTransactionCount());
        assertEquals(multip_txn.getQueryCount(), new_workload.getQueryCount());
       
        SingleSitedCostModel cost_model = new SingleSitedCostModel(catalogContext);
        final double orig_cost = cost_model.estimateWorkloadCost(catalogContext, new_workload);
        assert(orig_cost > 0);
        assertEquals(new_workload.getTransactionCount(), cost_model.getMultiPartitionProcedureHistogram().getSampleCount());
        assertEquals(0, cost_model.getSinglePartitionProcedureHistogram().getSampleCount());
       
        // Now invalidate the cache for the first query in the procedure
        Statement catalog_stmt = CollectionUtil.first(catalog_proc.getStatements());
        assertNotNull(catalog_stmt);
        Table catalog_tbl = CollectionUtil.first(CatalogUtil.getReferencedTables(catalog_stmt));
        assertNotNull(catalog_tbl);
        try {
            cost_model.invalidateCache(catalog_tbl);
        } catch (Throwable ex) {
            System.err.println(cost_model.debugHistograms(catalogContext));
            throw ex;
        }
        assertEquals(0, cost_model.getMultiPartitionProcedureHistogram().getSampleCount());
        assertEquals(new_workload.getTransactionCount(), cost_model.getSinglePartitionProcedureHistogram().getSampleCount());
        assertEquals(weight, cost_model.getQueryPartitionAccessHistogram().getSampleCount());
    }
   
    /**
     * testIsAlwaysSinglePartition
     */
    public void testIsAlwaysSinglePartition() throws Exception {
        Map<Procedure, Boolean> expected = new ListOrderedMap<Procedure, Boolean>();
        for (int i = 0; i < TARGET_PROCEDURES.length; i++) {
            expected.put(this.getProcedure(TARGET_PROCEDURES[i]), TARGET_PROCEDURES_SINGLEPARTITION_DEFAULT[i]);
        } // FOR
        expected.put(this.getProcedure(UpdateLocation.class), null);
        assertEquals(TARGET_PROCEDURES.length + 1, expected.size());
       
        // Throw our workload at the costmodel and check that the procedures have the
        // expected result for whether they are single sited or not
        SingleSitedCostModel cost_model = new SingleSitedCostModel(catalogContext);
        cost_model.estimateWorkloadCost(catalogContext, workload);
       
        for (Entry<Procedure, Boolean> e : expected.entrySet()) {
            Boolean sp = cost_model.isAlwaysSinglePartition(e.getKey());
            assertEquals(e.getKey().getName(), e.getValue(), sp);
        } // FOR
    }
   
    /**
     * testHistograms
     */
    public void testHistograms() throws Exception {
        // Grab a txn with a JOIN
        TransactionTrace xact_trace = null;
        for (TransactionTrace xact : workload.getTransactions()) {
            assertNotNull(xact);
            if (xact.getCatalogItemName().equals(TARGET_PROCEDURES[2])) {
                xact_trace = xact;
                break;
            }
        } // FOR
        assertNotNull(xact_trace);

        // Change the catalog so that the data from the tables are in different partitions
        Database clone_db = CatalogCloner.cloneDatabase(catalogContext.database);
        assertNotNull(clone_db);
        CatalogContext clone_catalogContext = new CatalogContext(clone_db.getCatalog());
        Table catalog_tbl = clone_db.getTables().get(TM1Constants.TABLENAME_CALL_FORWARDING);
        assertNotNull(catalog_tbl);
        Column catalog_col = catalog_tbl.getColumns().get("START_TIME");
        assertNotNull(catalog_col);
        catalog_tbl.setPartitioncolumn(catalog_col);
       
        // Throw the TransactionTrace at the costmodel and make sure that there is a TransactionCacheEntry
        SingleSitedCostModel cost_model = new SingleSitedCostModel(clone_catalogContext);
        cost_model.estimateTransactionCost(clone_catalogContext, xact_trace);
        cost_model.setCachingEnabled(true);
        TransactionCacheEntry entry = cost_model.getTransactionCacheEntry(xact_trace);
        assertNotNull(entry);
//        System.err.println(entry.toString());

        // --------------------------
        // Query Counters
        // --------------------------
        assertEquals(xact_trace.getQueries().size(), entry.getTotalQueryCount());
        assertEquals(xact_trace.getQueries().size(), entry.getExaminedQueryCount());
        assertEquals(0, entry.getSingleSiteQueryCount());
        assertEquals(1, entry.getMultiSiteQueryCount());
       
        // ---------------------------------------------
        // Partitions Touched by Txns
        // This should be all partitions because the query is trying to do a
        // range look-up on the partitioning column
        // ---------------------------------------------
        Histogram<Integer> txn_h = cost_model.getTxnPartitionAccessHistogram();
        assertNotNull(txn_h);
//        System.err.println(xact_trace.debug(catalogContext.database));
//        System.err.println("Transaction Partitions:\n" + txn_h);
        assertEquals(NUM_PARTITIONS, txn_h.getSampleCount());
        assertEquals(NUM_PARTITIONS, txn_h.getValueCount());

        // ---------------------------------------------
        // Partitions Touched By Queries
        // ---------------------------------------------
        Histogram<Integer> query_h = cost_model.getQueryPartitionAccessHistogram();
        assertNotNull(query_h);
//        System.err.println("Query Partitions:\n" + query_h);
        assertEquals(NUM_PARTITIONS, query_h.getSampleCount());
        assertEquals(NUM_PARTITIONS, query_h.getValueCount());
       
        // ---------------------------------------------
        // Partitions Executing Java Control Code
        // ---------------------------------------------
        Histogram<Integer> java_h = cost_model.getJavaExecutionHistogram();
        assertNotNull(java_h);
//        System.err.println("Java Execution:\n" + java_h);
        assertEquals(1, java_h.getSampleCount());
        assertEquals(1, java_h.getValueCount());

        // ---------------------------------------------
        // Single-Partition Procedures
        // ---------------------------------------------
        Histogram<String> sproc_h = cost_model.getSinglePartitionProcedureHistogram();
        assertNotNull(sproc_h);
//        System.err.println("SinglePartition:\n" + sproc_h);
        assertEquals(0, sproc_h.getSampleCount());
        assertEquals(0, sproc_h.getValueCount());

        // ---------------------------------------------
        // Multi-Partition Procedures
        // ---------------------------------------------
        Histogram<String> mproc_h = cost_model.getMultiPartitionProcedureHistogram();
        assertNotNull(mproc_h);
//        System.err.println("MultiPartition:\n" + mproc_h);
        assertEquals(1, mproc_h.getSampleCount());
        assertEquals(1, mproc_h.getValueCount());

        // Now throw the same txn back at the costmodel. All of our histograms should come back the same
        cost_model.estimateTransactionCost(catalogContext, xact_trace);

        Histogram<Integer> new_txn_h = cost_model.getTxnPartitionAccessHistogram();
        assertNotNull(new_txn_h);
        assertEquals(txn_h, new_txn_h);

        Histogram<Integer> new_query_h = cost_model.getQueryPartitionAccessHistogram();
        assertNotNull(new_query_h);
        assertEquals(query_h, new_query_h);
       
        Histogram<Integer> new_java_h = cost_model.getJavaExecutionHistogram();
        assertNotNull(new_java_h);
        assertEquals(java_h, new_java_h);
       
        Histogram<String> new_sproc_h = cost_model.getSinglePartitionProcedureHistogram();
        assertNotNull(new_sproc_h);
        assertEquals(sproc_h, new_sproc_h);

        Histogram<String> new_mproc_h = cost_model.getMultiPartitionProcedureHistogram();
        assertNotNull(new_mproc_h);
        assertEquals(mproc_h, new_mproc_h);

    }
   
    /**
     * testEstimateCost
     */
    public void testEstimateCost() throws Exception {
        TransactionTrace xact_trace = null;
        for (TransactionTrace xact : workload.getTransactions()) {
            assertNotNull(xact);
            if (xact.getCatalogItemName().equals(TARGET_PROCEDURES[0])) {
                xact_trace = xact;
                break;
            }
        } // FOR
        assertNotNull(xact_trace);
       
        // System.err.println(xact_trace.debug(catalogContext.database));
        SingleSitedCostModel cost_model = new SingleSitedCostModel(catalogContext);
        cost_model.estimateTransactionCost(catalogContext, xact_trace);
        TransactionCacheEntry entry = cost_model.getTransactionCacheEntry(xact_trace);
        assertNotNull(entry);
       
        assertEquals(xact_trace.getQueries().size(), entry.getTotalQueryCount());
        assertEquals(xact_trace.getQueries().size(), entry.getExaminedQueryCount());
        assertEquals(1, entry.getSingleSiteQueryCount());
        assertEquals(1, entry.getMultiSiteQueryCount());
       
        // Check Partition Access Histogram
        Histogram<Integer> hist_access = cost_model.getQueryPartitionAccessHistogram();
        assertNotNull(hist_access);
        assertEquals(NUM_PARTITIONS, hist_access.getValueCount());
        Integer multiaccess_partition = null;
        for (Object o : hist_access.values()) {
            Integer partition = (Integer)o;
            assertNotNull(partition);
            long count = hist_access.get(partition);
            assert(count > 0);
            if (count > 1) multiaccess_partition = partition;
        } // FOR
        assertNotNull(multiaccess_partition);
       
        // Check Java Execution Histogram
        // 2011-03-23
        // This always going to be empty because of how we store null ProcParameters...
        Histogram<Integer> hist_execute = cost_model.getJavaExecutionHistogram();
        assertNotNull(hist_execute);
        // System.err.println("HISTOGRAM:\n" + hist_execute);
        // assertEquals(0, hist_execute.getValueCount());
    }
   
    /**
     * testEstimateCostInvalidateCache
     */
    public void testEstimateCostInvalidateCache() throws Exception {
        SingleSitedCostModel cost_model = new SingleSitedCostModel(catalogContext);
       
        List<TransactionTrace> xacts = new ArrayList<TransactionTrace>();
        for (TransactionTrace xact_trace : workload.getTransactions()) {
            assertNotNull(xact_trace);
            if (xact_trace.getCatalogItemName().equals(TARGET_PROCEDURES[0])) {
                cost_model.estimateTransactionCost(catalogContext, xact_trace);
                xacts.add(xact_trace);
            }
        } // FOR
       
        // Now invalidate the cache for the SUBSCRIBER and CALL_FORWARDING table
        // This will cause the Txn entry to be thrown out completely because all the
        // queries have been invalidated
        cost_model.invalidateCache(this.getTable(TM1Constants.TABLENAME_SUBSCRIBER));
        cost_model.invalidateCache(this.getTable(TM1Constants.TABLENAME_CALL_FORWARDING));
       
        TransactionTrace xact_trace = xacts.get(0);
        assertNotNull(xact_trace);
        TransactionCacheEntry entry = cost_model.getTransactionCacheEntry(xact_trace);
        assertNull(entry);
       
        // Make sure that we updated the Execution Histogram
        Histogram<Integer> hist = cost_model.getJavaExecutionHistogram();
        assert(hist.isEmpty());
       
        // And make sure that we updated the Partition Access Histogram
        hist = cost_model.getQueryPartitionAccessHistogram();
        assert(hist.isEmpty());
    }
   
    /**
     * testEstimateCostInvalidateCachePartial
     */
    public void testEstimateCostInvalidateCachePartial() throws Exception {
        // DeleteCallForwarding has two queries, one that touches SUBSCRIBER and one that
        // touches CALL_FORWARDING. So we're going to invalidate SUBSCRIBER and check to make
        // sure that the our cache still has information for the second query but not the first.
        SingleSitedCostModel cost_model = new SingleSitedCostModel(catalogContext);
        Procedure catalog_proc = this.getProcedure(DeleteCallForwarding.class);
        Statement valid_stmt = catalog_proc.getStatements().get("update");
        assertNotNull(valid_stmt);
        Statement invalid_stmt = catalog_proc.getStatements().get("query");
        assertNotNull(invalid_stmt);
       
        List<TransactionTrace> xacts = new ArrayList<TransactionTrace>();
        for (TransactionTrace xact_trace : workload.getTransactions()) {
            assertNotNull(xact_trace);
            if (xact_trace.getCatalogItemName().equals(catalog_proc.getName())) {
                cost_model.estimateTransactionCost(catalogContext, xact_trace);
                xacts.add(xact_trace);
            }
        } // FOR
        assertFalse(xacts.isEmpty());

        // Invalidate that mofo!
        cost_model.invalidateCache(this.getTable(TM1Constants.TABLENAME_SUBSCRIBER));
       
        Histogram<Integer> expected_touched = new ObjectHistogram<Integer>();
        for (TransactionTrace txn_trace : xacts) {
            TransactionCacheEntry txn_entry = cost_model.getTransactionCacheEntry(txn_trace);
            assertNotNull(txn_entry);
//            expected_touched.put(txn_entry.getExecutionPartition());
           
            for (QueryCacheEntry query_entry : cost_model.getQueryCacheEntries(txn_trace)) {
                QueryTrace query_trace = txn_trace.getQueries().get(query_entry.getQueryIdx());
                assertNotNull(query_trace);
                assertNotNull(query_trace.getCatalogItemName());
                Boolean should_be_invalid = (query_trace.getCatalogItemName().equals(invalid_stmt.getName()) ? true :
                                            (query_trace.getCatalogItemName().equals(valid_stmt.getName()) ? false : null));
                assertNotNull(should_be_invalid);
                assertEquals(should_be_invalid.booleanValue(), query_entry.isInvalid());
               
                if (should_be_invalid) {
                    assert(query_entry.getAllPartitions().isEmpty());
                } else {
                    assertFalse(query_entry.getAllPartitions().isEmpty());
                    expected_touched.put(query_entry.getAllPartitions());
                }
            } // FOR
           
            assertEquals(catalog_proc.getStatements().size(), txn_entry.getTotalQueryCount());
            assert(txn_entry.isSinglePartitioned());
            assertFalse(txn_entry.isComplete());
            assertEquals(1, txn_entry.getExaminedQueryCount());
            assertEquals(0, txn_entry.getMultiSiteQueryCount());
            assertEquals(1, txn_entry.getSingleSiteQueryCount());
        } // FOR
       
        // Grab the histograms about what partitions got touched and make sure that they are updated properly
        Histogram<Integer> txn_partitions = cost_model.getTxnPartitionAccessHistogram();
        Histogram<Integer> query_partitions = cost_model.getQueryPartitionAccessHistogram();

        // The txn touched partitions histogram should now only contain the entries from
        // the single-sited query (plus the java execution) and not all of the partitions
        // from the broadcast query
        assertEquals(expected_touched.getValueCount(), txn_partitions.getValueCount());
        assertEquals(xacts.size(), query_partitions.getSampleCount());
    }
   
    /**
     * testProcParameterEstimate
     */
    public void testProcParameterEstimate() throws Exception {
        // So here we want to throw a txn at the cost model first without a partitioning ProcParameter
        // and then with one. We should see that the TransactionCacheEntry gets updated properly
        // and that the txn becomes multi-sited
        Database clone_db = CatalogCloner.cloneDatabase(catalogContext.database);
        assertNotNull(clone_db);
        CatalogContext clone_catalogContext = new CatalogContext(clone_db.getCatalog());
       
        Procedure catalog_proc = this.getProcedure(clone_db, GetAccessData.class);
        TransactionTrace target_txn = null;
        for (TransactionTrace txn : workload.getTransactions()) {
            if (txn.getCatalogItemName().equals(catalog_proc.getName())) {
                target_txn = txn;
                break;
            }
        } // FOR
        assertNotNull(target_txn);
        TransactionCacheEntry entry = null;
        int orig_partition_parameter = catalog_proc.getPartitionparameter();
       
        // Ok, now let's disable the ProcParameter
        SingleSitedCostModel cost_model = new SingleSitedCostModel(clone_catalogContext);
        catalog_proc.setPartitionparameter(NullProcParameter.PARAM_IDX);
        cost_model.setCachingEnabled(true);
        cost_model.estimateTransactionCost(clone_catalogContext, target_txn);
        entry = cost_model.getTransactionCacheEntry(target_txn);
        assertNotNull(entry);
        assertEquals(HStoreConstants.NULL_PARTITION_ID, entry.getExecutionPartition());
        assert(entry.isSinglePartitioned());
       
        // Make something else the ProcParameter
        cost_model.invalidateCache(catalog_proc);
        catalog_proc.setPartitionparameter(orig_partition_parameter + 1);
        cost_model.getPartitionEstimator().initCatalog(clone_catalogContext);
        cost_model.estimateTransactionCost(clone_catalogContext, target_txn);
        entry = cost_model.getTransactionCacheEntry(target_txn);
        assertNotNull(entry);
        assert(entry.getExecutionPartition() != HStoreConstants.NULL_PARTITION_ID);
        // assertFalse(entry.isSingleSited());
       
        // Now let's put S_ID back in as the ProcParameter
        cost_model.invalidateCache(catalog_proc);
        catalog_proc.setPartitionparameter(orig_partition_parameter);
        cost_model.getPartitionEstimator().initCatalog(clone_catalogContext);
        cost_model.estimateTransactionCost(clone_catalogContext, target_txn);
        entry = cost_model.getTransactionCacheEntry(target_txn);
        assertNotNull(entry);
        assert(entry.getExecutionPartition() != HStoreConstants.NULL_PARTITION_ID);
        if (!entry.isSinglePartitioned()) System.err.println(entry.debug());
        assert(entry.isSinglePartitioned());
    }
   
    /**
     * testMultiColumnPartitioning
     */
    public void testMultiColumnPartitioning() throws Exception {
        Database clone_db = CatalogCloner.cloneDatabase(catalogContext.database);
        CatalogContext clone_catalogContext = new CatalogContext(clone_db.getCatalog());
        Procedure catalog_proc = this.getProcedure(clone_db, GetAccessData.class);
        TransactionTrace target_txn = null;
        for (TransactionTrace txn : workload.getTransactions()) {
            if (txn.getCatalogItemName().equals(catalog_proc.getName())) {
                target_txn = txn;
                break;
            }
        } // FOR
        assertNotNull(target_txn);
        System.err.println(target_txn.debug(catalogContext.database));
       
        // Now change partitioning
        MultiProcParameter catalog_param = MultiProcParameter.get(catalog_proc.getParameters().get(0), catalog_proc.getParameters().get(1));
        assertNotNull(catalog_param);
        catalog_proc.setPartitionparameter(catalog_param.getIndex());
       
        Table catalog_tbl = this.getTable(clone_db, TM1Constants.TABLENAME_ACCESS_INFO);
        Column columns[] = {
            this.getColumn(clone_db, catalog_tbl, "S_ID"),
            this.getColumn(clone_db, catalog_tbl, "AI_TYPE"),
        };
        MultiColumn catalog_col = MultiColumn.get(columns);
        assertNotNull(catalog_col);
        catalog_tbl.setPartitioncolumn(catalog_col);
//        System.err.println(catalog_tbl + ": " + catalog_col);

        SingleSitedCostModel cost_model = new SingleSitedCostModel(clone_catalogContext);
        cost_model.setCachingEnabled(true);
        cost_model.estimateTransactionCost(clone_catalogContext, target_txn);
        TransactionCacheEntry txn_entry = cost_model.getTransactionCacheEntry(target_txn);
        assertNotNull(txn_entry);
        assertNotNull(txn_entry.getExecutionPartition());
        assert(txn_entry.isSinglePartitioned());
//        System.err.println(txn_entry.debug());
    }
}
TOP

Related Classes of edu.brown.costmodel.TestSingleSitedCostModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.