package edu.brown.workload;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import org.junit.Test;
import org.voltdb.VoltProcedure;
import org.voltdb.benchmark.tpcc.procedures.neworder;
import org.voltdb.catalog.*;
import edu.brown.utils.*;
import edu.brown.BaseTestCase;
public class TestWorkload extends BaseTestCase {
public static final Random rand = new Random();
public static final String TARGET_PROCEDURE = neworder.class.getSimpleName();
public static final int NUM_ORDER_ITEMS = 5;
public static final int BASE_PARTITION = 1;
public static final VoltProcedure CALLER = new VoltProcedure() {
public Long getTransactionId() {
return (1001l);
};
};
public static final Object BASE_ARGS[] = new Object[]{
new Long(BASE_PARTITION), // [0] W_ID
new Long(1), // [1] D_ID
new Long(1), // [2] C_ID
new Date(), // [3] TIMESTAMP
new Long[NUM_ORDER_ITEMS], // [4] OL_I_IDs
new Long[NUM_ORDER_ITEMS], // [5] OL_SUPPLY_W_ID
new Long[NUM_ORDER_ITEMS], // [6] OL_QUANTITY
};
static {
Long ids0[] = (Long[])BASE_ARGS[4];
Long ids1[] = (Long[])BASE_ARGS[6];
for (int i = 0; i < NUM_ORDER_ITEMS; i++) {
ids0[i] = new Long(rand.nextLong());
ids1[i] = new Long(rand.nextLong());
} // FOR
};
protected Workload workload;
protected Procedure catalog_proc;
protected Object single_xact_args[] = new Object[BASE_ARGS.length];
protected Object multi_xact_args[] = new Object[BASE_ARGS.length];
protected TransactionTrace last_xact_trace = null;
@Override
protected void setUp() throws Exception {
super.setUp(ProjectType.TPCC);
this.workload = new Workload(catalog);
this.catalog_proc = this.getProcedure(TARGET_PROCEDURE);
//
// Create arguments for two xact traces, one that is single-partition and one that is multi-partition
//
for (int i = 0; i < 2; i++) {
Object args[] = (i == 0 ? this.single_xact_args : this.multi_xact_args);
for (int ii = 0; ii < args.length; ii++) {
if (ii != 5) {
args[ii] = BASE_ARGS[ii];
} else {
Long w_ids[] = new Long[NUM_ORDER_ITEMS];
// Single-Partition
if (i == 0) {
for (int iii = 0; iii < NUM_ORDER_ITEMS; iii++) {
w_ids[iii] = new Long(BASE_PARTITION);
} // FOR
// Multi-Partition
} else {
for (int iii = 0; iii < NUM_ORDER_ITEMS; iii++) {
int rand_idx = rand.nextInt(10);
if (rand_idx <= 5) {
w_ids[iii] = new Long(BASE_PARTITION);
} else {
w_ids[iii] = new Long(rand_idx % 5);
}
} // FOR
}
args[ii] = w_ids;
}
} // FOR
} // FOR
}
protected TransactionTrace startTransaction(Object args[]) {
TransactionTrace xact = this.workload.startTransaction(CALLER.getTransactionId(), this.catalog_proc, args);
assertNotNull(xact);
assertNotNull(xact.getTransactionId());
assertTrue(xact.getTransactionId() >= 0);
assertNotNull(xact.getStartTimestamp());
assertTrue(xact.getStopTimestamp() == null);
this.last_xact_trace = xact;
return (xact);
}
protected QueryTrace startQuery(TransactionTrace xact, Statement catalog_stmt, Object args[], int batch_id) {
assertNotNull(xact);
QueryTrace query = (QueryTrace)this.workload.startQuery(xact, catalog_stmt, args, batch_id);
assertNotNull(query);
assertNotNull(query.getStartTimestamp());
assertTrue(query.getStopTimestamp() == null);
assertEquals(catalog_stmt.getName(), query.getCatalogItemName());
assertEquals(batch_id, query.getBatchId());
assertEquals(args.length, query.getParams().length);
return (query);
}
/**
* testStartTransaction
*/
public void testStartTransaction() throws Exception {
TransactionTrace xact = this.startTransaction(this.single_xact_args);
assertNotNull(this.workload.getTransaction(xact.getTransactionId()));
assertFalse(xact.isAborted());
}
/**
* testStopTransaction
*/
public void testStopTransaction() throws Exception {
TransactionTrace xact = this.startTransaction(this.single_xact_args);
this.workload.stopTransaction(xact);
assertNotNull(xact.getStopTimestamp());
assertFalse(xact.isAborted());
}
/**
* testAbortTransaction
*/
public void testAbortTransaction() throws Exception {
TransactionTrace xact = this.startTransaction(this.single_xact_args);
// Start+Stop one query to make sure that it doesn't get marked as aborted
Statement catalog_stmt = this.getStatement(xact.getCatalogItem(catalog_db), "getWarehouseTaxRate");
QueryTrace nonabort_query = this.startQuery(xact, catalog_stmt, new Object[]{1l}, 0);
assertNotNull(nonabort_query);
assert(xact.getQueries().contains(nonabort_query));
this.workload.stopQuery(nonabort_query, null);
assert(nonabort_query.isStopped());
assertFalse(nonabort_query.isAborted());
// Now start but don't stop a few queries so that we can make sure they do get aborted!
List<QueryTrace> aborted = new ArrayList<QueryTrace>();
for (int i = 0; i < 4; i++) {
catalog_stmt = this.getStatement(xact.getCatalogItem(catalog_db), "getWarehouseTaxRate");
QueryTrace abort_query = this.startQuery(xact, catalog_stmt, new Object[]{i}, 0);
assertNotNull(abort_query);
assert(xact.getQueries().contains(abort_query));
assertFalse(abort_query.isStopped());
assertFalse(abort_query.isAborted());
aborted.add(abort_query);
} // FOR
this.workload.abortTransaction(xact);
assertNotNull(xact.getStopTimestamp());
assert(xact.isAborted());
assertEquals(aborted.size()+1, xact.getQueryCount());
// System.err.println(xact.debug(catalog_db));
for (QueryTrace query : xact.getQueries()) {
if (aborted.contains(query)) {
assert(query.isAborted());
} else {
assertFalse(query.isAborted());
}
} // FOR
}
/**
* testStopQuery
*/
@Test(expected=IllegalStateException.class)
public void testStopQuery() throws Exception {
TransactionTrace xact = this.startTransaction(this.single_xact_args);
// Start one query in Batch #0 but then don't stop it
Statement catalog_stmt = this.getStatement(xact.getCatalogItem(catalog_db), "getWarehouseTaxRate");
QueryTrace query = this.startQuery(xact, catalog_stmt, new Object[]{1l}, 0);
assertNotNull(query);
assert(xact.getQueries().contains(query));
assertFalse(query.isStopped());
// Now try to start/stop another query in the next batch.
// The workload trace manager should disallow this!
boolean valid = false;
try {
query = this.startQuery(xact, catalog_stmt, new Object[]{2l}, 1);
} catch (IllegalStateException ex) {
valid = true;
}
assert(valid);
// assertNotNull(query);
// assert(xact.getQueries().contains(query));
// this.workload.stopQuery(query);
}
/**
* testStartQuery
*/
public void testStartQuery() throws Exception {
TransactionTrace xact = this.startTransaction(this.single_xact_args);
List<Statement> stmt_objs = new ArrayList<Statement>();
List<Object[]> stmt_args = new ArrayList<Object[]>();
List<Integer> stmt_batchids = new ArrayList<Integer>();
String stmt_names[] = { "getStockInfo", "getWarehouseTaxRate", "getDistrict" };
int batch_id = -1;
for (String stmt_name : stmt_names) {
batch_id++;
if (stmt_name.equals("getStockInfo")) {
assertEquals(0, batch_id);
int item_idx = 0;
for (Statement catalog_stmt : catalog_proc.getStatements()) {
if (!catalog_stmt.getName().startsWith(stmt_name)) continue;
Object args[] = new Object[] {
((Long[])this.single_xact_args[4])[item_idx],
((Long[])this.single_xact_args[5])[item_idx],
};
stmt_objs.add(catalog_stmt);
stmt_args.add(args);
stmt_batchids.add(batch_id);
if (item_idx++ >= (NUM_ORDER_ITEMS - 1)) break;
} // FOR
} else if (stmt_name.equals("getWarehouseTaxRate")) {
Object args[] = new Object[] {
this.single_xact_args[1], // W_ID
};
stmt_objs.add(catalog_proc.getStatements().get(stmt_name));
stmt_args.add(args);
stmt_batchids.add(batch_id);
} else if (stmt_name.equals("getDistrict")) {
Object args[] = new Object[] {
this.single_xact_args[2], // D_ID
this.single_xact_args[1], // W_ID
};
stmt_objs.add(catalog_proc.getStatements().get(stmt_name));
stmt_args.add(args);
stmt_batchids.add(batch_id);
}
} // FOR
for (int i = 0, cnt = stmt_objs.size(); i < cnt; i++) {
Statement catalog_stmt = stmt_objs.get(i);
Object args[] = stmt_args.get(i);
batch_id = stmt_batchids.get(i);
QueryTrace query = this.startQuery(xact, catalog_stmt, args, batch_id);
assertNotNull(query);
assert(xact.getQueries().contains(query));
this.workload.stopQuery(query, null);
} // FOR
this.workload.stopTransaction(xact);
assertNotNull(xact.getStopTimestamp());
}
}