Package edu.brown.hstore

Source Code of edu.brown.hstore.TestSpecExecScheduler

package edu.brown.hstore;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.voltdb.TransactionIdManager;
import org.voltdb.catalog.ConflictSet;
import org.voltdb.catalog.Procedure;
import org.voltdb.catalog.Table;
import org.voltdb.types.SpecExecSchedulerPolicyType;
import org.voltdb.types.SpeculationType;
import org.voltdb.utils.EstTimeUpdater;

import edu.brown.BaseTestCase;
import edu.brown.benchmark.tm1.procedures.UpdateLocation;
import edu.brown.catalog.conflicts.ConflictSetUtil;
import edu.brown.hstore.conf.HStoreConf;
import edu.brown.hstore.estimators.EstimatorState;
import edu.brown.hstore.estimators.MockEstimate;
import edu.brown.hstore.specexec.checkers.AbstractConflictChecker;
import edu.brown.hstore.specexec.checkers.TableConflictChecker;
import edu.brown.hstore.txns.AbstractTransaction;
import edu.brown.hstore.txns.LocalTransaction;
import edu.brown.profilers.SpecExecProfiler;
import edu.brown.utils.CollectionUtil;
import edu.brown.utils.ProjectType;

/**
* SpecExecScheduler Test Cases
* @author pavlo
*/
public class TestSpecExecScheduler extends BaseTestCase {
   
    private static final int NUM_PARTITIONS = 5;
    private static final int BASE_PARTITION = 1;
    private static final int WINDOW_SIZE = 5;
   
    private MockHStoreSite hstore_site;
    private TransactionIdManager idManager;
    private TransactionQueueManager queueManager;
    private PartitionLockQueue work_queue;
    private SpecExecScheduler scheduler;
    private SpecExecScheduler.Debug schedulerDebug;
    private AbstractConflictChecker checker;
    private LocalTransaction dtxn;
    private AbstractTransaction.Debug dtxnDebug;
    private List<LocalTransaction> addedTxns = new ArrayList<LocalTransaction>();
   
    @Override
    protected void setUp() throws Exception {
        super.setUp(ProjectType.TM1);
        this.initializeCatalog(2, 2, NUM_PARTITIONS);
        // if (isFirstSetup()) System.err.println(CatalogInfo.getInfo(catalog, null));
       
        HStoreConf hstore_conf = HStoreConf.singleton();
        hstore_conf.site.specexec_profiling = true;
        hstore_conf.site.specexec_profiling_sample = 1.0;
       
        this.checker = new TableConflictChecker(catalogContext);
        this.hstore_site = new MockHStoreSite(0, catalogContext, HStoreConf.singleton());
        this.idManager = hstore_site.getTransactionIdManager(0);
        this.queueManager = this.hstore_site.getTransactionQueueManager();
        this.work_queue = this.queueManager.getLockQueue(BASE_PARTITION);
        this.scheduler = new SpecExecScheduler(this.checker,
                                               BASE_PARTITION,
                                               this.work_queue,
                                               SpecExecSchedulerPolicyType.FIRST,
                                               WINDOW_SIZE);
        this.schedulerDebug = this.scheduler.getDebugContext();
       
        // Create our current distributed transaction
        Procedure catalog_proc = this.getProcedure(UpdateLocation.class);
        this.dtxn = new LocalTransaction(this.hstore_site);
        this.dtxn.testInit(this.idManager.getNextUniqueTransactionId(),
                           BASE_PARTITION,
                           null,
                           catalogContext.getAllPartitionIds(),
                           catalog_proc);
        assertFalse(this.dtxn.isPredictAllLocal());
        this.dtxnDebug = this.dtxn.getDebugContext();
    }
   
    // --------------------------------------------------------------------------------------------
    // UTILITY METHODS
    // --------------------------------------------------------------------------------------------
   
    private LocalTransaction populateQueue(Collection<LocalTransaction> txns, int size) throws Exception {
        Collection<Procedure> conflicts = ConflictSetUtil.getAllConflicts(dtxn.getProcedure());
        List<Procedure> procList = new ArrayList<Procedure>();
        for (Procedure p : catalogContext.getRegularProcedures()) {
            if (conflicts.contains(p) == false) {
                procList.add(p);
                if (procList.size() >= size)
                    break;
            }
        } // FOR
        assertFalse(procList.isEmpty());
       
        LocalTransaction ts = null, tsWithoutEstimatorState = null;
        for (Procedure proc: procList) {
            ts = new LocalTransaction(this.hstore_site);
            ts.testInit(this.idManager.getNextUniqueTransactionId(),
                        BASE_PARTITION,
                        null,
                        catalogContext.getPartitionSetSingleton(BASE_PARTITION),
                        proc);
            if (tsWithoutEstimatorState == null)
                tsWithoutEstimatorState = ts;
            assertTrue(ts.isPredictSinglePartition());
            this.addToQueue(ts);
            txns.add(ts);
        } // FOR
        EstTimeUpdater.update(System.currentTimeMillis());
        return (tsWithoutEstimatorState);
    }
   
    private LocalTransaction addToQueue(LocalTransaction ts) {
        this.work_queue.offer(ts, false);
        return (ts);
    }
   
    // --------------------------------------------------------------------------------------------
    // TEST CASES
    // --------------------------------------------------------------------------------------------

    /**
     * testFirstMatchPolicy
     */
    public void testFirstMatchPolicy() throws Exception {
        // We should be able to get one match with only one evaluation
        SpecExecProfiler profiler = this.schedulerDebug.getProfiler(SpeculationType.SP2_REMOTE_BEFORE);
        assertNotNull(profiler);
        assertTrue(profiler.num_comparisons.isEmpty());
       
        this.populateQueue(this.addedTxns, 10);
        this.scheduler.setPolicyType(SpecExecSchedulerPolicyType.FIRST);
        LocalTransaction next = this.scheduler.next(this.dtxn, SpeculationType.SP2_REMOTE_BEFORE);
        assertNotNull(next);
        assertEquals(CollectionUtil.first(this.addedTxns), next);
        assertEquals(1, profiler.num_comparisons.get(1));
    }
   
    /**
     * testLastMatchPolicy
     */
    public void testLastMatchPolicy() throws Exception {
        // We should be able to get one match with only one evaluation
        SpecExecProfiler profiler = this.schedulerDebug.getProfiler(SpeculationType.SP2_REMOTE_BEFORE);
        assertNotNull(profiler);
        assertTrue(profiler.num_comparisons.isEmpty());
        this.scheduler.setPolicyType(SpecExecSchedulerPolicyType.LAST);
        this.scheduler.setWindowSize(Integer.MAX_VALUE);
       
        this.populateQueue(this.addedTxns, 10);
        LocalTransaction next = this.scheduler.next(this.dtxn, SpeculationType.SP2_REMOTE_BEFORE);
        assertNotNull(next);
        assertEquals(CollectionUtil.last(this.addedTxns), next);
        assertEquals(this.addedTxns.size(), profiler.num_comparisons.getMaxValue().intValue());
    }
 
    /**
     * testShortestPolicy
     */
    public void testShortestPolicy() throws Exception {
        // We should only evaluate the same # of txns as the WINDOW_SIZE
        SpecExecProfiler profiler = this.schedulerDebug.getProfiler(SpeculationType.SP2_REMOTE_BEFORE);
        assertNotNull(profiler);
        assertTrue(profiler.num_comparisons.isEmpty());
       
        // Add a bunch and then set the last one to have the shortest time
        this.populateQueue(this.addedTxns, 20);
        AbstractTransaction shortest = CollectionUtil.last(this.work_queue);
        for (AbstractTransaction ts : this.work_queue) {
            final long remaining = (ts == shortest ? 10 : 1000);
            EstimatorState state = new EstimatorState(catalogContext) {
                {
                    MockEstimate est = new MockEstimate(remaining);
                    this.addEstimate(est);
                }
            };
            ts.setEstimatorState(state);
        } // FOR
       
        int windowSize = this.work_queue.size();
        this.scheduler.setPolicyType(SpecExecSchedulerPolicyType.SHORTEST);
        this.scheduler.setWindowSize(windowSize);
        LocalTransaction next = this.scheduler.next(this.dtxn, SpeculationType.SP2_REMOTE_BEFORE);
        assertNotNull(next);
        assertEquals(shortest, next);
        // System.err.println(profiler.num_comparisons.toString());
        assertEquals(1, profiler.num_comparisons.get(windowSize));
    }
   
    /**
     * testLongestPolicy
     */
    public void testLongestPolicy() throws Exception {
        LocalTransaction tsWithoutEstimatorState = this.populateQueue(this.addedTxns, 3);
        LocalTransaction next = this.scheduler.next(this.dtxn, SpeculationType.IDLE);
        // System.err.println(this.dtxn.debug());
        assertNotNull(next);
        assertEquals(tsWithoutEstimatorState, next);
        assertFalse(this.work_queue.toString(), this.work_queue.contains(next));
  }
   
    /**
     * testNonConflicting
     */
    public void testNonConflicting() throws Exception {
        // Make a single-partition txn for a procedure that has no conflicts with
        // our dtxn and add it to our queue. It should always be returned
        // and marked as speculative by the scheduler
        Collection<Procedure> conflicts = ConflictSetUtil.getAllConflicts(dtxn.getProcedure());
        Procedure proc = null;
        for (Procedure p : catalogContext.getRegularProcedures()) {
            if (conflicts.contains(p) == false) {
                proc = p;
                break;
            }
        } // FOR
        assertNotNull(proc);
       
        LocalTransaction ts = new LocalTransaction(this.hstore_site);
        ts.testInit(this.idManager.getNextUniqueTransactionId(), BASE_PARTITION, null, catalogContext.getPartitionSetSingleton(BASE_PARTITION), proc);
        assertTrue(ts.isPredictSinglePartition());
        this.addToQueue(ts);
       
        LocalTransaction next = this.scheduler.next(this.dtxn, SpeculationType.IDLE);
        //System.err.println(this.dtxn.debug());
        assertNotNull(next);
        assertEquals(ts, next);
        assertFalse(this.work_queue.contains(next));
    }
   
    /**
     * testWriteWriteConflicting
     */
    public void testWriteWriteConflicting() throws Exception {
        // Make a single-partition txn for a procedure that has a write-write conflict with
        // our dtxn and add it to our queue. It should only be allowed to be returned by next()
        // if the current dtxn has not written to that table yet (but reads are allowed)
        Procedure dtxnProc = dtxn.getProcedure();
        Procedure proc = null;
        for (Procedure p : catalogContext.getRegularProcedures()) {
            Collection<Procedure> c = ConflictSetUtil.getWriteWriteConflicts(p);
            if (c.contains(dtxnProc)) {
                proc = p;
                break;
            }
        } // FOR
        assertNotNull(proc);
       
        ConflictSet cs = proc.getConflicts().get(dtxnProc.getName());
        assertNotNull(cs);
        Collection<Table> conflictTables = ConflictSetUtil.getAllTables(cs.getWritewriteconflicts());
        assertFalse(conflictTables.isEmpty());
       
        // First time we should be able to get through
        LocalTransaction ts = new LocalTransaction(this.hstore_site);
        ts.testInit(this.idManager.getNextUniqueTransactionId(), BASE_PARTITION, null, catalogContext.getPartitionSetSingleton(BASE_PARTITION), proc);
        assertTrue(ts.isPredictSinglePartition());
        this.addToQueue(ts);
        LocalTransaction next = this.scheduler.next(this.dtxn, SpeculationType.SP2_REMOTE_AFTER);
        assertNotNull(next);
        assertEquals(ts, next);
        assertFalse(this.work_queue.contains(next));
        ts.finish();
       
        // Now have the dtxn "write" to one of the tables in our ConflictSet
        dtxnDebug.clearReadWriteSets();
        dtxn.markTableWritten(BASE_PARTITION, CollectionUtil.first(conflictTables));
        ts.testInit(this.idManager.getNextUniqueTransactionId(), BASE_PARTITION, null, catalogContext.getPartitionSetSingleton(BASE_PARTITION), proc);
        assertTrue(ts.isPredictSinglePartition());
        this.addToQueue(ts);
       
        next = this.scheduler.next(this.dtxn, SpeculationType.SP2_REMOTE_AFTER);
        assertNull(next);
        ts.finish();
       
        // Reads aren't allowed either
        dtxnDebug.clearReadWriteSets();
        dtxn.markTableRead(BASE_PARTITION, CollectionUtil.first(conflictTables));
        ts.testInit(this.idManager.getNextUniqueTransactionId(), BASE_PARTITION, null, catalogContext.getPartitionSetSingleton(BASE_PARTITION), proc);
        assertTrue(ts.isPredictSinglePartition());
        this.addToQueue(ts);
       
        next = this.scheduler.next(this.dtxn, SpeculationType.SP2_REMOTE_AFTER);
        assertNull(next);
        ts.finish();
    }
   
    /**
     * testReadWriteConflicting
     */
    public void testReadWriteConflicting() throws Exception {
        // Make a single-partition txn for a procedure that has a read-write conflict with
        // our dtxn and add it to our queue. We will first test it without updating the
        // dtxn's read/write table set, which means that our single-partition txn should be
        // returned by next(). We will then mark the conflict table as written by the dtxn,
        // which means that the single-partition txn should *not* be returned
        Procedure dtxnProc = dtxn.getProcedure();
        Procedure proc = null;
        for (Procedure p : catalogContext.getRegularProcedures()) {
            Collection<Procedure> c = ConflictSetUtil.getReadWriteConflicts(p);
            if (c.contains(dtxnProc)) {
                proc = p;
                break;
            }
        } // FOR
        assertNotNull(proc);
       
        ConflictSet cs = proc.getConflicts().get(dtxnProc.getName());
        assertNotNull(cs);
        Collection<Table> conflictTables = ConflictSetUtil.getAllTables(cs.getReadwriteconflicts());
        assertFalse(conflictTables.isEmpty());
       
        LocalTransaction ts = new LocalTransaction(this.hstore_site);
        ts.testInit(this.idManager.getNextUniqueTransactionId(), BASE_PARTITION, null, catalogContext.getPartitionSetSingleton(BASE_PARTITION), proc);
        assertTrue(ts.isPredictSinglePartition());
        this.addToQueue(ts);
       
        LocalTransaction next = this.scheduler.next(this.dtxn, SpeculationType.SP2_REMOTE_BEFORE);
        assertNotNull(next);
        assertEquals(ts, next);
        assertFalse(this.work_queue.contains(next));
        ts.finish();
       
        // Reads are allowed!
        dtxnDebug.clearReadWriteSets();
        dtxn.markTableRead(BASE_PARTITION, CollectionUtil.first(conflictTables));
        ts.testInit(this.idManager.getNextUniqueTransactionId(), BASE_PARTITION, null, catalogContext.getPartitionSetSingleton(BASE_PARTITION), proc);
        assertTrue(ts.isPredictSinglePartition());
        this.addToQueue(ts);
        next = this.scheduler.next(this.dtxn, SpeculationType.SP2_REMOTE_AFTER);
        assertNotNull(next);
        assertEquals(ts, next);
        assertFalse(this.work_queue.contains(next));
        ts.finish();
       
        // But writes are not!
        dtxnDebug.clearReadWriteSets();
        dtxn.markTableWritten(BASE_PARTITION, CollectionUtil.first(conflictTables));
        ts.testInit(this.idManager.getNextUniqueTransactionId(), BASE_PARTITION, null, catalogContext.getPartitionSetSingleton(BASE_PARTITION), proc);
        assertTrue(ts.isPredictSinglePartition());
        this.addToQueue(ts);
        next = this.scheduler.next(this.dtxn, SpeculationType.SP2_REMOTE_AFTER);
        assertNull(next);
    }

}
TOP

Related Classes of edu.brown.hstore.TestSpecExecScheduler

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.