gt:         Procedure dtxnProc = dtxn.getProcedure();
context: 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.SP3_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.SP3_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.SP3_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.SP3_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.SP3_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.SP3_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.SP1_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.SP1_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)
  