package edu.brown.api.results;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.voltdb.SysProcSelector;
import org.voltdb.VoltSystemProcedure;
import org.voltdb.VoltTable;
import org.voltdb.VoltTable.ColumnInfo;
import org.voltdb.VoltType;
import org.voltdb.client.Client;
import org.voltdb.client.ClientResponse;
import org.voltdb.client.ProcedureCallback;
import org.voltdb.sysprocs.Statistics;
import org.voltdb.utils.VoltTableUtil;
import edu.brown.api.BenchmarkInterest;
import edu.brown.hstore.Hstoreservice.Status;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
/**
* Poll the system at every interval to collect table information
*
*/
public class TableStatsPrinter implements BenchmarkInterest {
private static final Logger LOG = Logger.getLogger(TableStatsPrinter.class);
private static final LoggerBoolean debug = new LoggerBoolean(LOG.isDebugEnabled());
static {
LoggerUtil.attachObserver(LOG, debug);
}
public static final ColumnInfo COLUMNS[] = {
new ColumnInfo("INTERVAL", VoltType.INTEGER),
new ColumnInfo("ELAPSED", VoltType.BIGINT),
new ColumnInfo("TIMESTAMP", VoltType.BIGINT),
new ColumnInfo("HOST_ID", VoltType.INTEGER),
new ColumnInfo("HOSTNAME", VoltType.STRING),
new ColumnInfo("SITE_ID", VoltType.INTEGER),
new ColumnInfo("PARTITION_ID", VoltType.INTEGER),
new ColumnInfo("TABLE_NAME", VoltType.STRING),
new ColumnInfo("TABLE_TYPE", VoltType.STRING),
// ACTIVE
new ColumnInfo("TUPLE_COUNT", VoltType.INTEGER),
new ColumnInfo("TUPLE_ACCESSES", VoltType.BIGINT),
new ColumnInfo("TUPLE_ALLOCATED_MEMORY", VoltType.BIGINT),
new ColumnInfo("TUPLE_DATA_MEMORY", VoltType.BIGINT),
new ColumnInfo("STRING_DATA_MEMORY", VoltType.BIGINT),
new ColumnInfo("ANTICACHE_TUPLES_EVICTED", VoltType.INTEGER),
new ColumnInfo("ANTICACHE_BLOCKS_EVICTED", VoltType.INTEGER),
new ColumnInfo("ANTICACHE_BYTES_EVICTED", VoltType.BIGINT),
// GLOBAL WRITTEN
new ColumnInfo("ANTICACHE_TUPLES_WRITTEN", VoltType.INTEGER),
new ColumnInfo("ANTICACHE_BLOCKS_WRITTEN", VoltType.INTEGER),
new ColumnInfo("ANTICACHE_BYTES_WRITTEN", VoltType.BIGINT),
// GLOBAL READ
new ColumnInfo("ANTICACHE_TUPLES_READ", VoltType.INTEGER),
new ColumnInfo("ANTICACHE_BLOCKS_READ", VoltType.INTEGER),
new ColumnInfo("ANTICACHE_BYTES_READ", VoltType.BIGINT),
};
private final List<Object[]> results = new ArrayList<Object[]>();
private final Client client;
private final File outputPath;
private boolean stop = false;
private int intervalCounter = 0;
public TableStatsPrinter(Client client, File outputPath) {
this.client = client;
this.outputPath = outputPath;
}
@Override
public void stop() {
this.stop = true;
}
@Override
public String formatFinalResults(BenchmarkResults br) {
if (this.stop) return (null);
VoltTable vt = new VoltTable(COLUMNS);
for (Object row[] : this.results) {
vt.addRow(row);
}
try {
FileWriter writer = new FileWriter(this.outputPath);
VoltTableUtil.csv(writer, vt, true);
writer.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
LOG.info("Wrote CSV table stats periodically to '" + this.outputPath.getAbsolutePath() + "'");
return (null);
}
@Override
public void benchmarkHasUpdated(final BenchmarkResults br) {
if (this.stop) return;
final int interval = this.intervalCounter++;
// HACK: Skip every other interval
if (interval % 2 != 0) return;
ProcedureCallback callback = new ProcedureCallback() {
@Override
public void clientCallback(ClientResponse clientResponse) {
if (clientResponse.getStatus() != Status.OK) {
LOG.warn("Failed to get table stats", clientResponse.getException());
return;
}
if (debug.val)
LOG.debug("Updating table stats information [interval=" + interval + "]");
VoltTable vt = clientResponse.getResults()[0];
// CALCULATE DELAY
long timestamp = System.currentTimeMillis();
long delay = timestamp - br.getLastTimestamp();
while (vt.advanceRow()) {
Object row[] = new Object[COLUMNS.length];
int idx = 0;
row[idx++] = interval;
row[idx++] = br.getElapsedTime() + delay;
row[idx++] = timestamp;
while(idx < COLUMNS.length) {
row[idx] = vt.get(idx-2, COLUMNS[idx].getType());
idx++;
}
TableStatsPrinter.this.results.add(row);
};
}
};
String procName = VoltSystemProcedure.procCallName(Statistics.class);
Object params[] = { SysProcSelector.TABLE.name(), 0 };
try {
if (debug.val) LOG.debug("Retrieving memory stats from cluster");
boolean result = this.client.callProcedure(callback, procName, params);
assert(result) : "Failed to queue " + procName + " request";
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
@Override
public void markEvictionStart() {
// NOTHING
}
@Override
public void markEvictionStop() {
// NOTHING
}
}