// Starting at the current vertex, get all vertices at the next depth
// level
SortedSet<DesignerVertex> next = new TreeSet<DesignerVertex>(new VertexComparator(agraph, parent));
int parent_depth = ptree.getDepth(parent);
Table parent_table = parent.getCatalogItem();
LOG.debug("===============================================");
LOG.debug("Current Parent: " + parent + " " + parent.getAttributes(ptree));
LOG.debug("Current Depth: " + parent_depth);
LOG.debug("Successors: " + agraph.getSuccessors(parent));
// Look through all the vertices that our parent is adjacent to in the
// AccessGraph
// and come up with a list of the next vertices to visit
DesignerVertex parent_root = ptree.getRoot(parent);
for (DesignerVertex vertex : agraph.getSuccessors(parent)) {
boolean force = false;
Table vertex_tbl = vertex.getCatalogItem();
// Skip any self-references
if (vertex == parent)
continue;
// Skip any vertices that are marked as replicated
if (ptree.isReplicated(vertex)) {
LOG.debug("Skipping " + vertex + " because it is already marked for replication");
continue;
}
// Force dependencies
if (hints.force_dependency.containsKey(CatalogKey.createKey(vertex_tbl))) {
String force_dependency = hints.force_dependency.get(CatalogKey.createKey(vertex_tbl));
// We'll force this We're allowed to break this forced
// dependency if the current parent
// is a descendant of the table that the child should be forced
// to
if (force_dependency != null) {
Table force_tbl = CatalogKey.getFromKey(info.catalogContext.database, force_dependency, Table.class);
if (parent_table.equals(force_tbl)) {
force = true;
LOG.debug("Forcing dependency: " + parent_table + "->" + vertex_tbl);
} else if (info.dependencies.getDescendants(force_tbl).contains(parent_table) && (ptree.containsVertex(vertex) || hints.force_replication.contains(force_dependency))) {
LOG.debug("Allowing take over of dependency: " + parent_table + "->" + vertex_tbl);
} else {
LOG.debug("Not allowing: " + parent_table + "->" + vertex_tbl);
LOG.debug(info.dependencies.getDescendants(force_tbl));
LOG.debug("ptree.containsVertex: " + ptree.containsVertex(vertex));
continue;
}
}
}
// We then need to check whether the current parent table is a
// descendant of
// the other vertex in the DependencyGraph. This to check that you
// don't violate
// a foreign key dependency that may be several vertices removed
List<DesignerEdge> path = info.dgraph.getPath(vertex, parent);
if (!path.isEmpty()) {
LOG.debug("Skipping " + vertex + " because it is an ancestor of " + parent + " in the DependencyGraph");
continue;
}
// If this vertex is already in the PartitionTree, we need to check
// whether our
// current parent has an edge with a greater weight to the vertex
// than the one it
// currently has in the tree.
//
// What if the other vertex is a direct ascendant of the current
// parent? That means
// if we break the edge then the whole path will get messed up and
// all the vertices
// will be orphans again. Therefore, I think it should only move the
// vertex if
// the edge is greater *AND* it's not an ascendant of the current
// parent.
if (ptree.containsVertex(vertex)) {
if (ptree.getPath(parent).contains(vertex)) {
LOG.debug("Skipping " + vertex + " because it is an ancestor of " + parent + " in the PartitionTree");
continue;
}
// Now look to whether there is a new Edge in the AccessGraph
// with a greater
// weight than the one that is currently being used in the
// PartitionTree
// We will only move the vertex if it's in the same tree
DesignerVertex vertex_orig_parent = ptree.getParent(vertex);
if (vertex_orig_parent != null) {
// Check whether these guys have the same root
// If they don't, then we won't move the child.
DesignerVertex child_root = ptree.getRoot(vertex);
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.