package edu.brown.hstore.estimators.markov;
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.voltdb.CatalogContext;
import edu.brown.graphs.GraphvizExport;
import edu.brown.hstore.conf.HStoreConf;
import edu.brown.hstore.estimators.Estimate;
import edu.brown.hstore.estimators.EstimatorState;
import edu.brown.hstore.estimators.EstimatorUtil;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.markov.MarkovEdge;
import edu.brown.markov.MarkovGraph;
import edu.brown.markov.MarkovUtil;
import edu.brown.markov.MarkovVertex;
import edu.brown.pools.TypedPoolableObjectFactory;
import edu.brown.utils.PartitionSet;
import edu.brown.utils.StringUtil;
/**
* The current state of a transaction
*/
public final class MarkovEstimatorState extends EstimatorState {
private static final Logger LOG = Logger.getLogger(MarkovEstimatorState.class);
private static final LoggerBoolean debug = new LoggerBoolean();
private static final LoggerBoolean trace = new LoggerBoolean();
static {
LoggerUtil.attachObserver(LOG, debug, trace);
}
protected final List<MarkovVertex> actual_path = new ArrayList<MarkovVertex>();
protected final List<MarkovEdge> actual_path_edges = new ArrayList<MarkovEdge>();
private MarkovGraph markov;
private MarkovVertex current;
private Object args[];
protected final PartitionSet cache_past_partitions = new PartitionSet();
protected final PartitionSet cache_last_partitions = new PartitionSet();
/**
* State Factory
*/
public static class Factory extends TypedPoolableObjectFactory<MarkovEstimatorState> {
private final CatalogContext catalogContext;
public Factory(CatalogContext catalogContext) {
super(HStoreConf.singleton().site.pool_profiling);
this.catalogContext = catalogContext;
}
@Override
public MarkovEstimatorState makeObjectImpl() throws Exception {
return (new MarkovEstimatorState(this.catalogContext));
}
};
/**
* Constructor
*/
private MarkovEstimatorState(CatalogContext catalogContext) {
super(catalogContext);
}
public void init(Long txn_id, int base_partition, MarkovGraph markov, Object args[], long start_time) {
this.markov = markov;
this.args = args;
this.setCurrent(markov.getStartVertex(), null);
super.init(txn_id, base_partition, start_time);
}
@Override
public boolean isInitialized() {
return (this.markov != null && super.isInitialized());
}
@Override
public void finish() {
this.markov.incrementTransasctionCount();
this.actual_path.clear();
this.actual_path_edges.clear();
this.current = null;
this.markov = null;
this.args = null;
super.finish();
}
/**
* Get the next Estimate object for this State
* This will not add the Estimate to this the State's list
* That must be done separately.
* @return
*/
protected MarkovEstimate createNextEstimate(MarkovVertex v, boolean initial) {
assert(v != null);
MarkovEstimate next = new MarkovEstimate(this.catalogContext);
int batchId = (initial ? EstimatorUtil.INITIAL_ESTIMATE_BATCH : this.getEstimateCount());
next.init(v, batchId);
return (next);
}
@Override
protected void addInitialEstimate(Estimate estimate) {
super.addInitialEstimate(estimate);
}
@Override
protected Estimate addEstimate(Estimate est) {
return super.addEstimate(est);
}
@Override
protected void shouldAllowUpdates(boolean enable) {
super.shouldAllowUpdates(enable);
}
// ----------------------------------------------------------------------------
// MARKOV GRAPH METHODS
// ----------------------------------------------------------------------------
public Object[] getProcedureParameters() {
return (this.args);
}
public MarkovGraph getMarkovGraph() {
return (this.markov);
}
/**
* Get the actual path that the txn took through the MarkovGraph
* This is only updated if transaction updates are enabled.
* @return
*/
public List<MarkovVertex> getActualPath() {
return (this.actual_path);
}
public MarkovVertex getCurrent() {
return (this.current);
}
/**
* Set the current vertex for this transaction and update the actual path
* @param current
*/
public void setCurrent(MarkovVertex current, MarkovEdge e) {
if (this.current != null) assert(this.current.equals(current) == false);
this.actual_path.add(current);
if (e != null) this.actual_path_edges.add(e);
this.current = current;
}
/**
* Debug method to dump out the Markov graph to a Graphviz file
* Returns the path to the file
*/
public File dumpMarkovGraph() {
List<MarkovEdge> initialPath = this.markov.getPath(((MarkovEstimate)this.getInitialEstimate()).getMarkovPath());
List<MarkovEdge> actualPath = this.markov.getPath(this.actual_path);
GraphvizExport<MarkovVertex, MarkovEdge> gv = MarkovUtil.exportGraphviz(this.markov, true, initialPath);
gv.highlightPath(actualPath, "blue");
return gv.writeToTempFile(this.markov.getProcedure());
}
@Override
public String toString() {
Map<String, Object> m0 = new LinkedHashMap<String, Object>();
m0.put("TransactionId", this.txn_id);
m0.put("Procedure", (this.markov != null ? this.markov.getProcedure().getName() : null));
m0.put("MarkovGraph Id", (this.markov != null ? this.markov.getGraphId() : null));
Map<String, Object> m1 = new LinkedHashMap<String, Object>();
m1.put("Initial Estimate", this.getInitialEstimate());
Map<String, Object> m2 = new LinkedHashMap<String, Object>();
m2.put("Actual Partitions", this.getTouchedPartitions());
m2.put("Current Estimate", (this.current != null ? this.current.debug() : null));
return StringUtil.formatMaps(m0, m1, m2);
}
} // END CLASS