package edu.brown.hstore.specexec;
import java.util.List;
import java.util.Random;
import org.voltdb.ParameterSet;
import org.voltdb.SQLStmt;
import org.voltdb.VoltProcedure;
import org.voltdb.catalog.Partition;
import org.voltdb.catalog.ProcParameter;
import org.voltdb.catalog.Procedure;
import org.voltdb.catalog.Site;
import org.voltdb.catalog.Statement;
import org.voltdb.catalog.StmtParameter;
import org.voltdb.messaging.FastSerializer;
import org.voltdb.types.TimestampType;
import edu.brown.BaseTestCase;
import edu.brown.benchmark.seats.procedures.NewReservation;
import edu.brown.catalog.CatalogUtil;
import edu.brown.catalog.special.CountedStatement;
import edu.brown.hstore.HStoreCoordinator;
import edu.brown.hstore.Hstoreservice.TransactionInitRequest;
import edu.brown.hstore.Hstoreservice.WorkFragment;
import edu.brown.hstore.MockHStoreSite;
import edu.brown.hstore.conf.HStoreConf;
import edu.brown.hstore.estimators.EstimatorState;
import edu.brown.hstore.estimators.markov.MarkovEstimatorState;
import edu.brown.hstore.txns.DependencyTracker;
import edu.brown.hstore.specexec.PrefetchQueryPlanner;
import edu.brown.hstore.txns.LocalTransaction;
import edu.brown.utils.PartitionSet;
import edu.brown.utils.ProjectType;
import edu.brown.utils.StringUtil;
public class TestPrefetchQueryPlanner extends BaseTestCase {
private static final Long TXN_ID = 1000l;
private static final Class<? extends VoltProcedure> TARGET_PREFETCH_PROCEDURE = NewReservation.class;
private static final String TARGET_PREFETCH_STATEMENT = "GetCustomer";
private static final int NUM_HOSTS = 1;
private static final int NUM_SITES = 4; // per host
private static final int NUM_PARTITIONS = 1; // per site
private static final int LOCAL_SITE = 0;
private static final int LOCAL_PARTITION = 0;
private final MockHStoreSite[] hstore_sites = new MockHStoreSite[NUM_SITES];
private final HStoreCoordinator[] coordinators = new HStoreCoordinator[NUM_SITES];
private final FastSerializer fs = new FastSerializer();
private DependencyTracker depTracker;
private LocalTransaction ts;
private PrefetchQueryPlanner prefetcher;
private int[] partition_site_xref;
private Random rand = new Random(0);
private Object proc_params[] = {
100l, // r_id
LOCAL_PARTITION + 1l, // c_id
LOCAL_PARTITION, // f_id
this.rand.nextInt(100), // seatnum
100d, // price
new long[0], // attrs
new TimestampType()
};
@Override
protected void setUp() throws Exception {
super.setUp(ProjectType.SEATS);
this.initializeCatalog(NUM_HOSTS, NUM_SITES, NUM_PARTITIONS);
Procedure catalog_proc = this.getProcedure(TARGET_PREFETCH_PROCEDURE);
Statement catalog_stmt = this.getStatement(catalog_proc, TARGET_PREFETCH_STATEMENT);
catalog_stmt.setPrefetchable(true);
catalog_proc.setPrefetchable(true);
final ParameterSet params = new ParameterSet(this.proc_params);
final EstimatorState estState = new MarkovEstimatorState.Factory(catalogContext).makeObject();
estState.addPrefetchableStatement(new CountedStatement(catalog_stmt, 0));
// Hard-code ParameterMapping
int mappings[][] = {
// StmtParameter -> ProcParameter
{ 0, 1 },
};
List<ProcParameter> procParams = CatalogUtil.getSortedCatalogItems(catalog_proc.getParameters(), "index");
List<StmtParameter> stmtParams = CatalogUtil.getSortedCatalogItems(catalog_stmt.getParameters(), "index");
assertNotNull(stmtParams);
assertEquals(catalog_stmt.getParameters().size(), mappings.length);
for (int m[] : mappings) {
stmtParams.get(m[0]).setProcparameter(procParams.get(m[1]));
} // FOR
assertNotNull(catalogContext.paramMappings);
this.prefetcher = new PrefetchQueryPlanner(catalogContext, p_estimator);
SQLStmt[] batchStmts = {new SQLStmt(catalog_stmt)};
this.prefetcher.addPlanner(catalog_proc, estState.getPrefetchableStatements(), batchStmts);
for (int i = 0; i < NUM_SITES; i++) {
this.hstore_sites[i] = new MockHStoreSite(i, catalogContext, HStoreConf.singleton());
this.coordinators[i] = this.hstore_sites[i].initHStoreCoordinator();
// We have to make our fake ExecutionSites for each Partition at
// this site
// for (Partition catalog_part : catalog_site.getPartitions()) {
// MockPartitionExecutor es = new
// MockPartitionExecutor(catalog_part.getId(), catalog,
// p_estimator);
// this.hstore_sites[i].addPartitionExecutor(catalog_part.getId(),
// es);
// es.initHStoreSite(this.hstore_sites[i]);
// } // FOR
} // FOR
this.ts = new LocalTransaction(this.hstore_sites[LOCAL_SITE]) {
@Override
public org.voltdb.ParameterSet getProcedureParameters() {
return (params);
}
@Override
public edu.brown.hstore.estimators.EstimatorState getEstimatorState() {
return (estState);
}
};
// Generate the minimum set of partitions that we need to touch
PartitionSet partitions = new PartitionSet();
for (int idx : new int[] { 2, 1 }) {
Object val = this.proc_params[idx];
int p = p_estimator.getHasher().hash(val);
System.err.println(val + " -> " + p);
partitions.add(p);
} // FOR
this.ts.testInit(TXN_ID, LOCAL_PARTITION, null, partitions, this.getProcedure(TARGET_PREFETCH_PROCEDURE));
this.ts.initializePrefetch();
this.partition_site_xref = new int[catalogContext.numberOfPartitions];
for (Partition catalog_part : catalogContext.getAllPartitions()) {
this.partition_site_xref[catalog_part.getId()] = ((Site) catalog_part.getParent()).getId();
} // FOR
this.depTracker = this.hstore_sites[0].getDependencyTracker(LOCAL_PARTITION);
assertNotNull(this.depTracker);
}
/**
* testGenerateWorkFragments
*/
public void testGenerateWorkFragments() throws Exception {
int num_sites = catalogContext.numberOfSites;
this.ts.setTransactionId(TXN_ID);
TransactionInitRequest.Builder[] builders = this.prefetcher.plan(this.ts,
this.ts.getProcedureParameters(),
this.depTracker,
this.fs);
TransactionInitRequest[] requests = new TransactionInitRequest[builders.length];
for (int i = 0; i < builders.length; i++) {
if (builders[i] != null) requests[i] = builders[i].build();
}
assertEquals(num_sites, requests.length);
// The TransactionInitRequest for the local partition will be the
// default, the next partition will have a regular WorkFragment, and the
// rest will be null.
System.err.println(StringUtil.join("\n\n", requests));
/*
* TransactionInitRequest default_request =
* TransactionInitRequest.newBuilder()
* .setTransactionId(this.ts.getTransactionId())
* .setProcedureId(this.ts.getProcedure().getId())
* .addAllPartitions(this.ts.getPredictTouchedPartitions()) .build();
*/
int base_site = this.partition_site_xref[LOCAL_PARTITION];
int remote_site = this.partition_site_xref[LOCAL_PARTITION + 1];
assertNotSame(base_site, remote_site);
assertNotNull(requests[base_site]);
assertEquals(0, requests[base_site].getPrefetchFragmentsCount());
assertNotNull(requests[remote_site]);
assertEquals(1, requests[remote_site].getPrefetchFragmentsCount());
assertNull(requests[2]);
assertNull(requests[3]);
// The WorkFragments are grouped by siteID.
assert (requests.length == num_sites);
for (int siteid = 0; siteid < num_sites; ++siteid) {
TransactionInitRequest request = requests[siteid];
if (request != null && request.getPrefetchFragmentsCount() > 0) {
List<WorkFragment> frags = request.getPrefetchFragmentsList();
for (WorkFragment frag : frags) {
assertEquals(siteid, this.partition_site_xref[frag.getPartitionId()]);
assertTrue(frag.getPrefetch());
}
}
}
// The WorkFragment doesn't exist for the base partition.
TransactionInitRequest request = requests[base_site];
for (WorkFragment frag : request.getPrefetchFragmentsList()) {
assertFalse(frag.getPartitionId() == LOCAL_PARTITION);
assertTrue(frag.getPrefetch());
}
}
}