package edu.brown.hstore.estimators.fixed; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.log4j.Logger; import org.voltdb.catalog.Procedure; import org.voltdb.catalog.Statement; import edu.brown.catalog.special.CountedStatement; import edu.brown.hstore.estimators.EstimatorState; import edu.brown.logging.LoggerUtil; import edu.brown.logging.LoggerUtil.LoggerBoolean; import edu.brown.utils.PartitionEstimator; import edu.brown.utils.PartitionSet; /** * TPC-C Benchmark Fixed Estimator * @author pavlo */ public class FixedTPCCEstimator extends AbstractFixedEstimator { private static final Logger LOG = Logger.getLogger(FixedTPCCEstimator.class); private static final LoggerBoolean debug = new LoggerBoolean(); private static final LoggerBoolean trace = new LoggerBoolean(); static { LoggerUtil.attachObserver(LOG, debug, trace); } /** * W_ID Short -> PartitionId */ private int[] neworder_hack_hashes; /** * NewOrder Prefetchable Query Information */ private final Statement[] neworder_prefetchables; private final List<CountedStatement[]> neworder_countedstmts = new ArrayList<CountedStatement[]>(); /** * Constructor * @param hstore_site */ public FixedTPCCEstimator(PartitionEstimator p_estimator) { super(p_estimator); // Prefetchable Statements if (hstore_conf.site.exec_prefetch_queries) { Procedure catalog_proc = catalogContext.procedures.getIgnoreCase("neworder"); String prefetchables[] = { "getStockInfo" }; this.neworder_prefetchables = new Statement[prefetchables.length]; for (int i = 0; i < this.neworder_prefetchables.length; i++) { Statement catalog_stmt = catalog_proc.getStatements().getIgnoreCase(prefetchables[i]); assert(catalog_stmt != null) : String.format("Invalid prefetchable Statement %s.%s", catalog_proc.getName(), prefetchables[i]); this.neworder_prefetchables[i] = catalog_stmt; } // FOR } else { this.neworder_prefetchables = null; } for (int i = 0; i < 20; i++) { this.neworder_countedstmts.add(null); } // FOR } private int getPartition(short w_id) { if (this.neworder_hack_hashes == null || this.neworder_hack_hashes.length <= w_id) { synchronized (this) { if (this.neworder_hack_hashes == null || this.neworder_hack_hashes.length <= w_id) { int temp[] = new int[w_id+1]; for (int i = 0; i < temp.length; i++) { temp[i] = this.hasher.hash(i); } // FOR this.neworder_hack_hashes = temp; } } // SYNCH } return (this.neworder_hack_hashes[w_id]); } @SuppressWarnings("unchecked") @Override public <T extends EstimatorState> T startTransactionImpl(Long txn_id, int base_partition, Procedure catalog_proc, Object[] args) { String procName = catalog_proc.getName(); FixedEstimatorState ret = new FixedEstimatorState(this.catalogContext, txn_id, base_partition); PartitionSet partitions = null; PartitionSet readonly = null; if (procName.equalsIgnoreCase("neworder")) { partitions = this.newOrder(ret, args); readonly = EMPTY_PARTITION_SET; } else if (procName.startsWith("payment")) { int hash_w_id = this.getPartition((Short)args[0]); int hash_c_w_id = this.getPartition((Short)args[3]); if (hash_w_id == hash_c_w_id) { partitions = this.catalogContext.getPartitionSetSingleton(hash_w_id); } else { partitions = new PartitionSet(); partitions.add(hash_w_id); partitions.add(hash_c_w_id); } readonly = EMPTY_PARTITION_SET; } else if (procName.equalsIgnoreCase("delivery")) { partitions = this.catalogContext.getPartitionSetSingleton(base_partition); readonly = EMPTY_PARTITION_SET; } else { partitions = readonly = this.catalogContext.getPartitionSetSingleton(base_partition); } assert(partitions != null); assert(readonly != null); ret.createInitialEstimate(partitions, readonly, EMPTY_PARTITION_SET); return ((T)ret); } private PartitionSet newOrder(FixedEstimatorState state, Object args[]) { final Short w_id = (Short)args[0]; assert(w_id != null); short s_w_ids[] = (short[])args[5]; int base_partition = this.getPartition(w_id.shortValue()); PartitionSet touchedPartitions = this.catalogContext.getPartitionSetSingleton(base_partition); assert(touchedPartitions != null) : "base_partition = " + base_partition; for (int i = 0; i < s_w_ids.length; i++) { if (s_w_ids[i] != w_id) { if (this.neworder_prefetchables != null) { for (CountedStatement cntStmt : this.getNewOrderPrefetchables(i)) { state.addPrefetchableStatement(cntStmt); } // FOR } if (touchedPartitions.size() == 1) { touchedPartitions = new PartitionSet(base_partition); } touchedPartitions.add(this.getPartition(s_w_ids[i])); } } // FOR if (debug.val) LOG.debug(String.format("NewOrder - [W_ID=%d / S_W_IDS=%s] => [BasePartition=%s / Partitions=%s]", w_id, Arrays.toString(s_w_ids), base_partition, touchedPartitions)); return (touchedPartitions); } private CountedStatement[] getNewOrderPrefetchables(int index) { CountedStatement[] ret = this.neworder_countedstmts.get(index); if (ret == null) { // There's a race condition here, but who cares... ret = new CountedStatement[this.neworder_prefetchables.length]; for (int i = 0; i < ret.length; i++) { ret[i] = new CountedStatement(this.neworder_prefetchables[i], i); } // FOR this.neworder_countedstmts.set(index, ret); } return (ret); } }