if (!child_root.equals(parent_root)) {
LOG.debug("Skipping " + vertex + " because it's in a different partition tree (" + child_root + "<->" + parent_root + ")");
continue;
}
DesignerEdge orig_edge = null;
Double max_weight = null;
try {
orig_edge = ptree.findEdge(vertex_orig_parent, vertex);
// TODO: Need to think about whether it makes sense to
// take the total weight
// or whether we need to consider
max_weight = orig_edge.getTotalWeight();
} catch (Exception ex) {
LOG.error(vertex + " => " + vertex_orig_parent);
if (orig_edge != null) {
LOG.error(orig_edge.debug());
} else {
LOG.error("ORIG EDGE: null");
}
ex.printStackTrace();
System.exit(1);
}
DesignerEdge max_edge = orig_edge;
for (DesignerEdge candidate_edge : agraph.findEdgeSet(parent, vertex)) {
Double candidate_weight = (Double) candidate_edge.getAttribute(PartitionTree.EdgeAttributes.WEIGHT.name());
if (candidate_weight > max_weight) {
max_edge = candidate_edge;
max_weight = candidate_weight;
}
} // FOR
//
// If the edge has changed, then we need to add it to our
// list of next vertices to visit.
// What if there isn't an AttributeSet that matches up
// with the parent? Then
// we just broke up the graph for no good reason
//
if (!force && max_edge.equals(orig_edge)) {
LOG.debug("Skipping " + vertex + " because there was not an edge with a greater weight than what it currently has in the PartitionTree");
continue;
} else {
//
// Check whether this child was our parent before, then
// we need to make sure that
// we switch ourselves to the HASH partition method
// instead of MAP
//
if (ptree.getParent(parent) != null && ptree.getParent(parent).equals(vertex)) {
parent.setAttribute(ptree, PartitionTree.VertexAttributes.METHOD.name(), PartitionMethodType.HASH);
}
LOG.debug("Remove existing child " + vertex + " from PartitionTree");
ptree.removeChild(vertex);
}
}
}
LOG.debug("Adding " + vertex + " to the list of the next nodes to visit");
next.add(vertex);
} // FOR
// --------------------------------------------------------
// STEP #2: Selecting Partitioning Attribute
// --------------------------------------------------------
if (!next.isEmpty()) {
//
// If we're the root, then we need to select our partitioning
// attribute
//
if (is_root) {
TablePartitionSets attributes = new TablePartitionSets((Table) parent.getCatalogItem());
boolean debug = parent.getCatalogItem().getName().equals("STOCK");
for (DesignerVertex child : next) {
//
// We now need to pick what edge from the AccessGraph to use
// as the dependency edge
// in our partition mapping
//
Table catalog_child_tbl = child.getCatalogItem();
LOG.debug("Looking for edge between " + parent + " and " + child + ": " + agraph.findEdgeSet(parent, child));
for (DesignerEdge edge : agraph.findEdgeSet(parent, child)) {
LOG.debug("Creating AttributeSet entry for " + edge);
//
// We only want to use edges that are used in joins.
//
AccessGraph.AccessType type = (AccessGraph.AccessType) edge.getAttribute(AccessGraph.EdgeAttributes.ACCESSTYPE.name());
if (!AccessGraph.AccessType.JOINS.contains(type))
continue;
attributes.add(catalog_child_tbl, edge);
} // FOR
} // FOR
if (debug) {
LOG.debug(attributes.debug());
LOG.debug("---------------------");
}
if (attributes.size() > 1)
attributes.generateSubSets();
if (debug) {
LOG.debug(attributes.debug());
LOG.debug("---------------------");
}
//
// Now get the list of AttributeSets that have the highest
// weights
//
Set<TablePartitionSets.Entry> asets = attributes.getMaxWeightAttributes();
if (debug) {
System.out.println(asets);
}
TablePartitionSets.Entry aset = null;
if (asets.isEmpty()) {
LOG.debug("Skipping vertex " + parent + " because no attributes to its children were found");
return; // throw new
// Exception("ERROR: Failed to generate AttributeSets for parent '"
// + parent + "'");
} else if (asets.size() > 1) {
//
// XXX: Pick the attribute with the longest path to a root
// in the dependency graph
//
TablePartitionSets.Entry best_entry = null;
int best_length = Integer.MIN_VALUE;
for (TablePartitionSets.Entry entry : asets) {
for (Column catalog_col : entry) {
List<Column> ancestors = info.dependencies.getAncestors(catalog_col);
int length = ancestors.size();
LOG.debug(catalog_col + " ==> " + ancestors + " [length=" + length + "]");
if (length > best_length) {
best_entry = entry;
best_length = length;
}
} // FOR
} // FOR
if (best_entry == null) {
LOG.fatal("Unable to handle more than one AttributeSet for parent '" + parent + "' [" + asets.size() + "]");
System.exit(1);
}
LOG.debug("Choose PartitionSet.Entry " + best_entry + " because it has a path length of " + best_length);
aset = best_entry;
} else {
aset = CollectionUtil.first(asets);
}
//
// We need to figure out which attribute to select if there are
// multiple ones
// Well, one way is to pick one that
parent.setAttribute(ptree, PartitionTree.VertexAttributes.ATTRIBUTE.name(), CollectionUtil.first(aset));
} // is_root
//
// This AttributeSet determines how we want to partition the parent
// node.
// Therefore, we can only attach those children that have edges that
// use these attributes
//
List<DesignerVertex> next_to_visit = new ArrayList<DesignerVertex>();
Column parent_attribute = (Column) parent.getAttribute(ptree, PartitionTree.VertexAttributes.ATTRIBUTE.name());
for (DesignerVertex child : next) {
for (DesignerEdge edge : agraph.findEdgeSet(parent, child)) {
//
// Find the edge that links parent to this child
// If no edge exists, then the child can't be linked to the
// parent
//
PredicatePairs cset = (PredicatePairs) edge.getAttribute(AccessGraph.EdgeAttributes.COLUMNSET.name());
Collection<Column> entries = cset.findAllForOther(Column.class, parent_attribute);
if (!entries.isEmpty()) {
next_to_visit.add(child);
assert (entries.size() == 1) : "Multiple entries from " + parent + " to " + child + ": " + entries;
try {
if (!ptree.containsVertex(parent))
ptree.addVertex(parent);
DesignerEdge new_edge = ptree.createEdge(parent, child, edge);
LOG.debug("Creating new edge " + new_edge + " in PartitionTree");
LOG.debug(new_edge.debug(ptree));
child.setAttribute(ptree, PartitionTree.VertexAttributes.ATTRIBUTE.name(), CollectionUtil.first(entries));
child.setAttribute(ptree, PartitionTree.VertexAttributes.METHOD.name(), PartitionMethodType.MAP);
//
// For now we can only link ourselves to the
// parent's attribute
//
child.setAttribute(ptree, PartitionTree.VertexAttributes.PARENT_ATTRIBUTE.name(), parent.getAttribute(ptree, PartitionTree.VertexAttributes.ATTRIBUTE.name()));
// if
// (parent.getTable().getName().equals("DISTRICT"))
// {
// System.out.println(parent.getTable().getName() +
// "." + parent_attribute.getName() + " -> " +
// child.getTable().getName() + "." +
// CollectionUtil.getFirst(entries).getName());
// System.exit(1);
// }
} catch (Exception ex) {
LOG.fatal(ex.getMessage());
ex.printStackTrace();
System.exit(1);
}
break;
}
} // FOR
} // FOR
for (DesignerVertex child : next_to_visit) {
this.buildPartitionTree(ptree, child, agraph, hints);
}
//
// If the current parent doesn't have any children, then we
// we need to decide how to partition it based on the
// self-referencing edges
//
} else if (is_root || !ptree.containsVertex(parent)) {
LOG.debug("Parent " + parent + " does not have any children");
DesignerEdge partition_edge = null;
double max_weight = 0;
for (DesignerEdge edge : agraph.getIncidentEdges(parent)) {
AccessGraph.AccessType type = (AccessGraph.AccessType) edge.getAttribute(AccessGraph.EdgeAttributes.ACCESSTYPE.name());
if (type != AccessGraph.AccessType.SCAN)
continue;
Double weight = 0.0d; // FIXME
// (Double)edge.getAttribute(AccessGraph.EdgeAttributes.WEIGHT.name());
if (weight > max_weight) {
partition_edge = edge;
max_weight = weight;
}
} // FOR
if (partition_edge != null) {
PredicatePairs cset = (PredicatePairs) partition_edge.getAttribute(AccessGraph.EdgeAttributes.COLUMNSET.name());
Collection<Column> attributes = cset.findAllForParent(Column.class, parent_table);
parent.setAttribute(ptree, PartitionTree.VertexAttributes.ATTRIBUTE.name(), CollectionUtil.first(attributes));
parent.setAttribute(ptree, PartitionTree.VertexAttributes.METHOD.name(), PartitionMethodType.HASH);
LOG.debug(parent + parent.debug(ptree));
} else {