/**
*
*/
package edu.brown.hstore.util;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.voltdb.CatalogContext;
import org.voltdb.catalog.Procedure;
import edu.brown.statistics.FastIntHistogram;
import edu.brown.statistics.Histogram;
import edu.brown.statistics.ObjectHistogram;
import edu.brown.utils.StringUtil;
/**
* Internal counters for how transactions were executed.
* These are updated in various parts of the txn's lifetime.
* TODO: This should be better integrated into the Statistics framework.
*/
public enum TransactionCounter {
/** The number of transaction requests that have arrived at this site */
RECEIVED,
/** */
REJECTED,
/** Of the the received transactions, the number that we had to send somewhere else */
REDIRECTED,
/** The number of transactions that we executed locally */
EXECUTED,
/** The number of transactions that were completed (committed or aborted) */
COMPLETED,
/** Of the locally executed transactions, how many were single-partitioned */
SINGLE_PARTITION,
/** Of the locally executed transactions, how many were multi-partitioned */
MULTI_PARTITION,
/** Of the locally executed transactions, how many were multi-site */
MULTI_SITE,
/** Speculative Execution **/
SPECULATIVE,
/** The number of sysprocs that we executed */
SYSPROCS,
/** The number of transactions that were mispredicted (and thus re-executed) */
MISPREDICTED,
/** Of the locally executed transactions, how many were aborted by the user */
ABORTED,
/** The number of transactions that were unexpectedly aborted (e.g., because of an assert) */
ABORT_UNEXPECTED,
/** The number of transactions that were gracefully aborted */
ABORT_GRACEFUL,
/** The number of transactions that were aborted while being speculatively executed */
ABORT_SPECULATIVE,
/** The number of transactions that had to be restarted (non-speculative txns) */
RESTARTED,
/** The number of transactions that were aborted because they tried to access evicted data */
EVICTEDACCESS,
/** No undo buffers! Naked transactions! */
NO_UNDO,
/** The number of transactions that were sent out with prefetch queries */
PREFETCH,
// --------------------------------------------------------
// Speculative Execution Stall Points
// --------------------------------------------------------
SPECULATIVE_SP1_IDLE,
SPECULATIVE_SP1_LOCAL,
SPECULATIVE_SP2,
SPECULATIVE_SP3_BEFORE,
SPECULATIVE_SP3_AFTER,
SPECULATIVE_SP4_LOCAL,
SPECULATIVE_SP4_REMOTE,
;
private final FastIntHistogram h = new FastIntHistogram();
private final String name;
private TransactionCounter() {
this.name = StringUtil.title(this.name().replace("_", "-"));
}
@Override
public String toString() {
return (this.name);
}
public Histogram<Procedure> getHistogram(CatalogContext catalogContext) {
Histogram<Procedure> procHistogram = new ObjectHistogram<Procedure>();
for (int procId : this.h.fastValues()) {
Procedure catalog_proc = catalogContext.getProcedureById(procId);
procHistogram.put(catalog_proc, this.h.get(procId));
}
return (procHistogram);
}
public int get() {
return ((int)this.h.getSampleCount());
}
public Long get(Procedure catalog_proc) {
long val = this.h.get(catalog_proc.getId());
return (val < 0 ? null : val);
}
public int inc(Procedure catalog_proc) {
synchronized (catalog_proc) {
this.h.put(catalog_proc.getId());
} // SYNCH
return (this.get());
}
public int dec(Procedure catalog_proc) {
synchronized (catalog_proc) {
this.h.dec(catalog_proc.getId());
} // SYNCH
return (this.get());
}
public void clear() {
this.h.clear();
}
public static Collection<Procedure> getAllProcedures(CatalogContext catalogContext) {
Set<Procedure> ret = new TreeSet<Procedure>();
for (TransactionCounter tc : TransactionCounter.values()) {
for (int procId : tc.h.fastValues()) {
Procedure catalog_proc = catalogContext.getProcedureById(procId);
ret.add(catalog_proc);
} // FOR
} // fOR
return (ret);
}
public Double ratio() {
int total = -1;
int cnt = this.get();
switch (this) {
case SINGLE_PARTITION:
case MULTI_PARTITION:
case MULTI_SITE:
if (this.get() == 0) return (null);
total = SINGLE_PARTITION.get() + MULTI_PARTITION.get();
break;
case SPECULATIVE:
total = SINGLE_PARTITION.get();
break;
case NO_UNDO:
total = EXECUTED.get();
break;
case SYSPROCS:
case ABORTED:
case ABORT_UNEXPECTED:
case ABORT_GRACEFUL:
case ABORT_SPECULATIVE:
case RESTARTED:
case MISPREDICTED:
total = EXECUTED.get() - SYSPROCS.get();
break;
case REDIRECTED:
case REJECTED:
case RECEIVED:
case EXECUTED:
case PREFETCH:
total = RECEIVED.get();
break;
case SPECULATIVE_SP1_IDLE:
case SPECULATIVE_SP1_LOCAL:
case SPECULATIVE_SP2:
case SPECULATIVE_SP3_AFTER:
case SPECULATIVE_SP3_BEFORE:
case SPECULATIVE_SP4_LOCAL:
case SPECULATIVE_SP4_REMOTE:
total = SPECULATIVE.get();
break;
case COMPLETED:
return (null);
default:
assert(false) :
String.format("Unexpected %s.%s", this.getClass().getSimpleName(), this);
}
return (total == 0 ? null : cnt / (double)total);
}
protected static final Map<String, TransactionCounter> name_lookup = new HashMap<String, TransactionCounter>();
static {
for (TransactionCounter vt : EnumSet.allOf(TransactionCounter.class)) {
TransactionCounter.name_lookup.put(vt.name().toLowerCase(), vt);
}
}
public static TransactionCounter get(String name) {
return TransactionCounter.name_lookup.get(name.toLowerCase());
}
public static void resetAll(CatalogContext catalogContext) {
for (TransactionCounter tc : EnumSet.allOf(TransactionCounter.class)) {
tc.clear();
tc.h.ensureSize(catalogContext.procedures.size());
} // FOR
}
public static String debug() {
Map<String, Integer> m = new LinkedHashMap<String, Integer>();
for (TransactionCounter tc : EnumSet.allOf(TransactionCounter.class)) {
m.put(tc.name(), tc.get());
} // FOR
return (StringUtil.formatMaps(m));
}
}