Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 92 additions & 54 deletions src/optimizer/robust_optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -797,70 +797,108 @@ vector<PhysicalDAGNode *> RobustOptimizerContextState::BuildPhysicalPlanDAG(Logi
}

void RobustOptimizerContextState::FlipRootsToLeaves(vector<PhysicalDAGNode *> &all_nodes) {
// step 1: find all roots
vector<PhysicalDAGNode *> roots;
unordered_map<idx_t, bool> visited;
vector<Component> components;
for (auto *node : all_nodes) {
if (node->parents.empty()) {
roots.push_back(node);
// step 1: find all roots
if (visited.count(node->table_idx)) {
continue;
}
vector<PhysicalDAGNode *> comp_nodes;
vector<PhysicalDAGNode *> roots;
PhysicalDAGNode *anchor;
vector<PhysicalDAGNode *> que;
auto discover = [&](PhysicalDAGNode *candidate) {
if (visited.count(candidate->table_idx)) {
return;
}
if (candidate->parents.empty()) {
roots.push_back(candidate);
}
visited[candidate->table_idx] = true;
que.push_back(candidate);
comp_nodes.push_back(candidate);
};
discover(node);
while (!que.empty()) {
auto cur = que.back();
que.pop_back();
for (auto &child : cur->children) {
discover(child);
}
for (auto &parent : cur->parents) {
discover(parent);
}
}
}
if (roots.size() <= 1) {
return;
}

// step 2: find anchor root (largest cardinality)
PhysicalDAGNode *anchor = roots[0];
for (auto *r : roots) {
if (r->table_op->estimated_cardinality > anchor->table_op->estimated_cardinality) {
anchor = r;
// step 2: find anchor root (largest cardinality)
if (roots.empty()) {
D_PRINTF("ERROR: No root found for this component");
continue;
}
anchor = roots[0];
for (auto *r : roots) {
if (r->table_op->estimated_cardinality > anchor->table_op->estimated_cardinality) {
anchor = r;
}
}
components.push_back({comp_nodes, roots, anchor});
}
for (auto &comp : components) {
auto &comp_nodes = comp.comp_nodes;
auto &roots = comp.roots;
auto *anchor = comp.anchor;
if (roots.size() <= 1) {
continue;
}

// step 3: repeatedly flip non-anchor roots until only anchor remains
// flipping a root can expose new roots (e.g. flipping name reveals aka_name)
bool flipped = true;
while (flipped) {
flipped = false;
for (auto *node : all_nodes) {
if (!node->parents.empty() || node == anchor) {
continue;
}
// non-anchor root: reverse all edges to its children
auto children_copy = node->children;
for (auto *child : children_copy) {
PhysicalDAGEdge edge;
bool found = false;
for (idx_t i = 0; i < child->parents.size(); i++) {
if (child->parents[i] == node) {
edge = child->edges_to_parents[i];
child->parents.erase(child->parents.begin() + static_cast<std::ptrdiff_t>(i));
child->edges_to_parents.erase(child->edges_to_parents.begin() + static_cast<std::ptrdiff_t>(i));
found = true;
break;
}
}
if (!found) {
// step 3: repeatedly flip non-anchor roots until only anchor remains
// flipping a root can expose new roots (e.g. flipping name reveals aka_name)
bool flipped = true;
while (flipped) {
flipped = false;
for (auto *node : comp_nodes) {
if (!node->parents.empty() || node == anchor) {
continue;
}
for (idx_t i = 0; i < node->children.size(); i++) {
if (node->children[i] == child) {
node->children.erase(node->children.begin() + static_cast<std::ptrdiff_t>(i));
break;
// non-anchor root: reverse all edges to its children
auto children_copy = node->children;
for (auto *child : children_copy) {
PhysicalDAGEdge edge;
bool found = false;
for (idx_t i = 0; i < child->parents.size(); i++) {
if (child->parents[i] == node) {
edge = child->edges_to_parents[i];
child->parents.erase(child->parents.begin() + static_cast<std::ptrdiff_t>(i));
child->edges_to_parents.erase(child->edges_to_parents.begin() +
static_cast<std::ptrdiff_t>(i));
found = true;
break;
}
}
if (!found) {
continue;
}
for (idx_t i = 0; i < node->children.size(); i++) {
if (node->children[i] == child) {
node->children.erase(node->children.begin() + static_cast<std::ptrdiff_t>(i));
break;
}
}
child->children.push_back(node);
node->parents.push_back(child);

PhysicalDAGEdge reversed;
reversed.parent_table = edge.child_table;
reversed.child_table = edge.parent_table;
reversed.parent_cols = edge.child_cols;
reversed.child_cols = edge.parent_cols;
node->edges_to_parents.push_back(reversed);

// only mark progress on a real reversal; a childless root cannot
// be flipped and must not keep this loop spinning forever
flipped = true;
}
child->children.push_back(node);
node->parents.push_back(child);

PhysicalDAGEdge reversed;
reversed.parent_table = edge.child_table;
reversed.child_table = edge.parent_table;
reversed.parent_cols = edge.child_cols;
reversed.child_cols = edge.parent_cols;
node->edges_to_parents.push_back(reversed);

// only mark progress on a real reversal; a childless root cannot
// be flipped and must not keep this loop spinning forever
flipped = true;
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/optimizer/robust_optimizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ struct PhysicalDAGNode {
}
};

struct Component {
vector<PhysicalDAGNode *> comp_nodes;
vector<PhysicalDAGNode *> roots;
PhysicalDAGNode *anchor;
};

// column key for equivalence class union-find
using ColKey = std::pair<idx_t, idx_t>; // (table_idx, column_idx)

Expand Down
Loading