package edu.brown.workload.filters;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.log4j.Logger;
import org.voltdb.catalog.CatalogType;
import org.voltdb.catalog.Procedure;
import edu.brown.statistics.ObjectHistogram;
import edu.brown.workload.AbstractTraceElement;
import edu.brown.workload.TransactionTrace;
/**
* This filter allows uniformly samples procedures from the workload
* @author pavlo
*/
public class SamplingFilter extends Filter {
private static final Logger LOG = Logger.getLogger(SamplingFilter.class);
/**
* Procedure Name -> Total # of Txns Wanted
*/
private final Map<String, Integer> proc_includes;
private final ObjectHistogram<String> proc_histogram;
private final Map<String, AtomicInteger> proc_counters = new HashMap<String, AtomicInteger>();
private final Map<String, Integer> proc_rates = new HashMap<String, Integer>();
/**
*
* @param proc_includes
* @param proc_histogram
*/
public SamplingFilter(Map<String, Integer> proc_includes, ObjectHistogram<String> proc_histogram) {
final boolean debug = LOG.isDebugEnabled();
this.proc_includes = proc_includes;
this.proc_histogram = proc_histogram;
// For each procedure, figure out their sampling rate
for (Object o : proc_histogram.values()) {
String proc_name = null;
if (o instanceof Procedure) {
proc_name = ((Procedure)o).getName();
} else {
proc_name = (String)o;
}
Integer needed = this.proc_includes.get(proc_name);
String debug_msg = "";
if (needed != null) {
long total = this.proc_histogram.get(proc_name, 0);
int rate = (needed > 0 && needed < total ? Math.round(total / needed) : 1);
if (needed == 0) rate = 0;
this.proc_counters.put(proc_name, new AtomicInteger(0));
this.proc_rates.put(proc_name, rate);
if (debug) {
if (rate == 0) debug_msg = "NONE";
else debug_msg = (rate == 1 ? "ALL" : "Every " + rate) +
" [total=" + total + "]";
}
} else {
if (debug) debug_msg = "SKIPPED";
}
if (debug) LOG.debug(String.format("%-20s %s", proc_name+":", debug_msg));
} // FOR
}
@Override
public String debugImpl() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName())
.append("[");
String add = "";
for (Entry<String, AtomicInteger> e : this.proc_counters.entrySet()) {
int proc_total = this.proc_includes.get(e.getKey());
sb.append(String.format("%s%s=%d/", add, e.getKey(), e.getValue().get()));
sb.append(proc_total >= 0 ? proc_total : "UNLIMITED");
add = ", ";
} // FOR
sb.append("]");
return (sb.toString());
}
@Override
protected FilterResult filter(AbstractTraceElement<? extends CatalogType> element) {
FilterResult result = FilterResult.ALLOW;
if (element instanceof TransactionTrace) {
final boolean trace = LOG.isTraceEnabled();
final String proc_name = element.getCatalogItemName();
final AtomicInteger proc_counter = this.proc_counters.get(proc_name);
if (proc_counter == null) {
if (trace) LOG.trace("Procedure " + proc_name + " is not included in whitelist. Skipping...");
result = FilterResult.SKIP;
} else {
int proc_idx = proc_counter.getAndIncrement();
int proc_rate = this.proc_rates.get(proc_name);
result = (proc_rate != 0 && proc_idx % proc_rate == 0 ? FilterResult.ALLOW : FilterResult.SKIP);
}
}
return (result);
}
@Override
protected void resetImpl() {
for (AtomicInteger proc_counter : this.proc_counters.values()) {
proc_counter.set(0);
} // FOR
}
}