/***************************************************************************
* Copyright (C) 2010 by H-Store Project *
* Brown University *
* Massachusetts Institute of Technology *
* Yale University *
* *
* 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 edu.brown.benchmark.markov;
import java.io.IOException;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import org.voltdb.client.ClientResponse;
import org.voltdb.client.NoConnectionsException;
import org.voltdb.client.ProcedureCallback;
import edu.brown.api.BenchmarkComponent;
import edu.brown.rand.AbstractRandomGenerator;
public class MarkovClient extends BenchmarkComponent {
// --------------------------------------------------------------------
// DATA MEMBERS
// --------------------------------------------------------------------
private int m_scalefactor = 1;
private final AbstractRandomGenerator m_rng;
/**
* If the lock is not null, then we will only submit txns one at a time
*/
private final Object blockingLock = new Object();
/**
* Number of Records Per Table
*/
private final Map<String, Long> table_sizes = new HashMap<String, Long>();
// --------------------------------------------------------------------
// TXN PARAMETER GENERATOR
// --------------------------------------------------------------------
public interface MarkovParamGenerator {
public Object[] generate(AbstractRandomGenerator rng, Map<String, Long> table_sizes);
}
// --------------------------------------------------------------------
// BENCHMARK CONTROLLER REQUIREMENTS
// --------------------------------------------------------------------
public static enum Transaction {
DoneAtPartition(MarkovConstants.FREQUENCY_DONE_AT_PARTITON, new MarkovParamGenerator() {
@Override
public Object[] generate(AbstractRandomGenerator rng, Map<String, Long> tableSizes) {
Object params[] = new Object[] { rng.number(0, tableSizes.get(MarkovConstants.TABLENAME_TABLEA).intValue()), // A_ID
rng.number(0, 1 << 30), // VALUE
};
return (params);
}
}), ExecutionTime(MarkovConstants.FREQUENCY_EXECUTION_TIME, new MarkovParamGenerator() {
@Override
public Object[] generate(AbstractRandomGenerator rng, Map<String, Long> tableSizes) {
Object params[] = new Object[] { rng.number(0, tableSizes.get(MarkovConstants.TABLENAME_TABLEA).intValue()), // A_ID
};
return (params);
}
}), SinglePartitionWrite(MarkovConstants.FREQUENCY_SINGLE_PARTITION_WRITE, new MarkovParamGenerator() {
@Override
public Object[] generate(AbstractRandomGenerator rng, Map<String, Long> tableSizes) {
Object params[] = new Object[] {
// TODO
};
return (params);
}
}), SinglePartitionRead(MarkovConstants.FREQUENCY_SINGLE_PARTITION_READ, new MarkovParamGenerator() {
@Override
public Object[] generate(AbstractRandomGenerator rng, Map<String, Long> tableSizes) {
Object params[] = new Object[] {
// TODO
};
return (params);
}
}), MultiPartitionWrite(MarkovConstants.FREQUENCY_MULTI_PARTITION_WRITE, new MarkovParamGenerator() {
@Override
public Object[] generate(AbstractRandomGenerator rng, Map<String, Long> tableSizes) {
Object params[] = new Object[] {
// TODO
};
return (params);
}
}), MultiPartitionRead(MarkovConstants.FREQUENCY_MULTI_PARTITION_READ, new MarkovParamGenerator() {
@Override
public Object[] generate(AbstractRandomGenerator rng, Map<String, Long> tableSizes) {
Object params[] = new Object[] {
// TODO
};
return (params);
}
}), UserAbort(MarkovConstants.FREQUENCY_USER_ABORT, new MarkovParamGenerator() {
@Override
public Object[] generate(AbstractRandomGenerator rng, Map<String, Long> tableSizes) {
Object params[] = new Object[] {
// TODO
};
return (params);
}
});
private Transaction(int weight, MarkovParamGenerator generator) {
this.weight = weight;
this.generator = generator;
MarkovClient.TOTAL_WEIGHT += this.weight;
}
protected static final Map<Integer, Transaction> idx_lookup = new HashMap<Integer, Transaction>();
static {
for (Transaction vt : EnumSet.allOf(Transaction.class)) {
Transaction.idx_lookup.put(vt.ordinal(), vt);
}
}
public static Transaction get(int idx) {
assert (idx >= 0);
Transaction ret = Transaction.idx_lookup.get(idx);
return (ret);
}
public Object[] params(AbstractRandomGenerator rng, Map<String, Long> table_sizes) {
return (this.generator.generate(rng, table_sizes));
}
public int getWeight() {
return weight;
}
private final MarkovParamGenerator generator;
private final int weight;
};
private static int TOTAL_WEIGHT;
/**
* Transaction Execution Weights
*/
private static final MarkovClient.Transaction XACT_WEIGHTS[] = new MarkovClient.Transaction[100];
static {
int i = 0;
int sum = 0;
for (Transaction t : MarkovClient.Transaction.values()) {
for (int j = 0; j < t.weight; j++, i++) {
XACT_WEIGHTS[i] = t;
} // FOR
sum += t.weight;
} // FOR
assert (100 == sum);
}
public static void main(String args[]) {
edu.brown.api.BenchmarkComponent.main(MarkovClient.class, args, false);
}
/**
* Constructor
*
* @param args
*/
public MarkovClient(String[] args) {
super(args);
// Sanity check
assert (MarkovClient.TOTAL_WEIGHT == 100);
int seed = 0;
String randGenClassName = RandomGenerator.class.getName();
String randGenProfilePath = null;
for (String arg : args) {
String[] parts = arg.split("=", 2);
if (parts.length == 1)
continue;
if (parts[1].startsWith("${"))
continue;
if (parts[0].equals("scalefactor")) {
m_scalefactor = Integer.parseInt(parts[1]);
} else if (parts[0].equals("randomseed")) {
seed = Integer.parseInt(parts[1]);
} else if (parts[0].equals("randomgenerator")) {
randGenClassName = parts[1];
} else if (parts[0].equals("randomprofile")) {
randGenProfilePath = parts[1];
}
} // FOR
AbstractRandomGenerator rng = null;
try {
rng = AbstractRandomGenerator.factory(randGenClassName, seed);
if (randGenProfilePath != null)
rng.loadProfile(randGenProfilePath);
} catch (Exception ex) {
ex.printStackTrace();
System.exit(1);
}
m_rng = rng;
// Number of Records Per Table
this.table_sizes.put(MarkovConstants.TABLENAME_TABLEA, MarkovConstants.TABLESIZE_TABLEA / m_scalefactor);
this.table_sizes.put(MarkovConstants.TABLENAME_TABLEB, MarkovConstants.TABLESIZE_TABLEB / m_scalefactor);
this.table_sizes.put(MarkovConstants.TABLENAME_TABLEC, MarkovConstants.TABLESIZE_TABLEC / m_scalefactor);
this.table_sizes.put(MarkovConstants.TABLENAME_TABLED, MarkovConstants.TABLESIZE_TABLED / m_scalefactor);
for (String tableName : MarkovConstants.TABLENAMES) {
assert (this.table_sizes.containsKey(tableName)) : "Missing table size entry for " + tableName;
} // FOR
}
@Override
public String[] getTransactionDisplayNames() {
String names[] = new String[Transaction.values().length];
for (int i = 0; i < names.length; i++) {
names[i] = Transaction.values()[i].name();
}
return names;
}
@Override
public void runLoop() {
try {
while (true) {
MarkovClient.Transaction txn_type = XACT_WEIGHTS[m_rng.number(0, 99)];
assert (txn_type != null);
Object params[] = txn_type.params(m_rng, this.table_sizes);
this.getClientHandle().callProcedure(new MarkovCallback(txn_type), txn_type.name(), params);
this.getClientHandle().backpressureBarrier();
} // WHILE
} catch (NoConnectionsException e) {
/*
* Client has no clean mechanism for terminating with the DB.
*/
return;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
/*
* At shutdown an IOException is thrown for every connection to the
* DB that is lost Ignore the exception here in order to not get
* spammed, but will miss lost connections at runtime
*/
}
}
/**
* Basic Callback Class
*/
protected class MarkovCallback implements ProcedureCallback {
private final Transaction txn;
public MarkovCallback(Transaction txn) {
super();
this.txn = txn;
}
@Override
public void clientCallback(ClientResponse clientResponse) {
incrementTransactionCounter(clientResponse, this.txn.ordinal());
if (MarkovClient.this.blockingLock != null) {
synchronized (MarkovClient.this.blockingLock) {
MarkovClient.this.blockingLock.notifyAll();
}
}
}
} // END CLASS
}