/**
*
*/
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
}
}
}