Package edu.brown.designer.generators

Source Code of edu.brown.designer.generators.AccessGraphGenerator

/**
*
*/
package edu.brown.designer.generators;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.voltdb.catalog.CatalogType;
import org.voltdb.catalog.Column;
import org.voltdb.catalog.Constraint;
import org.voltdb.catalog.Database;
import org.voltdb.catalog.ProcParameter;
import org.voltdb.catalog.Procedure;
import org.voltdb.catalog.Statement;
import org.voltdb.catalog.StmtParameter;
import org.voltdb.catalog.Table;
import org.voltdb.types.ConstraintType;
import org.voltdb.types.ExpressionType;
import org.voltdb.types.QueryType;
import org.voltdb.utils.Pair;

import edu.brown.catalog.CatalogPair;
import edu.brown.catalog.CatalogUtil;
import edu.brown.designer.AccessGraph;
import edu.brown.designer.AccessGraph.AccessType;
import edu.brown.designer.AccessGraph.EdgeAttributes;
import edu.brown.designer.DesignerEdge;
import edu.brown.designer.DesignerInfo;
import edu.brown.designer.DesignerVertex;
import edu.brown.graphs.GraphvizExport;
import edu.brown.utils.ArgumentsParser;
import edu.brown.utils.CollectionUtil;
import edu.brown.utils.FileUtil;
import edu.brown.utils.PredicatePairs;
import edu.brown.workload.QueryTrace;
import edu.brown.workload.TransactionTrace;
import edu.uci.ics.jung.graph.util.EdgeType;

/**
* @author pavlo
*/
public class AccessGraphGenerator extends AbstractGenerator<AccessGraph> {
    private static final Logger LOG = Logger.getLogger(AccessGraphGenerator.class);
    private static final boolean d = LOG.isDebugEnabled();
    private static final boolean t = LOG.isTraceEnabled();

    private final Procedure catalog_proc;
    private final Map<Statement, Set<DesignerEdge>> stmt_edge_xref = new HashMap<Statement, Set<DesignerEdge>>();
    private final Map<DesignerEdge, Set<Set<Statement>>> multi_stmt_edge_xref = new HashMap<DesignerEdge, Set<Set<Statement>>>();
    private final Set<Table> debug_tables = new HashSet<Table>();

    private final List<ProcParameter> shared_params = new ArrayList<ProcParameter>();
    private final Map<Pair<CatalogType, CatalogType>, PredicatePairs> table_csets = new HashMap<Pair<CatalogType, CatalogType>, PredicatePairs>();
   
    /**
     * @param stats_catalog_db
     * @param graph
     * @param workload
     * @param catalog_proc
     */
    public AccessGraphGenerator(DesignerInfo info, Procedure catalog_proc) {
        super(info);
        this.catalog_proc = catalog_proc;

        debug_tables.add(this.info.catalogContext.database.getTables().get("CUSTOMER"));
        debug_tables.add(this.info.catalogContext.database.getTables().get("DISTRICT"));
    }

    /**
     * Generate a single AccessGraph for all of the procedures in catalog
     *
     * @param info
     * @return
     */
    public static AccessGraph generateGlobal(DesignerInfo info) {
        if (d)
            LOG.debug("Generating AccessGraph for entire catalog");

        AccessGraph agraph = new AccessGraph(info.catalogContext.database);
        for (Procedure catalog_proc : info.catalogContext.database.getProcedures()) {
            // Skip if there are no transactions in the workload for this
            // procedure
            assert (info.workload != null);
            if (info.workload.getTraces(catalog_proc).isEmpty()) {
                if (d)
                    LOG.debug("No " + catalog_proc + " transactions in workload. Skipping...");
            } else {
                try {
                    new AccessGraphGenerator(info, catalog_proc).generate(agraph);
                } catch (Exception ex) {
                    LOG.fatal(String.format("Failed to incorporate %s into global AccessGraph", catalog_proc.getName()), ex);
                    throw new RuntimeException(ex);
                }
            }
        } // FOR
        return (agraph);
    }

    public static AccessGraph convertToSingleColumnEdges(Database catalog_db, AccessGraph orig_agraph) {
        AccessGraph agraph = new AccessGraph(catalog_db);
        Map<CatalogPair, DesignerEdge> entry_edges = new HashMap<CatalogPair, DesignerEdge>();

        for (DesignerVertex v : orig_agraph.getVertices()) {
            agraph.addVertex(v);
        } // FOR

        for (DesignerEdge e : orig_agraph.getEdges()) {
            // Split up the ColumnSet into separate edges, one per entry
            PredicatePairs cset = e.getAttribute(EdgeAttributes.COLUMNSET);
            assert (cset != null);
            Collection<DesignerVertex> vertices = orig_agraph.getIncidentVertices(e);
            DesignerVertex v0 = CollectionUtil.first(vertices);
            DesignerVertex v1 = v0;
            if (vertices.size() > 1)
                v1 = CollectionUtil.get(vertices, 1);
            assert (v1 != null);

            Table catalog_tbl0 = v0.getCatalogItem();
            assert (catalog_tbl0 != null);
            Table catalog_tbl1 = v1.getCatalogItem();
            assert (catalog_tbl1 != null);

            if (d)
                LOG.debug(String.format("%s <-> %s\n%s", v0, v1, cset));

            for (CatalogPair entry : cset) {
                DesignerEdge new_e = entry_edges.get(entry);
                if (new_e == null) {
                    PredicatePairs new_cset = new PredicatePairs(cset.getStatements());
                    new_cset.add(entry);
                    new_e = new DesignerEdge(agraph, e);
                    new_e.setAttribute(EdgeAttributes.COLUMNSET, new_cset);
                    entry_edges.put(entry, new_e);

                    CatalogType parent0 = entry.getFirst().getParent();
                    CatalogType parent1 = entry.getSecond().getParent();

                    if (parent0 == null && parent1 == null) {
                        if (d)
                            LOG.debug(String.format("Skipping %s ===> %s, %s", entry, v0, v1));
                        continue;

                        // Check whether this is a self-referencing edge
                    } else if ((parent0 == null && parent1.equals(catalog_tbl0)) || (parent1 == null && parent0.equals(catalog_tbl0))) {
                        if (d)
                            LOG.debug(String.format("Self-referencing edge %s ===> %s, %s", entry, v0, v0));
                        agraph.addEdge(new_e, v0, v0);

                    } else if ((parent0 == null && parent1.equals(catalog_tbl1)) || (parent1 == null && parent0.equals(catalog_tbl1))) {
                        if (d)
                            LOG.debug(String.format("Self-referencing edge %s ===> %s, %s", entry, v1, v1));
                        agraph.addEdge(new_e, v1, v1);

                    } else if ((parent0.equals(catalog_tbl0) && parent1.equals(catalog_tbl1) == false) || (parent1.equals(catalog_tbl0) && parent0.equals(catalog_tbl1) == false)
                            || (parent0.equals(catalog_tbl0) && parent1.equals(catalog_tbl0))) {
                        if (d)
                            LOG.debug(String.format("Self-referencing edge %s ===> %s, %s", entry, v0, v0));
                        agraph.addEdge(new_e, v0, v0);

                    } else if ((parent0.equals(catalog_tbl1) && parent1.equals(catalog_tbl0) == false) || (parent1.equals(catalog_tbl1) && parent0.equals(catalog_tbl0) == false)
                            || (parent0.equals(catalog_tbl0) && parent1.equals(catalog_tbl0))) {
                        if (d)
                            LOG.debug(String.format("Self-referencing edge %s ===> %s, %s", entry, v1, v1));
                        agraph.addEdge(new_e, v1, v1);

                    } else {
                        if (d)
                            LOG.debug(String.format("New edge %s ===> %s, %s", entry, v0, v1));
                        agraph.addEdge(new_e, v0, v1);

                    }
                }
                // Add weights from original edge to this new edge
                new_e.addToWeight(e);
            } // FOR (entry)

            if (d)
                LOG.debug("=====================================================================");
        } // FOR
        return (agraph);
    }

    /*
     * (non-Javadoc)
     * @see
     * edu.brown.designer.analyzers.AbstractAnalyzer#generate(edu.brown.graphs
     * .AccessGraph)
     */
    @Override
    public void generate(AccessGraph agraph) throws Exception {
        if (d)
            LOG.debug("Constructing AccessGraph for Procedure '" + this.catalog_proc.getName() + "'");

        // First initialize our little graph...
        this.initialize(agraph);

        // Get the list of tables used in the procedure
        Collection<Table> proc_tables = CatalogUtil.getReferencedTables(this.catalog_proc);

        // Loop through each query and create edges for the explicitly defined
        // relationships:
        // + Add an edge from each table in the query table to all other
        //   tables in the same query
        // + Add a self-referencing edge for table0 if it is used in a filter
        //   predicate using a variable or an input parameter
        for (Statement catalog_stmt : this.catalog_proc.getStatements()) {
            this.createExplicitEdges(agraph, catalog_stmt);
        } // FOR
        if (debug)
            LOG.debug("===============================================================");

        // After the initial edges have been added to the graph, loop back
        // through again looking for implicit references between two tables:
        //  + Tables implicitly joined by sharing parameters on foreign keys
        //  + Tables implicitly referenced together by using the same values on
        //    foreign keys
        Statement catalog_stmts[] = this.catalog_proc.getStatements().values();
        for (int stmt_ctr0 = 0, stmt_cnt = catalog_stmts.length; stmt_ctr0 < stmt_cnt; stmt_ctr0++) {
            Statement catalog_stmt0 = catalog_stmts[stmt_ctr0];
            Collection<Table> stmt0_tables = CatalogUtil.getReferencedTables(catalog_stmt0);
            this.setDebug(stmt0_tables.containsAll(debug_tables));

            // --------------------------------------------------------------
            // (3) Add an edge between the tables in this Statement and all other
            // tables in other queries that share input parameters on foreign
            // keys relationships
            // --------------------------------------------------------------
            List<ProcParameter> params0 = new ArrayList<ProcParameter>();
            for (StmtParameter param : catalog_stmt0.getParameters()) {
                if (param.getProcparameter() != null)
                    params0.add(param.getProcparameter());
            } // FOR
            if (debug && d)
                LOG.debug(catalog_stmt0.getName() + " Params: " + params0);

            for (int stmt_ctr1 = stmt_ctr0 + 1; stmt_ctr1 < stmt_cnt; stmt_ctr1++) {
                Statement catalog_stmt1 = catalog_stmts[stmt_ctr1];
                if (catalog_stmt1 == null || catalog_stmt1.getParameters() == null)
                    continue;
                this.createSharedParamEdges(agraph, catalog_stmt0, catalog_stmt1, params0);
            } // FOR

            // --------------------------------------------------------------
            // (4) Create an edge between implicit references by primary key
            // This is when one statement has a predicate that uses an input
            // parameter that is not referenced in conjunction with other tables
            // --------------------------------------------------------------
            if (debug && d)
                LOG.debug("-----------------------------------------\n" +
                      "Looking for implicit reference joins in " + catalog_stmt0 + "\n" +
                          "TABLES: " + stmt0_tables);
            for (Table catalog_tbl : stmt0_tables) {
                this.createImplicitEdges(agraph, proc_tables, catalog_stmt0, catalog_tbl);
            } // FOR
        } // FOR

        //
        // (5) Now run through the workload and update the edges with all number
        // of times they
        // are used in the workload
        //
        // if (debug) System.err.println("STATEMENT EDGE XREF: " +
        // this.stmt_edge_xref.size());
        // for (Statement catalog_stmt : this.stmt_edge_xref.keySet()) {
        // if (debug) System.err.println(catalog_stmt + ": " +
        // this.stmt_edge_xref.get(catalog_stmt).size());
        // }
        // if (this.catalog_proc.getName().equals("neworder")) System.exit(1);
        // if (debug) System.err.println("MULTI-STATEMENT EDGE XREF: " +
        // this.multi_stmt_edge_xref.size());
        // for (Edge edge : this.multi_stmt_edge_xref.keySet()) {
        // if (debug) System.err.println(edge + ": " +
        // this.multi_stmt_edge_xref.get(edge).size());
        // }
        // if (this.catalog_proc.getName().equals("neworder")) System.exit(1);

        List<TransactionTrace> traces = this.info.workload.getTraces(this.catalog_proc);
        if (d)
            LOG.debug("Updating edge weights using " + traces.size() + " txn traces from workload");
        for (TransactionTrace xact : traces) {
            this.updateEdgeWeights(agraph, xact);
        } // FOR
        this.updateEdgeWeighModifiers(agraph);

        // Prune vertices that weren't used in the the procedure
        agraph.pruneIsolatedVertices();

        // Make sure all of the table used in the procedure are in the graph
        for (Table catalog_tbl : proc_tables) {
            assert (agraph.getVertex(catalog_tbl) != null) : "The AccessGraph is missing a vertex for " + catalog_tbl;
        }

        // Done!
        return;
    }

    /**
     * @param agraph
     * @throws Exception
     */
    protected void initialize(AccessGraph agraph) throws Exception {
        // Copy the vertices from the DependencyGraph into our graph
        for (DesignerVertex vertex : this.info.dgraph.getVertices()) {
            if (agraph.getVertex(vertex.getCatalogItem()) == null)
                agraph.addVertex(vertex);
        } // FOR
    }

    /**
     * @param agraph
     * @throws Exception
     */
    protected void createExplicitEdges(AccessGraph agraph, Statement catalog_stmt) throws Exception {
        if (d)
            LOG.debug("Looking at " + catalog_stmt.fullName());
        if (t)
            LOG.trace("SQL: " + catalog_stmt.getSqltext());
        List<Table> tables = new ArrayList<Table>();
        tables.addAll(CatalogUtil.getReferencedTables(catalog_stmt));
        for (int ctr = 0, cnt = tables.size(); ctr < cnt; ctr++) {
            Table table0 = tables.get(ctr);
            boolean debug_table = (debug_tables.contains(table0) && t);

            // --------------------------------------------------------------
            // (1) Add an edge from table0 to all other tables in the query
            // --------------------------------------------------------------
            for (int ctr2 = ctr + 1; ctr2 < cnt; ctr2++) {
                Table table1 = tables.get(ctr2);
                PredicatePairs cset = CatalogUtil.extractStatementPredicates(catalog_stmt, true, table0, table1);
                if (debug_table)
                    LOG.trace("Creating join edge between " + table0 + "<->" + table1 + " for " + catalog_stmt);
                this.addEdge(agraph, AccessType.SQL_JOIN, cset, agraph.getVertex(table0), agraph.getVertex(table1), catalog_stmt);
            } // FOR
              // --------------------------------------------------------------

            // --------------------------------------------------------------
            // (2) Add a self-referencing edge for table0 if it is used in
            // a filter predicate using a variable or an input parameter
            // --------------------------------------------------------------
            if (debug_table)
                LOG.trace("Looking for scan ColumnSet on table '" + table0.getName() + "'");
            PredicatePairs cset = CatalogUtil.extractStatementPredicates(catalog_stmt, true, table0);
            if (!cset.isEmpty()) {
                if (debug_table)
                    LOG.trace("Creating scan edge to " + table0 + " for " + catalog_stmt);
                // if (debug) if (d) LOG.debug("Scan Column SET[" +
                // table0.getName() + "]: " + cset.debug());
                DesignerVertex vertex = agraph.getVertex(table0);
                AccessType atype = (catalog_stmt.getQuerytype() == QueryType.INSERT.getValue() ? AccessType.INSERT : AccessType.SCAN);
                this.addEdge(agraph, atype, cset, vertex, vertex, catalog_stmt);
            }
            // --------------------------------------------------------------
        } // FOR
        return;
    }

    /**
     * @param agraph
     * @param stmt_ctr0
     * @throws Exception
     */
    protected void createSharedParamEdges(AccessGraph agraph, Statement catalog_stmt0, Statement catalog_stmt1, List<ProcParameter> catalog_stmt0_params) throws Exception {
        this.table_csets.clear();
        this.shared_params.clear();
        if (d) LOG.debug("Creating Shared Parameter Edges between " + catalog_stmt0.getName() + " <-> " + catalog_stmt1.getName());
       
        // Check whether these two queries share input parameters
        for (StmtParameter stmt_param : catalog_stmt1.getParameters()) {
            if (stmt_param.getProcparameter() != null && catalog_stmt0_params.contains(stmt_param.getProcparameter())) {
                shared_params.add(stmt_param.getProcparameter());
            }
        } // FOR
        if (shared_params.isEmpty())
            return;
        if (t) {
            LOG.trace(catalog_stmt0.getName() + " <==> " + catalog_stmt1.getName());
            LOG.trace("SHARED PARAMS: " + shared_params);
        }

        // For each shared parameter, we need to get the expressions that
        // use each one and figure out whether there is a foreign key
        // relationship
        // between the two tables used.
        for (ProcParameter param : shared_params) {
            Set<Column> columns0 = new HashSet<Column>();
            Set<Column> columns1 = new HashSet<Column>();

            if (this.stmt_edge_xref.containsKey(catalog_stmt0)) {
                for (DesignerEdge edge : this.stmt_edge_xref.get(catalog_stmt0)) {
                    PredicatePairs cset = (PredicatePairs) edge.getAttribute(EdgeAttributes.COLUMNSET.name());
                    columns0.addAll(cset.findAllForOther(Column.class, param));
                } // FOR
            }
            if (this.stmt_edge_xref.containsKey(catalog_stmt1)) {
                for (DesignerEdge edge : this.stmt_edge_xref.get(catalog_stmt1)) {
                    PredicatePairs cset = (PredicatePairs) edge.getAttribute(EdgeAttributes.COLUMNSET.name());
                    columns1.addAll(cset.findAllForOther(Column.class, param));
                } // FOR
            }

            // Partition the columns into sets based on their Table. This is
            // necessary
            // so that we can have specific edges between vertices
            Map<Table, Set<Column>> table_column_xref0 = new HashMap<Table, Set<Column>>();
            Map<Table, Set<Column>> table_column_xref1 = new HashMap<Table, Set<Column>>();
            for (CatalogType ctype : columns0) {
                Column col = (Column) ctype;
                Table tbl = (Table) col.getParent();
                if (!table_column_xref0.containsKey(tbl)) {
                    table_column_xref0.put(tbl, new HashSet<Column>());
                }
                table_column_xref0.get(tbl).add(col);
            } // FOR
            for (CatalogType ctype : columns1) {
                Column col = (Column) ctype;
                Table tbl = (Table) col.getParent();
                if (!table_column_xref1.containsKey(tbl)) {
                    table_column_xref1.put(tbl, new HashSet<Column>());
                }
                table_column_xref1.get(tbl).add(col);
            } // FOR

            // if (debug) {
            // StringBuilder buffer = new StringBuilder();
            // buffer.append("table_column_xref0:\n");
            // for (Table table : table_column_xref0.keySet()) {
            // buffer.append("  ").append(table).append(": ").append(table_column_xref0.get(table)).append("\n");
            // }
            // if (d) LOG.debug(buffer.toString());
            //
            // buffer = new StringBuilder();
            // buffer.append("table_column_xref1:\n");
            // for (Table table : table_column_xref1.keySet()) {
            // buffer.append("  ").append(table).append(": ").append(table_column_xref1.get(table)).append("\n");
            // }
            // if (d) LOG.debug(buffer.toString());
            // }

            // Now create a cross product of the two sets based on tables --
            // Nasty!!
            for (Table table0 : table_column_xref0.keySet()) {
                for (Table table1 : table_column_xref1.keySet()) {
                    if (table0 == table1)
                        continue;
                    Pair<CatalogType, CatalogType> table_pair = CatalogUtil.pair(table0, table1);
                    PredicatePairs cset = null;
                    if (table_csets.containsKey(table_pair)) {
                        cset = table_csets.get(table_pair);
                    } else {
                        cset = new PredicatePairs();
                    }
                    for (Column column0 : table_column_xref0.get(table0)) {
                        for (Column column1 : table_column_xref1.get(table1)) {
                            // TODO: Enforce foreign key dependencies
                            // TODO: Set real ComparisionExpression attribute
                            cset.add(column0, column1, ExpressionType.COMPARE_EQUAL);
                        } // FOR
                    } // FOR
                    table_csets.put(table_pair, cset);
                } // FOR
            } // FOR
        } // FOR

        // Now create the edges between the vertices
        for (Pair<CatalogType, CatalogType> table_pair : table_csets.keySet()) {
            DesignerVertex vertex0 = agraph.getVertex((Table) table_pair.getFirst());
            DesignerVertex vertex1 = agraph.getVertex((Table) table_pair.getSecond());
            PredicatePairs cset = table_csets.get(table_pair);

            if (t) {
                LOG.trace("Vertex0: " + vertex0.getCatalogKey());
                LOG.trace("Vertex1: " + vertex0.getCatalogKey());
                LOG.trace("ColumnSet:\n" + cset.debug() + "\n");
            }

            DesignerEdge edge = this.addEdge(agraph, AccessType.PARAM_JOIN, cset, vertex0, vertex1);
            if (!this.multi_stmt_edge_xref.containsKey(edge)) {
                this.multi_stmt_edge_xref.put(edge, new HashSet<Set<Statement>>());
            }
            Set<Statement> new_set = new HashSet<Statement>();
            new_set.add(catalog_stmt0);
            new_set.add(catalog_stmt1);
            this.multi_stmt_edge_xref.get(edge).add(new_set);

            cset.getStatements().add(catalog_stmt0);
            cset.getStatements().add(catalog_stmt1);
        } // FOR tablepair columnsets
    }

    /**
     * @param agraph
     * @param proc_tables
     * @param catalog_stmt0
     * @param catalog_tbl
     * @throws Exception
     */
    protected void createImplicitEdges(AccessGraph agraph, Collection<Table> proc_tables, Statement catalog_stmt0, Table catalog_tbl) throws Exception {
        // For each SCAN edge for this vertex, check whether the column has a
        // foreign key
        DesignerVertex vertex = agraph.getVertex(catalog_tbl);
        if (d) LOG.debug("Creating Implicit Edges for " + catalog_tbl);
        Collection<DesignerEdge> scanEdges = agraph.getIncidentEdges(vertex,
                                                                 AccessGraph.EdgeAttributes.ACCESSTYPE.name(),
                                                                 AccessType.SCAN);
        if (t) LOG.trace("\t" + catalog_tbl.getName() + " Incident Edges: " + scanEdges);
        for (DesignerEdge edge : scanEdges) {
            PredicatePairs scan_cset = (PredicatePairs) edge.getAttribute(AccessGraph.EdgeAttributes.COLUMNSET.name());
            if (t) LOG.trace("\tSCAN EDGE: " + edge); // + "\n" +
                                                   // scan_cset.debug());

            // For each table that our foreign keys reference, will construct a
            // ColumnSet mapping
            Map<Table, PredicatePairs> fkey_column_xrefs = new HashMap<Table, PredicatePairs>();
            if (t) LOG.trace("\tOUR COLUMNS: " + scan_cset.findAllForParent(Column.class, catalog_tbl));
            for (Column catalog_col : scan_cset.findAllForParent(Column.class, catalog_tbl)) {
                // Get the foreign key constraint for this column and then add
                // it to the ColumnSet
                Collection<Constraint> catalog_consts = CatalogUtil.getConstraints(catalog_col.getConstraints());
                catalog_consts = CatalogUtil.findAll(catalog_consts, "type", ConstraintType.FOREIGN_KEY.getValue());
                if (!catalog_consts.isEmpty()) {
                    assert (catalog_consts.size() == 1) : CatalogUtil.getDisplayName(catalog_col) + " has " + catalog_consts.size() + " foreign key constraints: " + catalog_consts;
                    Constraint catalog_const = CollectionUtil.first(catalog_consts);
                    Table catalog_fkey_tbl = catalog_const.getForeignkeytable();
                    assert (catalog_fkey_tbl != null);

                    // Important! We only want to include tables that are
                    // actually referenced in this procedure
                    if (proc_tables.contains(catalog_fkey_tbl)) {
                        Column catalog_fkey_col = CollectionUtil.first(catalog_const.getForeignkeycols()).getColumn();
                        assert (catalog_fkey_col != null);

                        // TODO: Use real ExpressionType from the entry
                        if (!fkey_column_xrefs.containsKey(catalog_fkey_tbl)) {
                            fkey_column_xrefs.put(catalog_fkey_tbl, new PredicatePairs());
                        }
                        // if (debug) System.err.println("Foreign Keys: " +
                        // CollectionUtil.getFirst(catalog_const.getForeignkeycols()).getColumn());
                        // if (debug) System.err.println("catalog_fkey_tbl: " +
                        // catalog_fkey_tbl);
                        // if (debug) System.err.println("catalog_col: " +
                        // catalog_col);
                        // if (debug) System.err.println("catalog_fkey_col: " +
                        // catalog_fkey_col);
                        // if (debug) System.err.println("fkey_column_xrefs: " +
                        // fkey_column_xrefs.get(catalog_fkey_tbl));
                        fkey_column_xrefs.get(catalog_fkey_tbl).add(catalog_col, catalog_fkey_col, ExpressionType.COMPARE_EQUAL);
                    } else {
                        if (t) LOG.trace("\tSkipping Implict Reference Join for " + catalog_fkey_tbl + " because it is not used in " + this.catalog_proc);
                    }
                } else if (t) {
                    LOG.warn("\tNo foreign keys found for " + catalog_col.fullName());
                }
            } // FOR

            // Now for each table create an edge from our table to the table
            // referenced in the foreign
            // key using all the columdns referenced by in the SCAN predicates
            for (Table catalog_fkey_tbl : fkey_column_xrefs.keySet()) {
                DesignerVertex other_vertex = agraph.getVertex(catalog_fkey_tbl);
                PredicatePairs implicit_cset = fkey_column_xrefs.get(catalog_fkey_tbl);
                if (t)
                    LOG.trace("\t" + catalog_tbl + "->" + catalog_fkey_tbl + "\n" + implicit_cset.debug());
                Collection<DesignerEdge> edges = agraph.findEdgeSet(vertex, other_vertex);
                if (edges.isEmpty()) {
                    this.addEdge(agraph, AccessType.IMPLICIT_JOIN, implicit_cset, vertex, other_vertex, catalog_stmt0);
                    // Even though we don't need to create a new edge, we still
                    // need to know that
                    // we have found a reference that should be counted when we
                    // calculate weights
                } else {
                    // 08/25/2009 - Skip tables that already have an edge...
                    // if (!this.stmt_edge_xref.containsKey(catalog_stmt0)) {
                    // this.stmt_edge_xref.put(catalog_stmt0, new
                    // HashSet<Edge>());
                    // }
                    // this.stmt_edge_xref.get(catalog_stmt0).addAll(edges);
                    // if (d) LOG.debug("An edge already exists between " +
                    // catalog_tbl + " and " + catalog_fkey_tbl + ". " +
                    // "Skipping implicit join edge...");
                }
            } // FOR
        } // FOR
        return;
    }

    /**
     * @param access_type
     * @param cset
     * @param vertices
     * @param catalog_stmt
     */
    protected DesignerEdge addEdge(AccessGraph agraph, AccessType access_type, PredicatePairs cset, DesignerVertex v0, DesignerVertex v1, Statement... catalog_stmts) {

        // Sort the vertices by their CatalogTypes
        if (v0.getCatalogItem().compareTo(v1.getCatalogItem()) > 0) {
            DesignerVertex temp = v0;
            v0 = v1;
            v1 = temp;
        }

        String stmts_debug = "";
        if (d) {
            stmts_debug = "[";
            String add = "";
            for (Statement catalog_stmt : catalog_stmts) {
                stmts_debug += add + catalog_stmt.getName();
                add = ", ";
            } // FOR
            stmts_debug += "]";
        }

        // We need to first check whether we already have an edge representing
        // this ColumnSet
        DesignerEdge new_edge = null;
        for (DesignerEdge edge : agraph.getEdges()) {
            Collection<DesignerVertex> vertices = agraph.getIncidentVertices(edge);
            PredicatePairs other_cset = (PredicatePairs) edge.getAttribute(EdgeAttributes.COLUMNSET.name());
            if (vertices.contains(v0) && vertices.contains(v1) && cset.equals(other_cset)) {
                if (t)
                    LOG.trace("FOUND DUPLICATE COLUMN SET: " + other_cset.debug() + "\n" + cset.toString() + "\n[" + edge.hashCode() + "] + " + cset.size() + " == " + other_cset.size() + "\n");
                new_edge = edge;
                break;
            }
        } // FOR
        if (new_edge == null) {
            new_edge = new DesignerEdge(agraph);
            new_edge.setAttribute(EdgeAttributes.ACCESSTYPE.name(), access_type);
            new_edge.setAttribute(EdgeAttributes.COLUMNSET.name(), cset);
            agraph.addEdge(new_edge, v0, v1, EdgeType.UNDIRECTED);
            if (d)
                LOG.debug("New " + access_type + " edge for " + stmts_debug + " between " + v0 + "<->" + v1 + ": " + cset.debug());
        }
        // For edges created by implicitly for joins, we're not going to have a
        // Statement object
        if (catalog_stmts.length > 0) {
            for (Statement catalog_stmt : catalog_stmts) {
                if (!this.stmt_edge_xref.containsKey(catalog_stmt)) {
                    this.stmt_edge_xref.put(catalog_stmt, new HashSet<DesignerEdge>());
                }
                this.stmt_edge_xref.get(catalog_stmt).add(new_edge);
            } // FOR
        }
        if (d)
            LOG.debug("# OF EDGES: " + agraph.getEdgeCount());
        return (new_edge);
    }

    /**
     * @param agraph
     * @param xact
     * @param time
     *            TODO
     * @throws Exception
     */
    protected void updateEdgeWeights(AccessGraph agraph, TransactionTrace xact) throws Exception {
        int time = info.workload.getTimeInterval(xact, this.info.getNumIntervals());

        // Update the weights for the direct query-to-edge mappings
        for (QueryTrace query : xact.getQueries()) {
            Statement catalog_stmt = query.getCatalogItem(this.info.catalogContext.database);
            if (!this.stmt_edge_xref.containsKey(catalog_stmt)) {
                if (d)
                    LOG.warn("Missing query '" + catalog_stmt.fullName() + "' in Statement-Edge Xref mapping");
            } else {
                for (DesignerEdge edge : this.stmt_edge_xref.get(catalog_stmt)) {
                    edge.addToWeight(time, 1d);
                } // FOR
            }
        } // FOR

        // Update the weights for any edges that required multiple statements to
        // be
        // executed in order the edges to be updated
        Map<Statement, Integer> catalog_stmt_counts = xact.getStatementCounts(info.catalogContext.database);
        for (DesignerEdge edge : this.multi_stmt_edge_xref.keySet()) {
            // For each edge in our list, there is a list of Statements that
            // need to be executed
            // in order for the implicitly join to have occurred. Thus, we need
            // to check whether
            // this transaction executed all the Statements. We keep the minimum
            // count for each
            // of these Statements and will update the weight accordingly.
            for (Set<Statement> stmts : this.multi_stmt_edge_xref.get(edge)) {
                int min_cnt = Integer.MAX_VALUE;
                for (Statement stmt : stmts) {
                    min_cnt = Math.min(min_cnt, catalog_stmt_counts.get(stmt));
                } // FOR
                if (min_cnt > 0) {
                    edge.addToWeight(time, min_cnt);
                }
            } // FOR
        } // FOR
        return;
    }

    /**
     * @param agraph
     */
    protected void updateEdgeWeighModifiers(AccessGraph agraph) {
        for (DesignerEdge edge : agraph.getEdges()) {
            List<DesignerVertex> vertices = new ArrayList<DesignerVertex>(agraph.getIncidentVertices(edge));
            AccessGraph.AccessType type = (AccessGraph.AccessType) edge.getAttribute(AccessGraph.EdgeAttributes.ACCESSTYPE.name());

            // Modifier
            double modifier = 1.0d;

            // Join Modifier
            switch (type) {
                case IMPLICIT_JOIN:
                    // weight *= AccessGraph.WEIGHT_IMPLICIT;
                    break;
                case PARAM_JOIN:

                    break;
                case SQL_JOIN:

                    break;
            } // SWITCH

            // Foreign Key Modifier
            if (!(this.info.dgraph.findEdgeSet(vertices.get(0), vertices.get(1)).isEmpty() && this.info.dgraph.findEdgeSet(vertices.get(1), vertices.get(0)).isEmpty())) {
                modifier += AccessGraph.WEIGHT_FOREIGN_KEY;
                edge.setAttribute(AccessGraph.EdgeAttributes.FOREIGNKEY.name(), true);
            } else {
                edge.setAttribute(AccessGraph.EdgeAttributes.FOREIGNKEY.name(), false);
            }

            // Update all weights using our modifier
            for (int time = 0, cnt = edge.getIntervalCount(); time < cnt; time++) {
                double weight = edge.getWeight(time) * modifier;
                edge.setWeight(time, weight);
            } // FOR
        } // FOR
    }

    public static void main(String[] vargs) throws Exception {
        ArgumentsParser args = ArgumentsParser.load(vargs);
        args.require(ArgumentsParser.PARAM_CATALOG, ArgumentsParser.PARAM_WORKLOAD);
        DesignerInfo info = new DesignerInfo(args);
        boolean global = true;
        boolean single = false;

        if (global) {
            AccessGraph agraph = AccessGraphGenerator.generateGlobal(info);
            assert (agraph != null);
            if (single)
                agraph = AccessGraphGenerator.convertToSingleColumnEdges(args.catalog_db, agraph);
            agraph.setVerbose(true);
            GraphvizExport<DesignerVertex, DesignerEdge> gv = new GraphvizExport<DesignerVertex, DesignerEdge>(agraph);
            gv.setEdgeLabels(true);
            String path = "/tmp/" + args.catalog_type.toString().toLowerCase() + ".dot";
            FileUtil.writeStringToFile(path, gv.export(args.catalog_type.toString()));
            LOG.info("Wrote Graphviz file to " + path);

        } else {
            for (Procedure catalog_proc : args.catalog_db.getProcedures()) {
                if (catalog_proc.getSystemproc())
                    continue;
                if (catalog_proc.getName().equals("neworder") == false)
                    continue;
                AccessGraphGenerator gen = new AccessGraphGenerator(info, catalog_proc);
                final AccessGraph agraph = new AccessGraph(args.catalog_db);
                gen.generate(agraph);
                agraph.setVerbose(true);

                GraphvizExport<DesignerVertex, DesignerEdge> gv = new GraphvizExport<DesignerVertex, DesignerEdge>(agraph);
                gv.setEdgeLabels(true);
                String path = "/tmp/" + catalog_proc.getName() + ".dot";
                FileUtil.writeStringToFile(path, gv.export(catalog_proc.getName()));
                LOG.info("Wrote Graphviz file to " + path);

                // javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
                // public void run() {
                // GraphVisualizationPanel.createFrame(agraph).setVisible(true);
                // }
                // });
            } // FOR
        }
    }
}
TOP

Related Classes of edu.brown.designer.generators.AccessGraphGenerator

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.