Package edu.brown.hstore.estimators.markov

Source Code of edu.brown.hstore.estimators.markov.MarkovPathEstimator$Factory

package edu.brown.hstore.estimators.markov;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.log4j.Logger;
import org.voltdb.CatalogContext;
import org.voltdb.catalog.ProcParameter;
import org.voltdb.catalog.Statement;
import org.voltdb.catalog.StmtParameter;
import org.voltdb.types.QueryType;

import edu.brown.catalog.CatalogUtil;
import edu.brown.catalog.special.CountedStatement;
import edu.brown.graphs.VertexTreeWalker;
import edu.brown.hstore.HStoreConstants;
import edu.brown.hstore.conf.HStoreConf;
import edu.brown.hstore.estimators.EstimatorUtil;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.mappings.ParameterMapping;
import edu.brown.mappings.ParameterMappingsSet;
import edu.brown.markov.MarkovEdge;
import edu.brown.markov.MarkovGraph;
import edu.brown.markov.MarkovVertex;
import edu.brown.pools.TypedPoolableObjectFactory;
import edu.brown.utils.CollectionUtil;
import edu.brown.utils.PartitionEstimator;
import edu.brown.utils.PartitionSet;
import edu.brown.utils.StringUtil;
import edu.uci.ics.jung.graph.util.EdgeType;

/**
* Path Estimator for MarkovEstimator
* @author pavlo
*/
public class MarkovPathEstimator extends VertexTreeWalker<MarkovVertex, MarkovEdge> {
    private static final Logger LOG = Logger.getLogger(MarkovPathEstimator.class);
    private static final LoggerBoolean debug = new LoggerBoolean();
    private static final LoggerBoolean trace = new LoggerBoolean();
    static {
        LoggerUtil.attachObserver(LOG, debug, trace);
    }
   
    /**
     *
     * @author pavlo
     */
    public static class Factory extends TypedPoolableObjectFactory<MarkovPathEstimator> {
        private final CatalogContext catalogContext;
        private final PartitionEstimator p_estimator;
       
        public Factory(CatalogContext catalogContext, PartitionEstimator p_estimator) {
            super(HStoreConf.singleton().site.pool_profiling);
            this.catalogContext = catalogContext;
            this.p_estimator = p_estimator;
        }
        @Override
        public MarkovPathEstimator makeObjectImpl() throws Exception {
            return (new MarkovPathEstimator(this.catalogContext, this.p_estimator));
        }
    };

    // ----------------------------------------------------------------------------
    // INVOCATION MEMBERS
    // ----------------------------------------------------------------------------
   
    private MarkovEstimate estimate;
    private int base_partition;
    private Object procParams[];

    private final int num_partitions;
    private final ParameterMappingsSet allMappings;
    private final PartitionEstimator p_estimator;
   
    /**
     * If this flag is set to true, then we will always try to go to the end
     * This means that if we don't have an edge to the vertex that we're pretty sure we
     * want to take, we'll just pick the edge from the one that is available that has
     * the highest probability.
     */
    private boolean force_traversal = false;
   
    /**
     * These are the vertices that we weren't sure about.
     * This only gets populated when force_traversal is set to true.
     * This is primarily used for debugging.
     */
    private Set<MarkovVertex> forced_vertices;
   
    /**
     * If this flag is set to true, then the estimator will be allowed to create vertices
     * that it knows that it needs to transition to but do not exist.
     */
    private boolean learning_enabled = false;
   
    /**
     * These are the vertices that we weren't sure about.
     * This only gets populated when force_traversal is set to true.
     * This is primarily used for debugging.
     */
    private Set<MarkovVertex> created_vertices;

    // ----------------------------------------------------------------------------
    // TEMPORARY TRAVERSAL MEMBERS
    // ----------------------------------------------------------------------------
   
    private final PartitionSet stmt_partitions = new PartitionSet();
    private final PartitionSet past_partitions = new PartitionSet();
    private final SortedSet<MarkovEdge> candidate_edges = new TreeSet<MarkovEdge>();
    private final Collection<CountedStatement> next_statements = new HashSet<CountedStatement>();
   
    // ----------------------------------------------------------------------------
    // CONSTRUCTORS
    // ----------------------------------------------------------------------------

    /**
     * Constructor
     * @param catalogContext
     * @param p_estimator
     */
    public MarkovPathEstimator(CatalogContext catalogContext, PartitionEstimator p_estimator) {
        super();
        this.num_partitions = catalogContext.numberOfPartitions;
        this.p_estimator = p_estimator;
        this.allMappings = catalogContext.paramMappings;
        assert(this.allMappings != null);
    }

    /**
     * Initialize this MarkovPathEstimator for a new traversal run.
     * @param markov The MarkovGraph to use for this txn.
     * @param estimate The MarkovEstimate to populate while we traverse the model.
     * @param procParams The txn's Procedure input parameters
     * @param base_partition The txn's bases partition.
     * @return
     */
    public MarkovPathEstimator init(MarkovGraph markov, MarkovEstimate estimate, Object procParams[], int base_partition) {
        this.init(markov, TraverseOrder.DEPTH, Direction.FORWARD);
        this.estimate = estimate;
        this.base_partition = base_partition;
        this.procParams = procParams;
        assert(this.base_partition >= 0);

        if (trace.val) {
            Map<String, Object> m = new LinkedHashMap<String, Object>();
            m.put("Procedure", markov.getProcedure().getName());
            m.put("Base Partition", this.base_partition);
            m.put("# of Partitions", this.num_partitions);
            m.put("Parameters", StringUtil.toString(this.procParams, true, true));
            m.put("Force Traversal", this.force_traversal);
            m.put("Auto Learning", this.learning_enabled);
           
            LOG.trace(String.format("Initialized %s [hashCode=%d]\n%s",
                      this.getClass().getSimpleName(), this.hashCode(),
                      StringUtil.formatMaps(m)));
        }
        return (this);
    }
   
    @Override
    public boolean isInitialized() {
        return (this.estimate != null);
    }
   
    @Override
    public void finish() {
        if (debug.val)
            LOG.debug(String.format("Cleaning up MarkovPathEstimator [hashCode=%d]",
                      this.hashCode()));
        super.finish();
        this.estimate = null;
        this.past_partitions.clear();
        this.stmt_partitions.clear();
        if (this.forced_vertices != null) this.forced_vertices.clear();
        if (this.created_vertices != null) this.created_vertices.clear();
    }
   
    /**
     * Forcing traversal means that we will keep estimating the
     * path even if the next MarkovVertex that the txn needs to transition
     * to is not in the MarkovGraph.
     * @param flag
     */
    public void setForceTraversal(boolean flag) {
        this.force_traversal = flag;
    }
    /**
     * Can be null.
     * @return
     */
    protected Collection<MarkovVertex> getForcedVertices() {
        return this.forced_vertices;
    }
   
    /**
     * Setting this flag to true means that the MarkovPathEstimator is allowed
     * to create vertices that it knows that it needs to transition to but do not
     * exist yet in the graph. Note that this is done without any synchronization, so
     * it is up to whomever is using use to make sure that what we're doing is thread safe.
     * @param flag
     */
    public void setLearningEnabled(boolean flag) {
        this.learning_enabled = flag;
    }
    /**
     * Can be null
     * @return
     */
    protected Collection<MarkovVertex> getCreatedVertices() {
        return this.created_vertices;
    }

    // ----------------------------------------------------------------------------
    // TRAVERSAL METHODS
    // ----------------------------------------------------------------------------
   
    /**
     * This is the main part of where we figure out the path that this transaction will take
     */
    protected void populate_children(Children<MarkovVertex> children, MarkovVertex element) {
//        if (element.isAbortVertex() || element.isCommitVertex()) {
//            return;
//        }
       
        // Initialize temporary data
        this.candidate_edges.clear();
        this.next_statements.clear();
        this.past_partitions.addAll(element.getPartitions());
       
        if (trace.val) LOG.trace("Current Vertex: " + element);
        Statement cur_catalog_stmt = element.getCatalogItem();
        int cur_catalog_stmt_index = element.getQueryCounter();
        MarkovGraph markov = (MarkovGraph)this.getGraph();
       
        // At our current vertex we need to gather all of our neighbors
        // and get unique Statements that we could be executing next
        Collection<MarkovVertex> next_vertices = markov.getSuccessors(element);
        if (next_vertices == null || next_vertices.isEmpty()) {
            if (debug.val) LOG.debug("No succesors were found for " + element + ". Halting traversal");
            return;
        }
        if (trace.val) LOG.trace("Successors: " + next_vertices);
       
        // Step #1
        // Get all of the unique Statement+StatementInstanceIndex pairs for the vertices
        // that are adjacent to our current vertex
        for (MarkovVertex next : next_vertices) {
            Statement next_catalog_stmt = next.getCatalogItem();
            int next_catalog_stmt_index = next.getQueryCounter();
           
            // Sanity Check: If this vertex is the same Statement as the current vertex,
            // then its instance counter must be greater than the current vertex's counter
            if (next_catalog_stmt.equals(cur_catalog_stmt)) {
                if (next_catalog_stmt_index <= cur_catalog_stmt_index) {
                    LOG.error("CURRENT: " + element + " [commit=" + element.isCommitVertex() + "]");
                    LOG.error("NEXT: " + next + " [commit=" + next.isCommitVertex() + "]");
                }
                assert(next_catalog_stmt_index > cur_catalog_stmt_index) :
                    String.format("%s[#%d] > %s[#%d]",
                                  next_catalog_stmt.fullName(), next_catalog_stmt_index,
                                  cur_catalog_stmt.fullName(), cur_catalog_stmt_index);
            }
           
            // Check whether it's COMMIT/ABORT
            if (next.isCommitVertex() || next.isAbortVertex()) {
                MarkovEdge candidate = markov.findEdge(element, next);
                assert(candidate != null);
                this.candidate_edges.add(candidate);
            } else {
                this.next_statements.add(next.getCountedStatement());
            }
        } // FOR

        // Now for the unique set of Statement+StatementIndex pairs, figure out which partitions
        // the queries will go to.
        MarkovEdge candidate_edge;
        for (CountedStatement cstmt : this.next_statements) {
            Statement catalog_stmt = cstmt.statement;
            Integer catalog_stmt_index = cstmt.counter;
            if (debug.val) LOG.debug("Examining " + cstmt);
           
            // Get the mapping objects (if any) for next
            // This is the only way we can predict what partitions we will touch
            Map<StmtParameter, SortedSet<ParameterMapping>> stmtMappings = this.allMappings.get(catalog_stmt, catalog_stmt_index);
            if (stmtMappings == null) {
                if (debug.val) {
                    LOG.warn("No parameter mappings for " + catalog_stmt);
                    if (trace.val) LOG.trace(this.allMappings.debug(catalog_stmt));
                }
                continue;
            }
           
            // Go through the StmtParameters and map values from ProcParameters
            StmtParameter stmt_params[] = catalog_stmt.getParameters().values();
            Object stmt_args[] = new Object[stmt_params.length]; // this.getStatementParamsArray(catalog_stmt);
            boolean stmt_args_set = false;
           
            // XXX: This method may return null because it's being used for other
            // purposes in the BatchPlanner.
            int stmt_args_offsets[] = this.p_estimator.getStatementEstimationParameters(catalog_stmt);
            if (stmt_args_offsets == null) {
                stmt_args_offsets = new int[stmt_args.length];
                for (int i = 0; i < stmt_args.length; i++)
                    stmt_args_offsets[i] = i;
            }
            assert(stmt_args_offsets != null) :
                "Unexpected null StmtParameter offsets for " + catalog_stmt.fullName();
            for (int offset : stmt_args_offsets) {
                StmtParameter catalog_stmt_param = stmt_params[offset];
                assert(catalog_stmt_param != null);
                if (trace.val)
                    LOG.trace("Retrieving ParameterMappings for " + catalog_stmt_param.fullName());
               
                Collection<ParameterMapping> mappings = stmtMappings.get(catalog_stmt_param);
                if (mappings == null || mappings.isEmpty()) {
                    if (trace.val)
                        LOG.trace("No parameter mappings exists for " + catalog_stmt_param.fullName());
                    continue;
                }
                if (debug.val)
                    LOG.debug("Found " + mappings.size() + " mapping(s) for " + catalog_stmt_param.fullName());
       
                // Special Case:
                // If the number of possible Statements we could execute next is greater than one,
                // then we need to prune our list by removing those Statements who have a StmtParameter
                // that are correlated to a ProcParameter that doesn't exist (such as referencing an
                // array element that is greater than the size of that current array)
                // TODO: For now we are just going always pick the first mapping
                // that comes back. Is there any choice that we would need to make in order
                // to have a better prediction about what the transaction might do?
                if (debug.val && mappings.size() > 1) {
                    LOG.warn("Multiple parameter mappings for " + catalog_stmt_param.fullName());
                    if (trace.val) {
                        int ctr = 0;
                        for (ParameterMapping m : mappings) {
                            LOG.trace("[" + (ctr++) + "] Mapping: " + m);
                        } // FOR
                    }
                }
                for (ParameterMapping m : mappings) {
                    if (trace.val) LOG.trace("Mapping: " + m);
                    ProcParameter catalog_proc_param = m.getProcParameter();
                    if (catalog_proc_param.getIsarray()) {
                        Object proc_inner_args[] = (Object[])procParams[m.getProcParameter().getIndex()];
                        if (trace.val)
                            LOG.trace(CatalogUtil.getDisplayName(m.getProcParameter(), true) + " is an array: " +
                                      Arrays.toString(proc_inner_args));
                       
                        // TODO: If this Mapping references an array element that is not available for this
                        // current transaction, should we just skip this mapping or skip the entire query?
                        if (proc_inner_args.length <= m.getProcParameterIndex()) {
                            if (trace.val)
                                LOG.trace("Unable to map parameters: " +
                                          "proc_inner_args.length[" + proc_inner_args.length + "] <= " +
                                          "c.getProcParameterIndex[" + m.getProcParameterIndex() + "]");
                            continue;
                        }
                        stmt_args[offset] = proc_inner_args[m.getProcParameterIndex()];
                        stmt_args_set = true;
                        if (trace.val)
                            LOG.trace("Mapped " + CatalogUtil.getDisplayName(m.getProcParameter()) + "[" + m.getProcParameterIndex() + "] to " +
                                      CatalogUtil.getDisplayName(catalog_stmt_param) + " [value=" + stmt_args[offset] + "]");
                    } else {
                        stmt_args[offset] = procParams[m.getProcParameter().getIndex()];
                        stmt_args_set = true;
                        if (trace.val)
                            LOG.trace("Mapped " + CatalogUtil.getDisplayName(m.getProcParameter()) + " to " +
                                      CatalogUtil.getDisplayName(catalog_stmt_param) + " [value=" + stmt_args[offset] + "]");
                    }
                    break;
                } // FOR (Mapping)
            } // FOR (StmtParameter)
               
            // If we set any of the stmt_args in the previous step, then we can throw it
            // to our good old friend the PartitionEstimator and see whether we can figure
            // things out for this Statement
            if (stmt_args_set) {
                if (trace.val)
                    LOG.trace("Mapped StmtParameters: " + Arrays.toString(stmt_args));
                this.stmt_partitions.clear();
                try {
                    this.p_estimator.getAllPartitions(this.stmt_partitions, catalog_stmt, stmt_args, this.base_partition);
                } catch (Exception ex) {
                    String msg = "Failed to calculate partitions for " + catalog_stmt + " using parameters " + Arrays.toString(stmt_args);
                    LOG.error(msg, ex);
                    this.stop();
                    return;
                }
                if (trace.val)
                    LOG.trace("Estimated Partitions for " + catalog_stmt + ": " + this.stmt_partitions);
               
                // Now for this given list of partitions, find a Vertex in our next set
                // that has the same partitions
                if (this.stmt_partitions.isEmpty() == false) {
                    candidate_edge = null;
                    if (trace.val)
                        LOG.trace("Partitions:" + this.stmt_partitions + " / Past:" + this.past_partitions);
                    for (MarkovVertex next_v : next_vertices) {
                        if (trace.val) LOG.trace("Checking whether " + next_v + " is the correct transition");
                        if (next_v.isEqual(catalog_stmt, this.stmt_partitions, this.past_partitions, catalog_stmt_index, true)) {
                            // BINGO!!!
                            assert(candidate_edge == null);
                            try {
                                candidate_edge = markov.findEdge(element, next_v);
                            } catch (NullPointerException ex) {
                                continue;
                            }
                            assert(candidate_edge != null);
                            this.candidate_edges.add(candidate_edge);
                            if (trace.val)
                                LOG.trace("Found candidate edge to " + next_v + " [" + candidate_edge + "]");
                            break;
                        } else if (trace.val) {
                            Map<String, Object> m = new LinkedHashMap<String, Object>();
                            m.put("stmt", next_v.getCatalogItem().equals(catalog_stmt));
                            m.put("stmtCtr", next_v.getQueryCounter() == catalog_stmt_index);
                            m.put("partitions", next_v.getPartitions().equals(this.stmt_partitions));
                            m.put("past", next_v.getPastPartitions().equals(this.past_partitions));
                            LOG.trace("Invalid candidate transition:\n" + StringUtil.formatMaps(m));
                        }
                    } // FOR (Vertex
                    if (trace.val && candidate_edge == null)
                        LOG.trace(String.format("Failed to find candidate edge from %s to %s [partitions=%s]",
                                  element, catalog_stmt.fullName(), this.stmt_partitions));
                }
            }
            // Without any stmt_args, there's nothing we can do here...
            else if (trace.val) {
                LOG.trace("No stmt_args for " + catalog_stmt + ". Skipping...");
            } // IF
        } // FOR
       
        // If we don't have any candidate edges and the FORCE TRAVERSAL flag is set, then we'll just
        // grab all of the edges from our current vertex
        int num_candidates = this.candidate_edges.size();
        boolean was_forced = false;
        if (num_candidates == 0 && this.force_traversal) {
            if (debug.val)
                LOG.debug(String.format("No candidate edges were found. " +
                      "Checking whether we can create our own. [nextStatements=%s]",
                      this.next_statements));
           
            // We're allow to create the vertices that we know are missing
            if (this.learning_enabled && this.next_statements.size() == 1) {
                CountedStatement cntStmt = CollectionUtil.first(this.next_statements);
                MarkovVertex v = new MarkovVertex(cntStmt.statement,
                                                  MarkovVertex.Type.QUERY,
                                                  cntStmt.counter,
                                                  this.stmt_partitions,
                                                  this.past_partitions);
                markov.addVertex(v);
               
                // For now we'll set the new edge's probability to 1.0 to just
                // make the calculations down below work. This will get updated
                // overtime when we recompute the probabilities in the entire graph.
                candidate_edge = new MarkovEdge(markov, 1, 1.0f);
                markov.addEdge(candidate_edge, element, v, EdgeType.DIRECTED);
                this.candidate_edges.add(candidate_edge);
               
                if (this.created_vertices == null) this.created_vertices = new HashSet<MarkovVertex>();
                this.created_vertices.add(v);
                if (trace.val)
                    LOG.trace(String.format("Created new vertex %s and connected it to %s", v, element));
               
                // 2012-10-21
                // The problem with allowing the estimator to create a new vertex is that
                // we don't know what it's children are going to be. That means that when
                // we invoke this method again at the next vertex (the one we just made above)
                // then it's not going to have any children, so we don't know what it's
                // going to do. We are actually better off with just grabbing the next best
                // vertex from the existing edges and then updating the graph after
                // the txn has finished, since now we know exactly what it did.
               
            }
            // Otherwise we'll just make all of the outbound edges from the
            // current vertex be our candidates
            else {
                if (trace.val)
                    LOG.trace("No candidate edges were found. Force travesal flag is set to true, so taking all");
                Collection<MarkovEdge> out_edges = markov.getOutEdges(element);
                if (out_edges != null) this.candidate_edges.addAll(out_edges);
            }
            num_candidates = this.candidate_edges.size();
            was_forced = true;
        }
       
        // So now we have our list of candidate edges. We can pick the first one
        // since they will be sorted by their probability
        if (trace.val) LOG.trace("Candidate Edges: " + this.candidate_edges);
        if (num_candidates > 0) {
            MarkovEdge next_edge = CollectionUtil.first(this.candidate_edges);
            assert(next_edge != null) : "Unexpected null edge " + this.candidate_edges;
            MarkovVertex next_vertex = markov.getOpposite(element, next_edge);
            children.addAfter(next_vertex);
            if (was_forced) {
                if (this.forced_vertices == null) this.forced_vertices = new HashSet<MarkovVertex>();
                this.forced_vertices.add(next_vertex);
            }

            if (debug.val) {
                StringBuilder sb = new StringBuilder();
                sb.append(String.format("#%02d CANDIDATES:\n", this.getDepth()));
                int i = 0;
                for (MarkovEdge e : this.candidate_edges) {
                    MarkovVertex v = markov.getOpposite(element, e);
                    sb.append(String.format("  [%d] %s  --[%s]--> %s%s%s",
                              i++, element, e, v,
                              (next_vertex.equals(v) ? " <== SELECTED" : ""),
                              (trace.val && this.candidate_edges.size() > 1 ? "\n"+StringUtil.addSpacers(v.debug()) : "")));
                } // FOR
                LOG.debug(sb.toString());
            } // DEBUG
           
            // If there was only one next Statement that we could possibly execute here,
            // and if our ParameterMappings allowed us to know exactly what path we took,
            // then we don't need to compute the confidence based on the candidate edges.
            // We know that our confidence here is one!
            if (was_forced == false && this.next_statements.size() == 1 && num_candidates == 1) {
                // Nothing to do!
            }
            // Otherwise, our confidence is based on the total sum of the probabilities for all of the
            // edges that we could have taken in comparison to the one that we did take.
            else {
                double total_probability = 0.0;
                for (MarkovEdge e : this.candidate_edges) {
                    total_probability += e.getProbability();
                } // FOR
                this.estimate.confidence *= next_edge.getProbability() / total_probability;
                if (debug.val) LOG.debug("TOTAL:    " + total_probability);
            }
           
            // Update our list of partitions touched by this transaction
            MarkovPathEstimator.populateProbabilities(this.estimate, next_vertex);
           
            if (debug.val) {
                LOG.debug("SELECTED: " + next_vertex + " [confidence=" + this.estimate.confidence + "]");
                LOG.debug(StringUtil.repeat("-", 150));
            }
        } else {
            if (trace.val) LOG.trace("No matching children found. We have to stop...");
        }
    }
   
    @Override
    protected void callback(MarkovVertex v) {
        this.estimate.path.add(v);
        if (v.isQueryVertex() == false) {
            if (v.isCommitVertex()) {
                if (trace.val) LOG.trace("Reached COMMIT. Stopping...");
                this.stop();
            } else if (v.isAbortVertex()) {
                if (trace.val) LOG.trace("Reached ABORT. Stopping...");
                this.stop();
            }
        }
    }
   
   
    @Override
    protected void callback_finish() {
        MarkovPathEstimator.populateMarkovEstimate(this.estimate, this.estimate.getVertex());
    }
   
    // ----------------------------------------------------------------------------
    // PROBABILITY CALCULATION METHODS
    // ----------------------------------------------------------------------------
   
    protected static void populateProbabilities(MarkovEstimate estimate, MarkovVertex vertex) {
        if (debug.val)
            LOG.debug(String.format("Populating %s probabilities based on %s " +
                      "[touchedPartitions=%s, confidence=%.03f, hashCode=%d]%s",
                      estimate.getClass().getSimpleName(), vertex.getClass().getSimpleName(),
                      estimate.touched_partitions, estimate.confidence, estimate.hashCode(),
                      (trace.val ? "\n"+vertex.debug() : "")));
       
        Statement catalog_stmt = vertex.getCatalogItem();
        PartitionSet partitions = vertex.getPartitions();
        boolean readQuery = (catalog_stmt.getQuerytype() == QueryType.SELECT.getValue());
        for (int partition : partitions.values()) {
            if (estimate.isDoneProbabilitySet(partition) == false) {
                estimate.setDoneProbability(partition, vertex.getDoneProbability(partition));
            }
            if (estimate.isWriteProbabilitySet(partition) == false) {
                estimate.setWriteProbability(partition, vertex.getWriteProbability(partition));
            }
            (readQuery ? estimate.read_partitions : estimate.write_partitions).add(partition);
            estimate.incrementTouchedCounter(partition);
            estimate.touched_partitions.add(partition);
        } // FOR
        // Make sure that we update our probabilities for any partition that we've touched
        // in the past but are not touching for this query
        for (int partition : vertex.getPastPartitions()) {
            if (partitions.contains(partition) == false) {
                if (estimate.isDoneProbabilitySet(partition) == false) {
                    estimate.setDoneProbability(partition, vertex.getDoneProbability(partition));
                }
                if (estimate.isWriteProbabilitySet(partition) == false) {
                    estimate.setWriteProbability(partition, vertex.getWriteProbability(partition));
                }  
            }
        } // FOR
       
     // float inverse_prob = 1.0f - estimate.confidence;
//        // READ QUERY
//        if (catalog_stmt.getQuerytype() == QueryType.SELECT.getValue()) {
//            for (int partition : next_partitions.values()) {
//                // This is the first time we've read from this partition
//                if (estimate.read_partitions.contains(partition) == false) {
//                    if (trace.val)
//                        LOG.trace(String.format("First time partition %d is read from! " +
//                              "Setting read-only probability to %.03f",
//                                  partition, estimate.confidence));
////                    estimate.setReadOnlyProbability(p, estimate.confidence);
//                    if (estimate.isDoneProbabilitySet(partition) == false) {
//                        estimate.setDoneProbability(partition, inverse_prob);
//                    }
//                    estimate.read_partitions.add(partition);
//                }
//                estimate.incrementTouchedCounter(partition);
//            } // FOR
//        }
//        // WRITE QUERY
//        else {
//            for (int partition : next_partitions.values()) {
//                // This is the first time we've written to this partition
//                if (estimate.write_partitions.contains(partition) == false) {
//                    if (trace.val)
//                        LOG.trace(String.format("First time partition %d is written to! " +
//                              "Setting write probability to %.03f",
//                                  partition, estimate.confidence));
////                    estimate.setReadOnlyProbability(p, inverse_prob);
//                    estimate.setWriteProbability(partition, estimate.confidence);
//                    if (estimate.isDoneProbabilitySet(partition) == false) {
//                        estimate.setDoneProbability(partition, inverse_prob);
//                    }
//                    estimate.write_partitions.add(partition);
//                }
//                estimate.incrementTouchedCounter(partition);
//            } // FOR
//        }
       
        // Keep track of the highest abort probability that we've seen thus far
        if (vertex.isQueryVertex() && vertex.getAbortProbability() > estimate.greatest_abort) {
            estimate.greatest_abort = vertex.getAbortProbability();
        }
    }
   
    /**
     * Copy the MarkovVertex probabilities into the given MarkovEstimate
     * @param estimate
     * @param vertex
     */
    protected static void populateMarkovEstimate(MarkovEstimate estimate, MarkovVertex vertex) {
        assert(vertex != null);
        if (debug.val)
            LOG.debug(String.format("Populating %s internal properties based on current %s " +
                  "[touchedPartitions=%s, confidence=%f]",
                  estimate.getClass().getSimpleName(), vertex.getClass().getSimpleName(),
                  estimate.touched_partitions, estimate.confidence));
       
//        float untouched_finish = 1.0f;
        // float inverse_prob = 1.0f - estimate.confidence;
       
        // We need to loop through all possible partitions and make sure
        // that they all have a probability here.
        for (int partition : estimate.getCatalogContext().getAllPartitionIds().values()) {
            if (estimate.isDoneProbabilitySet(partition) == false) {
                estimate.setDoneProbability(partition, vertex.getDoneProbability(partition));
            }
            if (estimate.isWriteProbabilitySet(partition) == false) {
                estimate.setWriteProbability(partition, vertex.getWriteProbability(partition));
            }
//            estimate.setReadOnlyProbability(partition, vertex.getReadOnlyProbability(partition));
        } // FOR
       
        // If our single-partition probability hasn't been set and we can set it now
//        if (estimate.isSinglePartitionProbabilitySet() == false) {
//            if (estimate.touched_partitions.size() == 1) {
//                estimate.setSinglePartitionProbability(estimate.confidence);
//            } else {
//                estimate.setSinglePartitionProbability(1f - estimate.confidence);
//            }
//            if (debug.val)
//                LOG.debug(String.format("Setting single-partition probability to %s [touchedPartitions=%s]",
//                          estimate.getSinglePartitionProbability(), estimate.touched_partitions));
//        }
       
        // Abort Probability
        // Only use the abort probability if we have seen at least ABORT_MIN_TXNS
        if (vertex.getTotalHits() >= MarkovGraph.MIN_HITS_FOR_NO_ABORT) {
            if (estimate.greatest_abort == EstimatorUtil.NULL_MARKER) estimate.greatest_abort = 0.0f;
            estimate.setAbortProbability(estimate.greatest_abort);
        } else {
            estimate.setAbortProbability(1.0f);
        }
    }
   
    // ----------------------------------------------------------------------------
    // CONVENIENCE METHODS
    // ----------------------------------------------------------------------------
   
    public static void fastEstimation(MarkovEstimate estimate, List<MarkovVertex> initialPath, MarkovVertex current) {
        if (debug.val)
            LOG.debug(String.format("Fast Estimation for %s [hashCode=%d]\n%s",
                      estimate.getClass().getSimpleName(), estimate.hashCode(),
                      estimate.toString()));
       
        boolean add = false;
        for (MarkovVertex v : initialPath) {
            if (add || current.equals(v)) {
                MarkovPathEstimator.populateProbabilities(estimate, v);
                estimate.path.add(v);
                add = true;
            }
        } // FOR
        MarkovPathEstimator.populateMarkovEstimate(estimate, estimate.getVertex());
    }
   
    /**
     * Convenience method that returns the traversal path predicted for this instance
     * @param markov
     * @param t_estimator
     * @param args
     * @return
     */
    public static MarkovEstimate predictPath(MarkovGraph markov, MarkovEstimator t_estimator, Object args[]) {
        CatalogContext catalogContext = t_estimator.getCatalogContext();
        PartitionEstimator p_estimator = t_estimator.getPartitionEstimator();
       
        int base_partition = HStoreConstants.NULL_PARTITION_ID;
        try {
            base_partition = p_estimator.getBasePartition(markov.getProcedure(), args);
        } catch (Exception ex) {
            String msg = String.format("Failed to calculate base partition for <%s, %s>",
                                       markov.getProcedure().getName(), Arrays.toString(args));
            LOG.fatal(msg, ex);
            throw new RuntimeException(msg, ex);
        }
        assert(base_partition != HStoreConstants.NULL_PARTITION_ID);
       
       
        MarkovEstimate est = new MarkovEstimate(t_estimator.getCatalogContext());
        MarkovPathEstimator estimator = new MarkovPathEstimator(catalogContext, p_estimator);
        estimator.init(markov, est, args, base_partition);
        estimator.traverse(markov.getStartVertex());
        return (est);
    }
}
TOP

Related Classes of edu.brown.hstore.estimators.markov.MarkovPathEstimator$Factory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.