diff --git a/arangod/Aql/ExecutionNode.h b/arangod/Aql/ExecutionNode.h index cc70ee447c..c399d8933b 100644 --- a/arangod/Aql/ExecutionNode.h +++ b/arangod/Aql/ExecutionNode.h @@ -709,6 +709,16 @@ namespace triagens { //FIXME improve this estimate . . . } +//////////////////////////////////////////////////////////////////////////////// +/// @brief getVariablesSetHere +//////////////////////////////////////////////////////////////////////////////// + + virtual std::vector getVariablesSetHere () { + std::vector v; + v.push_back(_outVariable); + return v; + } + // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- @@ -1548,6 +1558,28 @@ namespace triagens { // TODO: improve this estimate! } +//////////////////////////////////////////////////////////////////////////////// +/// @brief getVariablesUsedHere +//////////////////////////////////////////////////////////////////////////////// + + virtual std::vector getVariablesUsedHere () { + std::vector v; + v.push_back(_inVariable); + return v; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief getVariablesSetHere +//////////////////////////////////////////////////////////////////////////////// + + virtual std::vector getVariablesSetHere () { + std::vector v; + if (_outVariable != nullptr) { + v.push_back(_outVariable); + } + return v; + } + // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- @@ -1635,6 +1667,28 @@ namespace triagens { return 1000 * _dependencies.at(0)->getCost(); //FIXME change this! } +//////////////////////////////////////////////////////////////////////////////// +/// @brief getVariablesUsedHere +//////////////////////////////////////////////////////////////////////////////// + + virtual std::vector getVariablesUsedHere () { + std::vector v; + v.push_back(_inVariable); + return v; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief getVariablesSetHere +//////////////////////////////////////////////////////////////////////////////// + + virtual std::vector getVariablesSetHere () { + std::vector v; + if (_outVariable != nullptr) { + v.push_back(_outVariable); + } + return v; + } + // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- diff --git a/arangod/Aql/ExecutionPlan.cpp b/arangod/Aql/ExecutionPlan.cpp index 5a280cef5d..96d5ca1dfd 100644 --- a/arangod/Aql/ExecutionPlan.cpp +++ b/arangod/Aql/ExecutionPlan.cpp @@ -832,6 +832,56 @@ void ExecutionPlan::findVarUsage () { root()->walk(&finder); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief removeNodes +//////////////////////////////////////////////////////////////////////////////// + +struct NodeRemover : public WalkerWorker { + + ExecutionPlan* _plan; + std::unordered_set& _toRemove; + std::vector parents; + + NodeRemover (ExecutionPlan* plan, + std::unordered_set& toRemove) + : _plan(plan), _toRemove(toRemove) { + } + + ~NodeRemover () { + }; + + void before (ExecutionNode* en) { + if (_toRemove.find(en) != _toRemove.end()) { + // Remove this node: + if (parents.size() == 0) { + THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, + "Cannot remove root node of plan."); + } + else { + auto dep = en->getDependencies(); + parents.back()->removeDependency(en); + if (dep.size() == 1) { + parents.back()->addDependency(dep[0]); + } + else if (dep.size() > 1) { + THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, + "Cannot remove node with more than one dependency."); + } + } + } + parents.push_back(en); + } + + void after (ExecutionNode* en) { + parents.pop_back(); + } +}; + +void ExecutionPlan::removeNodes (std::unordered_set& toRemove) { + NodeRemover remover(this, toRemove); + root()->walk(&remover); +} + // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- diff --git a/arangod/Aql/ExecutionPlan.h b/arangod/Aql/ExecutionPlan.h index f05af05dbe..49954523c3 100644 --- a/arangod/Aql/ExecutionPlan.h +++ b/arangod/Aql/ExecutionPlan.h @@ -110,6 +110,13 @@ namespace triagens { void findVarUsage (); +//////////////////////////////////////////////////////////////////////////////// +/// @brief removeNodes, note that this does not delete the removed +/// nodes and that one cannot remove the root node of the plan. +//////////////////////////////////////////////////////////////////////////////// + + void removeNodes (std::unordered_set& toRemove); + // ----------------------------------------------------------------------------- // --SECTION-- private methods // ----------------------------------------------------------------------------- @@ -251,7 +258,7 @@ namespace triagens { std::vector _nodes; //////////////////////////////////////////////////////////////////////////////// -/// @brief root node of the engine +/// @brief root node of the plan //////////////////////////////////////////////////////////////////////////////// ExecutionNode* _root; diff --git a/arangod/Aql/Optimizer.cpp b/arangod/Aql/Optimizer.cpp index c1058e1a71..9bfedfbe04 100644 --- a/arangod/Aql/Optimizer.cpp +++ b/arangod/Aql/Optimizer.cpp @@ -41,7 +41,8 @@ using namespace triagens::aql; Optimizer::Optimizer () { // List all the rules in the system here: registerRule (relaxRule, 1000); - registerRule (removeUnnecessaryCalc, 999); + // registerRule (removeUnnecessaryCalc, 999); + // deactivated because a test crashes // Now sort them by pass: std::stable_sort(_rules.begin(), _rules.end()); @@ -65,6 +66,9 @@ int Optimizer::createPlans (ExecutionPlan* plan) { _plans.clear(); for (int pass = 1; pass <= numberOfPasses; pass++) { + std::cout << "Entering pass " << pass << " of query optimization..." + << std::endl; + // This vector holds the plans we have created in this pass: PlanList newPlans; diff --git a/arangod/Aql/OptimizerRules.cpp b/arangod/Aql/OptimizerRules.cpp index e8badfbaf0..caf71ed68d 100644 --- a/arangod/Aql/OptimizerRules.cpp +++ b/arangod/Aql/OptimizerRules.cpp @@ -55,7 +55,32 @@ int triagens::aql::removeUnnecessaryCalc (Optimizer* opt, bool& keep) { std::vector nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::CALCULATION); - keep = true; + std::unordered_set toRemove; + for (auto n : nodes) { + auto nn = static_cast(n); + if (! nn->expression()->canThrow()) { + // If this node can throw, we must not optimize it away! + auto outvar = n->getVariablesSetHere(); + TRI_ASSERT(outvar.size() == 1); + auto varsUsedLater = n->getVarsUsedLater(); + if (varsUsedLater.find(outvar[0]) == varsUsedLater.end()) { + // The variable whose value is calculated here is not used at + // all further down the pipeline! We remove the whole + // calculation node, + toRemove.insert(n); + } + } + } + if (toRemove.size() > 0) { + std::cout << "Removing " << toRemove.size() << " unnecessary " + "CalculationNodes..." << std::endl; + plan->removeNodes(toRemove); + out.push_back(plan); + keep = false; + } + else { + keep = true; + } return TRI_ERROR_NO_ERROR; }