/* This file is part of VoltDB.
* Copyright (C) 2008-2010 VoltDB L.L.C.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.voltdb.benchmark.tpcc;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.voltdb.VoltProcedure;
import org.voltdb.VoltTable;
import org.voltdb.VoltType;
import org.voltdb.benchmark.BlockingClient;
import org.voltdb.benchmark.Clock;
import org.voltdb.benchmark.Verification;
import org.voltdb.benchmark.Verification.Expression;
import org.voltdb.benchmark.tpcc.procedures.ResetWarehouse;
import org.voltdb.benchmark.tpcc.procedures.delivery;
import org.voltdb.benchmark.tpcc.procedures.neworder;
import org.voltdb.benchmark.tpcc.procedures.ostatByCustomerId;
import org.voltdb.benchmark.tpcc.procedures.ostatByCustomerName;
import org.voltdb.benchmark.tpcc.procedures.paymentByCustomerId;
import org.voltdb.benchmark.tpcc.procedures.paymentByCustomerName;
import org.voltdb.benchmark.tpcc.procedures.slev;
import org.voltdb.client.Client;
import org.voltdb.client.ClientResponse;
import org.voltdb.client.NoConnectionsException;
import org.voltdb.client.ProcedureCallback;
import org.voltdb.types.ExpressionType;
import org.voltdb.types.TimestampType;
import edu.brown.api.BenchmarkComponent;
import edu.brown.hstore.conf.HStoreConf;
import edu.brown.rand.RandomDistribution.FlatHistogram;
import edu.brown.statistics.ObjectHistogram;
import edu.brown.utils.StringUtil;
public class TPCCClient extends BenchmarkComponent implements TPCCSimulation.ProcCaller {
private static final Logger LOG = Logger.getLogger(TPCCClient.class);
final TPCCSimulation m_tpccSim;
final ScaleParameters m_scaleParams;
final TPCCConfig m_tpccConfig;
FlatHistogram<Transaction> txnWeights;
private final boolean crash_on_error = false;
// type used by at least VoltDBClient and JDBCClient
@SuppressWarnings("unchecked")
public enum Transaction {
STOCK_LEVEL(TPCCConstants.FREQUENCY_STOCK_LEVEL, slev.class),
DELIVERY(TPCCConstants.FREQUENCY_DELIVERY, delivery.class),
ORDER_STATUS(TPCCConstants.FREQUENCY_ORDER_STATUS, ostatByCustomerId.class, ostatByCustomerName.class),
PAYMENT(TPCCConstants.FREQUENCY_PAYMENT, paymentByCustomerId.class, paymentByCustomerName.class),
NEW_ORDER(TPCCConstants.FREQUENCY_NEW_ORDER, neworder.class),
RESET_WAREHOUSE(0, ResetWarehouse.class);
private Transaction(int weight, Class<? extends VoltProcedure>...procClasses) {
this.displayName = StringUtil.title(this.name().replace("_", " ").toLowerCase());
this.weight = weight;
this.procClasses = procClasses;
}
public final String displayName;
public final int weight;
public final Class<? extends VoltProcedure> procClasses[];
}
private static class ForeignKeyConstraints implements Expression {
private final String m_table;
private static final Set<Short> m_warehouse = new HashSet<Short>();
private static final Set<List<Number>> m_district = new HashSet<List<Number>>();
private static final Set<List<Number>> m_customer = new HashSet<List<Number>>();
private static final Set<List<Number>> m_orders = new HashSet<List<Number>>();
private static final Set<List<Number>> m_stock = new HashSet<List<Number>>();
private static final Set<Integer> m_item = new HashSet<Integer>();
public ForeignKeyConstraints(String table) {
m_table = table;
}
@Override
public <T> Object evaluate(T tuple) {
VoltTable row = (VoltTable) tuple;
if (m_table.equalsIgnoreCase("warehouse")) {
getKey(row, "W_ID", m_warehouse);
} else if (m_table.equalsIgnoreCase("district")) {
getKeys(row, new String[] {"D_W_ID", "D_ID"},
m_district);
short d_w_id = (short) row.getLong("D_W_ID");
return m_warehouse.contains(d_w_id);
} else if (m_table.equalsIgnoreCase("customer")) {
getKeys(row, new String[] {"C_W_ID", "C_D_ID", "C_ID"},
m_customer);
short c_w_id = (short) row.getLong("C_W_ID");
byte c_d_id = (byte) row.getLong("C_D_ID");
List<Number> key = new ArrayList<Number>(2);
key.add(c_w_id);
key.add(c_d_id);
return m_district.contains(key);
} else if (m_table.equalsIgnoreCase("history")) {
short h_w_id = (short) row.getLong("H_W_ID");
byte h_d_id = (byte) row.getLong("H_D_ID");
if (row.wasNull()) {
System.err.println("row was null 1");
return false;
}
List<Number> districtKey = new ArrayList<Number>(2);
districtKey.add(h_w_id);
districtKey.add(h_d_id);
short h_c_w_id = (short) row.getLong("H_C_W_ID");
if (row.wasNull()) {
System.err.println("row was null 2");
return false;
}
byte h_c_d_id = (byte) row.getLong("H_C_D_ID");
if (row.wasNull()) {
System.err.println("row was null 3");
return false;
}
int h_c_id = (int) row.getLong("H_C_ID");
if (row.wasNull()) {
System.err.println("row was null 4");
return false;
}
List<Number> customerKey = new ArrayList<Number>(3);
customerKey.add(h_c_w_id);
customerKey.add(h_c_d_id);
customerKey.add(h_c_id);
return (m_district.contains(districtKey)
&& m_customer.contains(customerKey));
} else if (m_table.equalsIgnoreCase("new_order")) {
short no_w_id = (short) row.getLong("NO_W_ID");
byte no_d_id = (byte) row.getLong("NO_D_ID");
int no_o_id = (int) row.getLong("NO_O_ID");
List<Number> key = new ArrayList<Number>(3);
key.add(no_w_id);
key.add(no_d_id);
key.add(no_o_id);
return m_orders.contains(key);
} else if (m_table.equalsIgnoreCase("orders")) {
getKeys(row, new String[] {"O_W_ID", "O_D_ID", "O_ID"},
m_orders);
short o_w_id = (short) row.getLong("O_W_ID");
byte o_d_id = (byte) row.getLong("O_D_ID");
int o_c_id = (int) row.getLong("O_C_ID");
if (row.wasNull())
return false;
List<Number> key = new ArrayList<Number>(3);
key.add(o_w_id);
key.add(o_d_id);
key.add(o_c_id);
return m_customer.contains(key);
} else if (m_table.equalsIgnoreCase("order_line")) {
short ol_supply_w_id = (short) row.getLong("OL_SUPPLY_W_ID");
if (row.wasNull())
return false;
int ol_i_id = (int) row.getLong("OL_I_ID");
if (row.wasNull())
return false;
List<Number> stockKey = new ArrayList<Number>(2);
stockKey.add(ol_supply_w_id);
stockKey.add(ol_i_id);
short ol_w_id = (short) row.getLong("OL_W_ID");
byte ol_d_id = (byte) row.getLong("OL_D_ID");
int ol_o_id = (int) row.getLong("OL_O_ID");
List<Number> ordersKey = new ArrayList<Number>(3);
ordersKey.add(ol_w_id);
ordersKey.add(ol_d_id);
ordersKey.add(ol_o_id);
return (m_stock.contains(stockKey)
&& m_orders.contains(ordersKey));
} else if (m_table.equalsIgnoreCase("item")) {
getKey(row, "I_ID", m_item);
} else if (m_table.equalsIgnoreCase("stock")) {
getKeys(row, new String[] {"S_W_ID", "S_I_ID"}, m_stock);
short s_w_id = (short) row.getLong("S_W_ID");
int s_i_id = (int) row.getLong("S_I_ID");
return (m_warehouse.contains(s_w_id)
&& m_item.contains(s_i_id));
}
return true;
}
@SuppressWarnings("unchecked")
private static <T> void getKey(VoltTable tuple, String columnName,
Set<T> keySet) {
final int index = tuple.getColumnIndex(columnName);
final VoltType type = tuple.getColumnType(index);
keySet.add((T) tuple.get(index, type));
}
private static <T> void getKeys(VoltTable tuple, String[] columnNames,
Set<List<Number>> keySet) {
final List<Number> key = new ArrayList<Number>(columnNames.length);
for (String name : columnNames) {
final int index = tuple.getColumnIndex(name);
final VoltType type = tuple.getColumnType(index);
key.add((Number) tuple.get(index, type));
}
keySet.add(key);
}
@Override
public <T> String toString(T tuple) {
return ("foreight key check on " + m_table);
}
}
/** Complies with our benchmark client remote controller scheme */
public static void main(String args[]) {
edu.brown.api.BenchmarkComponent.main(TPCCClient.class, args, false);
}
public TPCCClient(
Client client,
RandomGenerator generator,
Clock clock,
ScaleParameters params,
TPCCConfig config)
{
super(client);
m_scaleParams = params;
m_tpccConfig = config;
m_tpccSim = new TPCCSimulation(this, generator, clock, m_scaleParams, m_tpccConfig, 1.0, this.getCatalogContext());
// m_tpccSim2 = new TPCCSimulation(this, generator, clock, m_scaleParams, m_tpccConfig, 1.0);
this.initTransactionWeights();
}
/** Complies with our benchmark client remote controller scheme */
public TPCCClient(String args[]) {
super(args);
m_tpccConfig = TPCCConfig.createConfig(this.getCatalogContext(), m_extraParams);
if (LOG.isDebugEnabled()) LOG.debug("TPC-C Client Configuration:\n" + m_tpccConfig);
// makeForRun requires the value cLast from the load generator in
// order to produce a valid generator for the run. Thus the sort
// of weird eat-your-own ctor pattern.
RandomGenerator.NURandC base_loadC = new RandomGenerator.NURandC(0,0,0);
RandomGenerator.NURandC base_runC = RandomGenerator.NURandC.makeForRun(
new RandomGenerator.Implementation(0), base_loadC);
RandomGenerator rng = new RandomGenerator.Implementation(0);
rng.setC(base_runC);
RandomGenerator.NURandC base_loadC2 = new RandomGenerator.NURandC(0,0,0);
RandomGenerator.NURandC base_runC2 = RandomGenerator.NURandC.makeForRun(
new RandomGenerator.Implementation(0), base_loadC2);
// RandomGenerator rng2 = new RandomGenerator.Implementation(0);
rng.setC(base_runC2);
HStoreConf hstore_conf = this.getHStoreConf();
m_scaleParams = ScaleParameters.makeWithScaleFactor(m_tpccConfig, hstore_conf.client.scalefactor);
m_tpccSim = new TPCCSimulation(this, rng, new Clock.RealTime(), m_scaleParams, m_tpccConfig, hstore_conf.client.skewfactor, this.getCatalogContext());
// m_tpccSim2 = new TPCCSimulation(this, rng2, new Clock.RealTime(), m_scaleParams, m_tpccConfig, hstore_conf.client.skewfactor);
// Set up checking
buildConstraints();
// Initialize the sampling table
this.initTransactionWeights();
// Disable all distributed transaction requests for this client thread
if (this.isSinglePartitionOnly()) m_tpccConfig.disableDistributedTransactions();
//m_sampler = new VoltSampler(20, "tpcc-cliet-sampling");
}
/**
* Initialize the sampling table
*/
private void initTransactionWeights() {
ObjectHistogram<Transaction> txns = new ObjectHistogram<Transaction>(true);
for (Transaction t : Transaction.values()) {
Integer weight = null;
// HACK: Because there are multiple stored procedures for payment and order_status,
// we will try to match on their weights on either the class names or enum names
for (Class<? extends VoltProcedure> procClass : t.procClasses) {
weight = this.getTransactionWeight(procClass.getSimpleName());
if (weight != null) break;
} // FOR
if (weight == null) weight = this.getTransactionWeight(t.name());
if (weight == null) weight = t.weight;
if (weight > 0) txns.put(t, weight);
} // FOR
assert(txns.getSampleCount() == 100) : txns;
this.txnWeights = new FlatHistogram<Transaction>(m_tpccSim.rng(), txns);
if (LOG.isDebugEnabled()) LOG.debug("Transaction Weights:\n" + txns);
}
protected TPCCConfig getTPCCConfig() {
return (m_tpccConfig);
}
protected ScaleParameters getScaleParameters() {
return (m_scaleParams);
}
protected TPCCSimulation getTPCCSimulation() {
return (m_tpccSim);
}
@Override
protected boolean useHeavyweightClient() {
return true;
}
protected void buildConstraints() {
Expression constraint = null;
// WAREHOUSE table
Expression w_id = Verification.inRange("W_ID", (short) m_scaleParams.starting_warehouse,
(short) (m_scaleParams.warehouses * 2) + m_scaleParams.starting_warehouse);
Expression w_tax = Verification.inRange("W_TAX", TPCCConstants.MIN_TAX,
TPCCConstants.MAX_TAX);
Expression w_fk = new ForeignKeyConstraints("WAREHOUSE");
Expression warehouse = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
w_id, w_tax, w_fk);
// DISTRICT table
Expression d_id = Verification.inRange("D_ID", (byte) 1,
(byte) m_scaleParams.districtsPerWarehouse);
Expression d_w_id = Verification.inRange("D_W_ID", (short) m_scaleParams.starting_warehouse,
(short) (m_scaleParams.warehouses * 2) + m_scaleParams.starting_warehouse);
Expression d_next_o_id = Verification.inRange("D_NEXT_O_ID", 1, 10000000);
Expression d_tax = Verification.inRange("D_TAX", TPCCConstants.MIN_TAX,
TPCCConstants.MAX_TAX);
Expression d_fk = new ForeignKeyConstraints("DISTRICT");
Expression district = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
d_id, d_w_id, d_next_o_id, d_tax,
d_fk);
// CUSTOMER table
Expression c_id = Verification.inRange("C_ID", 1,
m_scaleParams.customersPerDistrict);
Expression c_d_id = Verification.inRange("C_D_ID", (byte) 1,
(byte) m_scaleParams.districtsPerWarehouse);
Expression c_w_id = Verification.inRange("C_W_ID", (short) m_scaleParams.starting_warehouse,
(short) (m_scaleParams.warehouses * 2) + m_scaleParams.starting_warehouse);
Expression c_discount = Verification.inRange("C_DISCOUNT", TPCCConstants.MIN_DISCOUNT,
TPCCConstants.MAX_DISCOUNT);
Expression c_credit =
Verification.conjunction(ExpressionType.CONJUNCTION_OR,
Verification.compareWithConstant(ExpressionType.COMPARE_EQUAL,
"C_CREDIT",
TPCCConstants.GOOD_CREDIT),
Verification.compareWithConstant(ExpressionType.COMPARE_EQUAL,
"C_CREDIT",
TPCCConstants.BAD_CREDIT));
Expression c_fk = new ForeignKeyConstraints("CUSTOMER");
Expression customer = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
c_id, c_d_id, c_w_id, c_discount, c_credit,
c_fk);
// HISTORY table
Expression h_c_id = Verification.inRange("H_C_ID", 1,
m_scaleParams.customersPerDistrict);
Expression h_c_d_id = Verification.inRange("H_C_D_ID", (byte) 1,
(byte) m_scaleParams.districtsPerWarehouse);
Expression h_c_w_id = Verification.inRange("H_C_W_ID", (short) m_scaleParams.starting_warehouse,
(short) (m_scaleParams.warehouses * 2) + m_scaleParams.starting_warehouse);
Expression h_d_id = Verification.inRange("H_D_ID", (byte) 1,
(byte) m_scaleParams.districtsPerWarehouse);
Expression h_w_id = Verification.inRange("H_W_ID", (short) m_scaleParams.starting_warehouse,
(short) (m_scaleParams.warehouses * 2) + m_scaleParams.starting_warehouse);
Expression h_fk = new ForeignKeyConstraints("HISTORY");
Expression history = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
h_c_id, h_c_d_id, h_c_w_id, h_d_id, h_w_id,
h_fk);
// NEW_ORDER table
Expression no_o_id = Verification.inRange("NO_O_ID", 1, 10000000);
Expression no_d_id = Verification.inRange("NO_D_ID", (byte) 1,
(byte) m_scaleParams.districtsPerWarehouse);
Expression no_w_id = Verification.inRange("NO_W_ID", (short) m_scaleParams.starting_warehouse,
(short) (m_scaleParams.warehouses * 2) + m_scaleParams.starting_warehouse);
Expression no_fk = new ForeignKeyConstraints("NEW_ORDER");
Expression new_order = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
no_o_id, no_d_id, no_w_id, no_fk);
// ORDERS table
Expression o_id = Verification.inRange("O_ID", 1, 10000000);
Expression o_c_id = Verification.inRange("O_C_ID", 1,
m_scaleParams.customersPerDistrict);
Expression o_d_id = Verification.inRange("O_D_ID", (byte) 1,
(byte) m_scaleParams.districtsPerWarehouse);
Expression o_w_id = Verification.inRange("O_W_ID", (short) m_scaleParams.starting_warehouse,
(short) (m_scaleParams.warehouses * 2) + m_scaleParams.starting_warehouse);
Expression o_carrier_id =
Verification.conjunction(ExpressionType.CONJUNCTION_OR,
Verification.compareWithConstant(ExpressionType.COMPARE_EQUAL,
"O_CARRIER_ID",
(int) TPCCConstants.NULL_CARRIER_ID),
Verification.inRange("O_CARRIER_ID",
TPCCConstants.MIN_CARRIER_ID,
TPCCConstants.MAX_CARRIER_ID));
Expression o_fk = new ForeignKeyConstraints("ORDERS");
Expression orders = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
o_id, o_c_id, o_d_id, o_w_id, o_carrier_id,
o_fk);
// ORDER_LINE table
Expression ol_o_id = Verification.inRange("OL_O_ID", 1, 10000000);
Expression ol_d_id = Verification.inRange("OL_D_ID", (byte) 1,
(byte) m_scaleParams.districtsPerWarehouse);
Expression ol_w_id = Verification.inRange("OL_W_ID", (short) m_scaleParams.starting_warehouse,
(short) (m_scaleParams.warehouses * 2) + m_scaleParams.starting_warehouse);
Expression ol_number = Verification.inRange("OL_NUMBER", 1,
TPCCConstants.MAX_OL_CNT);
Expression ol_i_id = Verification.inRange("OL_I_ID", 1, m_scaleParams.num_items);
Expression ol_supply_w_id = Verification.inRange("OL_SUPPLY_W_ID", (short) m_scaleParams.starting_warehouse,
(short) (m_scaleParams.warehouses * 2) + m_scaleParams.starting_warehouse);
Expression ol_quantity = Verification.inRange("OL_QUANTITY", 0,
TPCCConstants.MAX_OL_QUANTITY);
Expression ol_amount = Verification.inRange("OL_AMOUNT",
0.0,
TPCCConstants.MAX_PRICE * TPCCConstants.MAX_OL_QUANTITY);
Expression ol_fk = new ForeignKeyConstraints("ORDER_LINE");
Expression order_line = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
ol_o_id, ol_d_id, ol_w_id, ol_number,
ol_i_id, ol_supply_w_id, ol_quantity,
ol_amount, ol_fk);
// ITEM table
Expression i_id = Verification.inRange("I_ID", 1, m_scaleParams.num_items);
Expression i_im_id = Verification.inRange("I_IM_ID", TPCCConstants.MIN_IM,
TPCCConstants.MAX_IM);
Expression i_price = Verification.inRange("I_PRICE", TPCCConstants.MIN_PRICE,
TPCCConstants.MAX_PRICE);
Expression i_fk = new ForeignKeyConstraints("ITEM");
Expression item = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
i_id, i_im_id, i_price, i_fk);
// STOCK table
Expression s_i_id = Verification.inRange("S_I_ID", 1, m_scaleParams.num_items);
Expression s_w_id = Verification.inRange("S_W_ID", (short) m_scaleParams.starting_warehouse,
(short) (m_scaleParams.warehouses * 2) + m_scaleParams.starting_warehouse);
Expression s_quantity = Verification.inRange("S_QUANTITY", TPCCConstants.MIN_QUANTITY,
TPCCConstants.MAX_QUANTITY);
Expression s_fk = new ForeignKeyConstraints("STOCK");
Expression stock = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
s_i_id, s_w_id, s_quantity, s_fk);
// Delivery (no need to check 'd_id', it's systematically generated)
constraint = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
d_id, o_id);
addConstraint(TPCCConstants.DELIVERY, 0, constraint);
// New Order table 0
constraint = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
c_discount, c_credit);
addConstraint(TPCCConstants.NEWORDER, 0, constraint);
// New Order table 1
constraint =
Verification.conjunction(ExpressionType.CONJUNCTION_AND,
d_next_o_id,
w_tax, d_tax,
Verification.compareWithConstant(ExpressionType.COMPARE_GREATERTHAN,
"total", 0.0));
addConstraint(TPCCConstants.NEWORDER, 1, constraint);
// New Order table 2
constraint = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
s_quantity,
i_price,
ol_amount);
addConstraint(TPCCConstants.NEWORDER, 2, constraint);
// Order Status table 0
addConstraint(TPCCConstants.ORDER_STATUS_BY_ID, 0, c_id);
addConstraint(TPCCConstants.ORDER_STATUS_BY_NAME, 0, c_id);
// Order Status table 1
constraint = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
o_id, o_carrier_id);
addConstraint(TPCCConstants.ORDER_STATUS_BY_ID, 1, constraint);
addConstraint(TPCCConstants.ORDER_STATUS_BY_NAME, 1, constraint);
// Order Status table 2
constraint = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
ol_supply_w_id, ol_i_id,
ol_quantity, ol_amount);
addConstraint(TPCCConstants.ORDER_STATUS_BY_ID, 2, constraint);
addConstraint(TPCCConstants.ORDER_STATUS_BY_NAME, 2, constraint);
// Payment
constraint = Verification.conjunction(ExpressionType.CONJUNCTION_AND,
c_id, c_discount);
addConstraint(TPCCConstants.PAYMENT_BY_ID, 2, constraint);
// addConstraint(TPCCConstants.PAYMENT_BY_ID_C, 0, constraint);
addConstraint(TPCCConstants.PAYMENT_BY_NAME, 2, constraint);
// addConstraint(TPCCConstants.PAYMENT_BY_NAME_C, 0, constraint);
// slev
constraint = Verification.compareWithConstant(ExpressionType.COMPARE_GREATERTHANOREQUALTO,
"C1",
0L);
addConstraint(TPCCConstants.STOCK_LEVEL, 0, constraint);
// Full table checks (The order of adding them MATTERS!)
addTableConstraint("WAREHOUSE", warehouse);
addTableConstraint("DISTRICT", district);
addTableConstraint("CUSTOMER", customer);
addTableConstraint("HISTORY", history);
addTableConstraint("ORDERS", orders);
addTableConstraint("NEW_ORDER", new_order);
addTableConstraint("ITEM", item);
addTableConstraint("STOCK", stock);
addTableConstraint("ORDER_LINE", order_line);
}
/**
* Whether a message was queued when attempting the last invocation.
*/
private boolean m_queuedMessage = false;
/*
* callXXX methods should spin on backpressure barrier until they successfully queue rather then
* setting m_queuedMessage and returning immediately.
*/
private boolean m_blockOnBackpressure = true;
/**
* Hint used when constructing the Client to control the size of buffers allocated for message
* serialization
* Set to 512 because neworder tops out around that size
* @return
*/
@Override
protected int getExpectedOutgoingMessageSize() {
return 256;
}
@Override
public boolean runOnce() throws NoConnectionsException {
m_blockOnBackpressure = false;
// will send procedures to first connection w/o backpressure
// if all connections have backpressure, will round robin across
// busy servers (but the loop will spend more time running the
// network below.)
try {
m_tpccSim.doOne(txnWeights.nextValue());
return m_queuedMessage;
} catch (IOException e) {
throw (NoConnectionsException)e;
}
}
@Override
public void runLoop() throws NoConnectionsException {
m_blockOnBackpressure = true;
// if (Runtime.getRuntime().availableProcessors() > 4) {
// new Thread() {
// @Override
// public void run() {
// try {
// while (true) {
// m_tpccSim2.doOne();
// }
// } catch (IOException e) {
// }
// }
// }.start();
// }
try {
while (true) {
// will send procedures to first connection w/o backpressure
// if all connections have backpressure, will round robin across
// busy servers (but the loop will spend more time running the
// network below.)
m_tpccSim.doOne(txnWeights.nextValue());
}
} catch (IOException e) {
throw (NoConnectionsException)e;
}
}
// Delivery
class DeliveryCallback implements ProcedureCallback {
@Override
public void clientCallback(ClientResponse clientResponse) {
if (crash_on_error) {
boolean status = checkTransaction(TPCCConstants.DELIVERY, clientResponse, false, false);
assert status;
if (status && clientResponse.getResults()[0].getRowCount()
!= m_scaleParams.districtsPerWarehouse) {
/* FIXME
System.err.println(
"Only delivered from "
+ clientResponse.getResults()[0].getRowCount()
+ " districts.");
*/
}
}
incrementTransactionCounter(clientResponse, TPCCClient.Transaction.DELIVERY.ordinal());
}
}
@Override
public void callDelivery(short w_id, int carrier, TimestampType date) throws IOException {
if (m_blockOnBackpressure) {
final DeliveryCallback cb = new DeliveryCallback();
while (!this.getClientHandle().callProcedure(cb,
TPCCConstants.DELIVERY, w_id, carrier, date)) {
try {
this.getClientHandle().backpressureBarrier();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
m_queuedMessage = this.getClientHandle().callProcedure(new DeliveryCallback(),
TPCCConstants.DELIVERY, w_id, carrier, date);
}
}
// NewOrder
class NewOrderCallback implements ProcedureCallback {
public NewOrderCallback(boolean rollback) {
super();
this.cbRollback = rollback;
}
@Override
public void clientCallback(ClientResponse clientResponse) {
if (LOG.isDebugEnabled()) LOG.debug("NewOrder clientResponse.getStatus() = " + clientResponse.getStatus());
if (crash_on_error) {
boolean status = checkTransaction(TPCCConstants.NEWORDER, clientResponse, cbRollback, false);
assert (this.cbRollback || status) : "Rollback=" + this.cbRollback + ", Status=" + clientResponse.getStatus();
}
incrementTransactionCounter(clientResponse, TPCCClient.Transaction.NEW_ORDER.ordinal());
}
private boolean cbRollback;
}
int randomIndex = 0;
@Override
public void callNewOrder(boolean rollback, boolean noop, Object... paramlist) throws IOException {
final String proc_name = (noop ? TPCCConstants.NOOP : TPCCConstants.NEWORDER);
final NewOrderCallback cb = new NewOrderCallback(rollback);
if (m_blockOnBackpressure) {
while (!this.getClientHandle().callProcedure(cb, proc_name, paramlist)) {
try {
this.getClientHandle().backpressureBarrier();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
m_queuedMessage = this.getClientHandle().callProcedure(cb, proc_name, paramlist);
}
}
// Order status
class VerifyBasicCallback implements ProcedureCallback {
private final TPCCClient.Transaction m_transactionType;
private final String m_procedureName;
/**
* A generic callback that does not credit a transaction. Some transactions
* use two procedure calls - this counts as one transaction not two.
*/
VerifyBasicCallback() {
m_transactionType = null;
m_procedureName = null;
}
/** A generic callback that credits for the transaction type passed. */
VerifyBasicCallback(TPCCClient.Transaction transaction, String procName) {
m_transactionType = transaction;
m_procedureName = procName;
}
@Override
public void clientCallback(ClientResponse clientResponse) {
boolean abortExpected = false;
if (m_procedureName != null && (m_procedureName.equals(TPCCConstants.ORDER_STATUS_BY_NAME)
|| m_procedureName.equals(TPCCConstants.ORDER_STATUS_BY_ID)))
abortExpected = true;
if (crash_on_error) {
boolean status = checkTransaction(m_procedureName,
clientResponse,
abortExpected,
false);
assert status;
}
if (m_transactionType != null) {
incrementTransactionCounter(clientResponse, m_transactionType.ordinal());
}
}
}
@Override
public void callOrderStatus(String proc, Object... paramlist) throws IOException {
if (m_blockOnBackpressure) {
final VerifyBasicCallback cb = new VerifyBasicCallback(TPCCClient.Transaction.ORDER_STATUS,
proc);
while (!this.getClientHandle().callProcedure( cb,
proc, paramlist)) {
try {
this.getClientHandle().backpressureBarrier();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
m_queuedMessage = this.getClientHandle().callProcedure(new VerifyBasicCallback(TPCCClient.Transaction.ORDER_STATUS,
proc),
proc, paramlist);
}
}
// Payment
@Override
public void callPaymentById(short w_id, byte d_id, double h_amount,
short c_w_id, byte c_d_id, int c_id, TimestampType now) throws IOException {
m_queuedMessage = this.getClientHandle().callProcedure(new VerifyBasicCallback(TPCCClient.Transaction.PAYMENT, TPCCConstants.PAYMENT_BY_ID),
TPCCConstants.PAYMENT_BY_ID,
w_id, d_id, h_amount, c_w_id, c_d_id, c_id, now);
//
// if (m_blockOnBackpressure) {
// if (m_scaleParams.warehouses > 1) {
// final VerifyBasicCallback cb = new VerifyBasicCallback();
// while (!this.getClientHandle().callProcedure(cb, Constants.PAYMENT_BY_ID_W,
// w_id, d_id, h_amount, c_w_id, c_d_id, c_id, now)) {
// try {
// this.getClientHandle().backpressureBarrier();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// final VerifyBasicCallback cb2 = new VerifyBasicCallback(TPCCSimulation.Transaction.PAYMENT, Constants.PAYMENT_BY_ID_C);
// while (!this.getClientHandle().callProcedure(cb2, Constants.PAYMENT_BY_ID_C,
// w_id, d_id, h_amount, c_w_id, c_d_id, c_id, now)) {
// try {
// this.getClientHandle().backpressureBarrier();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// } else {
// final VerifyBasicCallback cb = new VerifyBasicCallback(TPCCSimulation.Transaction.PAYMENT, Constants.PAYMENT_BY_ID);
// while (!this.getClientHandle().callProcedure(cb, Constants.PAYMENT_BY_ID,
// w_id, d_id, h_amount, c_w_id, c_d_id, c_id, now)) {
// try {
// this.getClientHandle().backpressureBarrier();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }
// } else {
// if (m_scaleParams.warehouses > 1) {
// this.getClientHandle().callProcedure(new VerifyBasicCallback(), Constants.PAYMENT_BY_ID_W, w_id, d_id, h_amount, c_w_id, c_d_id, c_id, now);
// m_queuedMessage = this.getClientHandle().callProcedure(new VerifyBasicCallback(TPCCSimulation.Transaction.PAYMENT, Constants.PAYMENT_BY_ID_C), Constants.PAYMENT_BY_ID_C,
// w_id, d_id, h_amount, c_w_id, c_d_id, c_id, now);
// } else {
// m_queuedMessage = this.getClientHandle().callProcedure(new VerifyBasicCallback(TPCCSimulation.Transaction.PAYMENT, Constants.PAYMENT_BY_ID), Constants.PAYMENT_BY_ID,
// w_id, d_id, h_amount, c_w_id, c_d_id, c_id, now);
// }
// }
}
@Override
public void callPaymentByName(short w_id, byte d_id, double h_amount,
short c_w_id, byte c_d_id, String c_last, TimestampType now) throws IOException {
m_queuedMessage = this.getClientHandle().callProcedure(new VerifyBasicCallback(TPCCClient.Transaction.PAYMENT, TPCCConstants.PAYMENT_BY_NAME),
TPCCConstants.PAYMENT_BY_NAME,
w_id, d_id, h_amount, c_w_id, c_d_id, c_last, now);
// if (m_blockOnBackpressure) {
// if ((m_scaleParams.warehouses > 1) || (c_last != null)) {
// final VerifyBasicCallback cb = new VerifyBasicCallback();
// while(!this.getClientHandle().callProcedure(cb,
// Constants.PAYMENT_BY_NAME_W, w_id, d_id, h_amount,
// c_w_id, c_d_id, c_last, now)) {
// try {
// this.getClientHandle().backpressureBarrier();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// final VerifyBasicCallback cb2 = new VerifyBasicCallback(TPCCSimulation.Transaction.PAYMENT,
// Constants.PAYMENT_BY_NAME_C);
// while(!this.getClientHandle().callProcedure( cb2,
// Constants.PAYMENT_BY_NAME_C, w_id, d_id, h_amount,
// c_w_id, c_d_id, c_last, now)) {
// try {
// this.getClientHandle().backpressureBarrier();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }
// else {
// final VerifyBasicCallback cb = new VerifyBasicCallback(TPCCSimulation.Transaction.PAYMENT,
// Constants.PAYMENT_BY_ID);
// while(!this.getClientHandle().callProcedure( cb,
// Constants.PAYMENT_BY_ID, w_id,
// d_id, h_amount, c_w_id, c_d_id, c_last, now)) {
// try {
// this.getClientHandle().backpressureBarrier();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }
// } else {
// if ((m_scaleParams.warehouses > 1) || (c_last != null)) {
// this.getClientHandle().callProcedure(new VerifyBasicCallback(),
// Constants.PAYMENT_BY_NAME_W, w_id, d_id, h_amount,
// c_w_id, c_d_id, c_last, now);
// m_queuedMessage = this.getClientHandle().callProcedure(new VerifyBasicCallback(TPCCSimulation.Transaction.PAYMENT,
// Constants.PAYMENT_BY_NAME_C),
// Constants.PAYMENT_BY_NAME_C, w_id, d_id, h_amount,
// c_w_id, c_d_id, c_last, now);
// }
// else {
// m_queuedMessage = this.getClientHandle().callProcedure(new VerifyBasicCallback(TPCCSimulation.Transaction.PAYMENT,
// Constants.PAYMENT_BY_ID),
// Constants.PAYMENT_BY_ID, w_id,
// d_id, h_amount, c_w_id, c_d_id, c_last, now);
// }
// }
}
// StockLevel
class StockLevelCallback implements ProcedureCallback {
@Override
public void clientCallback(ClientResponse clientResponse) {
if (crash_on_error) {
boolean status = checkTransaction(TPCCConstants.STOCK_LEVEL,
clientResponse,
false,
false);
assert status;
}
incrementTransactionCounter(clientResponse, TPCCClient.Transaction.STOCK_LEVEL.ordinal());
}
}
@Override
public void callStockLevel(short w_id, byte d_id, int threshold) throws IOException {
final StockLevelCallback cb = new StockLevelCallback();
while (!this.getClientHandle().callProcedure( cb, TPCCConstants.STOCK_LEVEL,
w_id, d_id, threshold)) {
try {
this.getClientHandle().backpressureBarrier();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class DumpStatisticsCallback implements ProcedureCallback {
@Override
public void clientCallback(ClientResponse clientResponse) {
if (checkTransaction(null, clientResponse, false, false))
System.err.println(clientResponse.getResults()[0]);
}
}
public void dumpStatistics() throws IOException {
m_queuedMessage = this.getClientHandle().callProcedure(new DumpStatisticsCallback(),
"@Statistics", "procedure");
}
class ResetWarehouseCallback implements ProcedureCallback {
@Override
public void clientCallback(ClientResponse clientResponse) {
if (checkTransaction(null, clientResponse, false, false))
incrementTransactionCounter(clientResponse, TPCCClient.Transaction.RESET_WAREHOUSE.ordinal());
}
}
@Override
public void callResetWarehouse(long w_id, long districtsPerWarehouse,
long customersPerDistrict, long newOrdersPerDistrict)
throws IOException {
Client client = this.getClientHandle();
// HACK
if (client instanceof BlockingClient) {
client = ((BlockingClient)client).getClient();
}
m_queuedMessage = client.callProcedure(new ResetWarehouseCallback(),
TPCCConstants.RESET_WAREHOUSE, w_id, districtsPerWarehouse,
customersPerDistrict, newOrdersPerDistrict);
}
@Override
public void tickCallback(int counter) {
m_tpccSim.tick(counter);
LOG.debug("TICK: " + counter);
}
@Override
public void clearCallback() {
if (m_tpccConfig.reset_on_clear && this.getClientId() == 0) {
LOG.info("Reseting WAREHOUSE data");
for (int w_id = m_tpccConfig.first_warehouse; w_id < m_tpccConfig.num_warehouses; w_id++) {
try {
this.callResetWarehouse(w_id,
m_tpccSim.parameters.districtsPerWarehouse,
m_tpccSim.parameters.customersPerDistrict,
m_tpccSim.parameters.newOrdersPerDistrict);
} catch (IOException ex) {
throw new RuntimeException("Failed to reset warehouse #" + w_id, ex);
}
} // FOR
}
}
@Override
public void stopCallback() {
if (m_tpccConfig.neworder_skew_warehouse) {
LOG.info("WAREHOUSE DISTRIBUTION:\n" + m_tpccSim.getWarehouseZipf().getHistory());
}
}
@Override
public String[] getTransactionDisplayNames() {
String countDisplayNames[] = new String[TPCCClient.Transaction.values().length];
for (int ii = 0; ii < TPCCClient.Transaction.values().length; ii++) {
countDisplayNames[ii] = TPCCClient.Transaction.values()[ii].displayName;
}
return countDisplayNames;
}
}