1
0
Fork 0

Implement clear unneeded registers.

This commit is contained in:
Max Neunhoeffer 2014-08-22 17:00:53 +02:00
parent e5f09bfd87
commit 8fd6cd1184
9 changed files with 290 additions and 51 deletions

View File

@ -118,6 +118,34 @@ void AqlItemBlock::shrink (size_t nrItems) {
_nrItems = nrItems; _nrItems = nrItems;
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief clears out some columns (registers), this deletes the values if
/// necessary, using the reference count.
////////////////////////////////////////////////////////////////////////////////
void AqlItemBlock::clearRegisters (std::unordered_set<RegisterId>& toClear) {
for (auto reg : toClear) {
for (size_t i = 0; i < _nrItems; i++) {
AqlValue& a(_data[_nrRegs * i + reg]);
if (! a.isEmpty()) {
auto it = _valueCount.find(a);
if (it != _valueCount.end()) {
if (--it->second == 0) {
try {
_valueCount.erase(it);
}
catch (...) {
it->second++;
throw;
}
}
}
a.erase();
}
}
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief slice/clone, this does a deep copy of all entries /// @brief slice/clone, this does a deep copy of all entries
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -239,6 +239,13 @@ namespace triagens {
void shrink (size_t nrItems); void shrink (size_t nrItems);
////////////////////////////////////////////////////////////////////////////////
/// @brief clears out some columns (registers), this deletes the values if
/// necessary, using the reference count.
////////////////////////////////////////////////////////////////////////////////
void clearRegisters (std::unordered_set<RegisterId>& toClear);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief slice/clone, this does a deep copy of all entries /// @brief slice/clone, this does a deep copy of all entries
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -194,6 +194,45 @@ void ExecutionBlock::walk (WalkerWorker<ExecutionBlock>* worker) {
/// @brief static analysis /// @brief static analysis
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
struct StaticAnalysisDebugger : public WalkerWorker<ExecutionBlock> {
StaticAnalysisDebugger () : indent(0) {};
~StaticAnalysisDebugger () {};
int indent;
bool enterSubquery (ExecutionBlock* super, ExecutionBlock* sub) {
indent++;
return true;
}
void leaveSubquery (ExecutionBlock* super, ExecutionBlock* sub) {
indent--;
}
void after (ExecutionBlock* eb) {
ExecutionNode const* ep = eb->getPlanNode();
for (int i = 0; i < indent; i++) {
std::cout << " ";
}
std::cout << ep->getTypeString() << " ";
std::cout << "regsUsedHere: ";
for (auto v : ep->getVariablesUsedHere()) {
std::cout << eb->_varOverview->varInfo.find(v->id)->second.registerId
<< " ";
}
std::cout << "regsSetHere: ";
for (auto v : ep->getVariablesSetHere()) {
std::cout << eb->_varOverview->varInfo.find(v->id)->second.registerId
<< " ";
}
std::cout << "regsToClear: ";
for (auto r : eb->_regsToClear) {
std::cout << r << " ";
}
std::cout << std::endl;
}
};
void ExecutionBlock::staticAnalysis (ExecutionBlock* super) { void ExecutionBlock::staticAnalysis (ExecutionBlock* super) {
// The super is only for the case of subqueries. // The super is only for the case of subqueries.
shared_ptr<VarOverview> v; shared_ptr<VarOverview> v;
@ -211,6 +250,14 @@ void ExecutionBlock::staticAnalysis (ExecutionBlock* super) {
sq->getSubquery()->staticAnalysis(s); sq->getSubquery()->staticAnalysis(s);
} }
v->reset(); v->reset();
// Just for debugging:
/*
std::cout << std::endl;
StaticAnalysisDebugger debugger;
walk(&debugger);
std::cout << std::endl;
*/
} }
int ExecutionBlock::initialize () { int ExecutionBlock::initialize () {
@ -250,19 +297,20 @@ void ExecutionBlock::inheritRegisters (AqlItemBlock const* src,
RegisterId const n = src->getNrRegs(); RegisterId const n = src->getNrRegs();
for (RegisterId i = 0; i < n; i++) { for (RegisterId i = 0; i < n; i++) {
if (! src->getValue(row, i).isEmpty()) { if (_regsToClear.find(i) == _regsToClear.end()) {
AqlValue a = src->getValue(row, i).clone(); if (! src->getValue(row, i).isEmpty()) {
try { AqlValue a = src->getValue(row, i).clone();
dst->setValue(0, i, a); try {
} dst->setValue(0, i, a);
catch (...) { }
a.destroy(); catch (...) {
throw; a.destroy();
throw;
}
} }
// copy collection
dst->setDocumentCollection(i, src->getDocumentCollection(i));
} }
// copy collection
dst->setDocumentCollection(i, src->getDocumentCollection(i));
} }
} }
@ -281,7 +329,14 @@ bool ExecutionBlock::getBlock (size_t atLeast, size_t atMost) {
return true; return true;
} }
AqlItemBlock* ExecutionBlock::getSome (size_t atLeast, size_t atMost) { AqlItemBlock* ExecutionBlock::getSome(size_t atLeast, size_t atMost) {
std::unique_ptr<AqlItemBlock> result(getSomeWithoutRegisterClearout(atLeast, atMost));
clearRegisters(result.get());
return result.release();
}
AqlItemBlock* ExecutionBlock::getSomeWithoutRegisterClearout (
size_t atLeast, size_t atMost) {
TRI_ASSERT(0 < atLeast && atLeast <= atMost); TRI_ASSERT(0 < atLeast && atLeast <= atMost);
size_t skipped = 0; size_t skipped = 0;
AqlItemBlock* result = nullptr; AqlItemBlock* result = nullptr;
@ -292,6 +347,13 @@ AqlItemBlock* ExecutionBlock::getSome (size_t atLeast, size_t atMost) {
return result; return result;
} }
void ExecutionBlock::clearRegisters (AqlItemBlock* result) {
// Clear out registers not needed later on:
if (result != nullptr) {
result->clearRegisters(_regsToClear);
}
}
size_t ExecutionBlock::skipSome (size_t atLeast, size_t atMost) { size_t ExecutionBlock::skipSome (size_t atLeast, size_t atMost) {
TRI_ASSERT(0 < atLeast && atLeast <= atMost); TRI_ASSERT(0 < atLeast && atLeast <= atMost);
size_t skipped = 0; size_t skipped = 0;
@ -656,6 +718,8 @@ AqlItemBlock* EnumerateCollectionBlock::getSome (size_t atLeast,
} }
} }
} }
// Clear out registers no longer needed later:
clearRegisters(res.get());
return res.release(); return res.release();
} }
@ -831,6 +895,8 @@ AqlItemBlock* IndexRangeBlock::getSome (size_t atLeast,
} }
} }
} }
// Clear out registers no longer needed later:
clearRegisters(res.get());
return res.release(); return res.release();
} }
@ -1048,6 +1114,9 @@ AqlItemBlock* EnumerateListBlock::getSome (size_t atLeast, size_t atMost) {
} }
while (res.get() == nullptr); while (res.get() == nullptr);
// Clear out registers no longer needed later:
clearRegisters(res.get());
return res.release(); return res.release();
} }
@ -1249,13 +1318,16 @@ void CalculationBlock::doEvaluation (AqlItemBlock* result) {
AqlItemBlock* CalculationBlock::getSome (size_t atLeast, AqlItemBlock* CalculationBlock::getSome (size_t atLeast,
size_t atMost) { size_t atMost) {
unique_ptr<AqlItemBlock> res(ExecutionBlock::getSome(atLeast, atMost)); unique_ptr<AqlItemBlock> res(ExecutionBlock::getSomeWithoutRegisterClearout(
atLeast, atMost));
if (res.get() == nullptr) { if (res.get() == nullptr) {
return nullptr; return nullptr;
} }
doEvaluation(res.get()); doEvaluation(res.get());
// Clear out registers no longer needed later:
clearRegisters(res.get());
return res.release(); return res.release();
} }
@ -1282,7 +1354,8 @@ int SubqueryBlock::initialize () {
AqlItemBlock* SubqueryBlock::getSome (size_t atLeast, AqlItemBlock* SubqueryBlock::getSome (size_t atLeast,
size_t atMost) { size_t atMost) {
unique_ptr<AqlItemBlock> res(ExecutionBlock::getSome(atLeast, atMost)); unique_ptr<AqlItemBlock> res(ExecutionBlock::getSomeWithoutRegisterClearout(
atLeast, atMost));
if (res.get() == nullptr) { if (res.get() == nullptr) {
return nullptr; return nullptr;
@ -1315,6 +1388,8 @@ AqlItemBlock* SubqueryBlock::getSome (size_t atLeast,
throw; throw;
} }
} }
// Clear out registers no longer needed later:
clearRegisters(res.get());
return res.release(); return res.release();
} }
@ -2029,7 +2104,7 @@ int LimitBlock::getOrSkipSome (size_t atLeast,
AqlItemBlock* ReturnBlock::getSome (size_t atLeast, AqlItemBlock* ReturnBlock::getSome (size_t atLeast,
size_t atMost) { size_t atMost) {
auto res = ExecutionBlock::getSome(atLeast, atMost); auto res = ExecutionBlock::getSomeWithoutRegisterClearout(atLeast, atMost);
if (res == nullptr) { if (res == nullptr) {
return res; return res;
@ -2107,7 +2182,7 @@ AqlItemBlock* ModificationBlock::getSome (size_t atLeast,
// loop over input until it is exhausted // loop over input until it is exhausted
try { try {
while (true) { while (true) {
auto res = ExecutionBlock::getSome(atLeast, atMost); auto res = ExecutionBlock::getSomeWithoutRegisterClearout(atLeast, atMost);
if (res == nullptr) { if (res == nullptr) {
break; break;
@ -2707,6 +2782,28 @@ void ExecutionBlock::VarOverview::after (ExecutionBlock *eb) {
} }
eb->_depth = depth; eb->_depth = depth;
eb->_varOverview = *me; eb->_varOverview = *me;
// Now find out which registers ought to be erased after this node:
auto ep = eb->getPlanNode();
if (ep->getType() != ExecutionNode::RETURN) {
// ReturnBlocks are special, since they return a single column anyway
std::unordered_set<Variable const*> const& varsUsedLater = ep->getVarsUsedLater();
std::vector<Variable const*> const& varsUsedHere = ep->getVariablesUsedHere();
// We need to delete those variables that have been used here but are not
// used any more later:
std::unordered_set<RegisterId> regsToClear;
for (auto v : varsUsedHere) {
auto it = varsUsedLater.find(v);
if (it == varsUsedLater.end()) {
auto it2 = varInfo.find(v->id);
TRI_ASSERT(it2 != varInfo.end());
RegisterId r = it2->second.registerId;
regsToClear.insert(r);
}
}
eb->setRegsToClear(regsToClear);
}
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -294,6 +294,27 @@ namespace triagens {
virtual AqlItemBlock* getSome (size_t atLeast, size_t atMost); virtual AqlItemBlock* getSome (size_t atLeast, size_t atMost);
////////////////////////////////////////////////////////////////////////////////
/// @brief getSomeWithoutRegisterClearout, same as above, however, this
/// is the actual worker which does not clear out registers at the end
/// the idea is that somebody who wants to call the generic functionality
/// in a derived class but wants to modify the results before the register
/// cleanup can use this method, internal use only
////////////////////////////////////////////////////////////////////////////////
protected:
AqlItemBlock* getSomeWithoutRegisterClearout (size_t atLeast, size_t atMost);
////////////////////////////////////////////////////////////////////////////////
/// @brief clearRegisters, clears out registers holding values that are no
/// longer needed by later nodes
////////////////////////////////////////////////////////////////////////////////
void clearRegisters (AqlItemBlock* result);
public:
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief getSome, skips some more items, semantic is as follows: not /// @brief getSome, skips some more items, semantic is as follows: not
/// more than atMost items may be skipped. The method tries to /// more than atMost items may be skipped. The method tries to
@ -320,6 +341,14 @@ namespace triagens {
return _exeNode; return _exeNode;
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief set regs to be deleted
////////////////////////////////////////////////////////////////////////////////
void setRegsToClear (std::unordered_set<RegisterId>& toClear) {
_regsToClear = toClear;
}
protected: protected:
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -372,6 +401,7 @@ namespace triagens {
/// @brief info about variables, filled in by staticAnalysis /// @brief info about variables, filled in by staticAnalysis
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
public:
std::shared_ptr<VarOverview> _varOverview; std::shared_ptr<VarOverview> _varOverview;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -392,6 +422,16 @@ namespace triagens {
bool _done; bool _done;
////////////////////////////////////////////////////////////////////////////////
/// @brief the following contains the registers which should be cleared
/// just before this node hands on results. This is computed during
/// the static analysis for each node using the variable usage in the plan.
////////////////////////////////////////////////////////////////////////////////
public:
std::unordered_set<RegisterId> _regsToClear;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- public variables // --SECTION-- public variables
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -635,7 +635,7 @@ struct SubqueryVarUsageFinder : public WalkerWorker<ExecutionNode> {
/// @brief getVariablesUsedHere /// @brief getVariablesUsedHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::vector<Variable const*> SubqueryNode::getVariablesUsedHere () { std::vector<Variable const*> SubqueryNode::getVariablesUsedHere () const {
SubqueryVarUsageFinder finder; SubqueryVarUsageFinder finder;
_subquery->walk(&finder); _subquery->walk(&finder);
@ -755,6 +755,50 @@ void AggregateNode::toJsonHelper (triagens::basics::Json& nodes,
nodes(json); nodes(json);
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief getVariablesUsedHere
////////////////////////////////////////////////////////////////////////////////
struct UserVarFinder : public WalkerWorker<ExecutionNode> {
UserVarFinder () {};
~UserVarFinder () {};
std::vector<Variable const*> userVars;
bool enterSubquery (ExecutionNode* super, ExecutionNode* sub) {
return false;
}
void before (ExecutionNode* en) {
auto vars = en->getVariablesSetHere();
for (auto v : vars) {
if (v->isUserDefined()) {
userVars.push_back(v);
}
}
}
};
std::vector<Variable const*> AggregateNode::getVariablesUsedHere () const {
std::unordered_set<Variable const*> v;
for (auto p : _aggregateVariables) {
v.insert(p.second);
}
if (_outVariable != nullptr) {
// Here we have to find all user defined variables in this query
// amonst our dependencies:
UserVarFinder finder;
auto myselfasnonconst = const_cast<AggregateNode*>(this);
myselfasnonconst->walk(&finder);
for (auto x : finder.userVars) {
v.insert(x);
}
}
std::vector<Variable const*> vv;
for (auto x : v) {
vv.push_back(x);
}
return vv;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- methods of ReturnNode // --SECTION-- methods of ReturnNode
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -364,7 +364,7 @@ namespace triagens {
/// @brief getVariablesUsedHere /// @brief getVariablesUsedHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesUsedHere () { virtual std::vector<Variable const*> getVariablesUsedHere () const {
return std::vector<Variable const*>(); return std::vector<Variable const*>();
} }
@ -372,7 +372,7 @@ namespace triagens {
/// @brief getVariablesSetHere /// @brief getVariablesSetHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesSetHere () { virtual std::vector<Variable const*> getVariablesSetHere () const {
return std::vector<Variable const*>(); return std::vector<Variable const*>();
} }
@ -388,7 +388,7 @@ namespace triagens {
/// @brief getVarsUsedLater /// @brief getVarsUsedLater
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::unordered_set<Variable const*>& getVarsUsedLater () { std::unordered_set<Variable const*> const& getVarsUsedLater () const {
TRI_ASSERT(_varUsageValid); TRI_ASSERT(_varUsageValid);
return _varsUsedLater; return _varsUsedLater;
} }
@ -405,7 +405,7 @@ namespace triagens {
/// @brief getVarsValid /// @brief getVarsValid
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::unordered_set<Variable const*>& getVarsValid () { std::unordered_set<Variable const*> const& getVarsValid () const {
TRI_ASSERT(_varUsageValid); TRI_ASSERT(_varUsageValid);
return _varsValid; return _varsValid;
} }
@ -648,7 +648,7 @@ namespace triagens {
/// @brief getVariablesSetHere /// @brief getVariablesSetHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesSetHere () { virtual std::vector<Variable const*> getVariablesSetHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
v.push_back(_outVariable); v.push_back(_outVariable);
return v; return v;
@ -770,7 +770,7 @@ namespace triagens {
/// @brief getVariablesUsedHere /// @brief getVariablesUsedHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesUsedHere () { virtual std::vector<Variable const*> getVariablesUsedHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
v.push_back(_inVariable); v.push_back(_inVariable);
return v; return v;
@ -780,7 +780,7 @@ namespace triagens {
/// @brief getVariablesSetHere /// @brief getVariablesSetHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesSetHere () { virtual std::vector<Variable const*> getVariablesSetHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
v.push_back(_outVariable); v.push_back(_outVariable);
return v; return v;
@ -885,7 +885,7 @@ namespace triagens {
/// @brief getVariablesSetHere /// @brief getVariablesSetHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesSetHere () { virtual std::vector<Variable const*> getVariablesSetHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
v.push_back(_outVariable); v.push_back(_outVariable);
return v; return v;
@ -1110,7 +1110,7 @@ namespace triagens {
/// @brief getVariablesUsedHere /// @brief getVariablesUsedHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesUsedHere () { virtual std::vector<Variable const*> getVariablesUsedHere () const {
std::unordered_set<Variable*> vars = _expression->variables(); std::unordered_set<Variable*> vars = _expression->variables();
std::vector<Variable const*> v; std::vector<Variable const*> v;
for (auto vv : vars) { for (auto vv : vars) {
@ -1123,7 +1123,7 @@ namespace triagens {
/// @brief getVariablesSetHere /// @brief getVariablesSetHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesSetHere () { virtual std::vector<Variable const*> getVariablesSetHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
v.push_back(_outVariable); v.push_back(_outVariable);
return v; return v;
@ -1248,13 +1248,13 @@ namespace triagens {
/// @brief getVariablesUsedHere /// @brief getVariablesUsedHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesUsedHere (); virtual std::vector<Variable const*> getVariablesUsedHere () const;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief getVariablesSetHere /// @brief getVariablesSetHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesSetHere () { virtual std::vector<Variable const*> getVariablesSetHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
v.push_back(_outVariable); v.push_back(_outVariable);
return v; return v;
@ -1358,7 +1358,7 @@ namespace triagens {
/// @brief getVariablesUsedHere /// @brief getVariablesUsedHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesUsedHere () { virtual std::vector<Variable const*> getVariablesUsedHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
v.push_back(_inVariable); v.push_back(_inVariable);
return v; return v;
@ -1442,7 +1442,7 @@ namespace triagens {
/// @brief getVariablesUsedHere /// @brief getVariablesUsedHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesUsedHere () { virtual std::vector<Variable const*> getVariablesUsedHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
for (auto p : _elements) { for (auto p : _elements) {
v.push_back(p.first); v.push_back(p.first);
@ -1541,19 +1541,13 @@ namespace triagens {
/// @brief getVariablesUsedHere /// @brief getVariablesUsedHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesUsedHere () { virtual std::vector<Variable const*> getVariablesUsedHere () const;
std::vector<Variable const*> v;
for (auto p : _aggregateVariables) {
v.push_back(p.second);
}
return v;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief getVariablesSetHere /// @brief getVariablesSetHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesSetHere () { virtual std::vector<Variable const*> getVariablesSetHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
for (auto p : _aggregateVariables) { for (auto p : _aggregateVariables) {
v.push_back(p.first); v.push_back(p.first);
@ -1658,7 +1652,7 @@ namespace triagens {
/// @brief getVariablesUsedHere /// @brief getVariablesUsedHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesUsedHere () { virtual std::vector<Variable const*> getVariablesUsedHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
v.push_back(_inVariable); v.push_back(_inVariable);
return v; return v;
@ -1815,7 +1809,7 @@ namespace triagens {
/// @brief getVariablesUsedHere /// @brief getVariablesUsedHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesUsedHere () { virtual std::vector<Variable const*> getVariablesUsedHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
v.push_back(_inVariable); v.push_back(_inVariable);
return v; return v;
@ -1825,7 +1819,7 @@ namespace triagens {
/// @brief getVariablesSetHere /// @brief getVariablesSetHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesSetHere () { virtual std::vector<Variable const*> getVariablesSetHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
if (_outVariable != nullptr) { if (_outVariable != nullptr) {
v.push_back(_outVariable); v.push_back(_outVariable);
@ -1927,7 +1921,7 @@ namespace triagens {
/// @brief getVariablesUsedHere /// @brief getVariablesUsedHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesUsedHere () { virtual std::vector<Variable const*> getVariablesUsedHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
v.push_back(_inVariable); v.push_back(_inVariable);
return v; return v;
@ -1937,7 +1931,7 @@ namespace triagens {
/// @brief getVariablesSetHere /// @brief getVariablesSetHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesSetHere () { virtual std::vector<Variable const*> getVariablesSetHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
if (_outVariable != nullptr) { if (_outVariable != nullptr) {
v.push_back(_outVariable); v.push_back(_outVariable);
@ -2042,7 +2036,7 @@ namespace triagens {
/// @brief getVariablesUsedHere /// @brief getVariablesUsedHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesUsedHere () { virtual std::vector<Variable const*> getVariablesUsedHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
v.push_back(_inDocVariable); v.push_back(_inDocVariable);
@ -2056,7 +2050,7 @@ namespace triagens {
/// @brief getVariablesSetHere /// @brief getVariablesSetHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesSetHere () { virtual std::vector<Variable const*> getVariablesSetHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
if (_outVariable != nullptr) { if (_outVariable != nullptr) {
v.push_back(_outVariable); v.push_back(_outVariable);
@ -2167,7 +2161,7 @@ namespace triagens {
/// @brief getVariablesUsedHere /// @brief getVariablesUsedHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesUsedHere () { virtual std::vector<Variable const*> getVariablesUsedHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
v.push_back(_inDocVariable); v.push_back(_inDocVariable);
@ -2181,7 +2175,7 @@ namespace triagens {
/// @brief getVariablesSetHere /// @brief getVariablesSetHere
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual std::vector<Variable const*> getVariablesSetHere () { virtual std::vector<Variable const*> getVariablesSetHere () const {
std::vector<Variable const*> v; std::vector<Variable const*> v;
if (_outVariable != nullptr) { if (_outVariable != nullptr) {
v.push_back(_outVariable); v.push_back(_outVariable);

View File

@ -53,6 +53,7 @@ using JsonHelper = triagens::basics::JsonHelper;
ExecutionPlan::ExecutionPlan () ExecutionPlan::ExecutionPlan ()
: _ids(), : _ids(),
_root(nullptr), _root(nullptr),
_varUsageComputed(false),
_nextId(0) { _nextId(0) {
} }
@ -997,6 +998,15 @@ void ExecutionPlan::findVarUsage () {
VarUsageFinder finder; VarUsageFinder finder;
root()->walk(&finder); root()->walk(&finder);
_varSetBy = finder._varSetBy; _varSetBy = finder._varSetBy;
_varUsageComputed = true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief determine if the above are already set
////////////////////////////////////////////////////////////////////////////////
bool ExecutionPlan::varUsageComputed () {
return _varUsageComputed;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1033,6 +1043,7 @@ void ExecutionPlan::unlinkNode (ExecutionNode* node) {
node->removeDependency(x); node->removeDependency(x);
} }
} }
_varUsageComputed = false;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1060,6 +1071,7 @@ void ExecutionPlan::replaceNode (ExecutionNode* oldNode,
"Could not replace dependencies of an old node."); "Could not replace dependencies of an old node.");
} }
} }
_varUsageComputed = false;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1082,6 +1094,7 @@ void ExecutionPlan::insertDependency (ExecutionNode* oldNode,
newNode->removeDependencies(); newNode->removeDependencies();
newNode->addDependency(oldDeps[0]); newNode->addDependency(oldDeps[0]);
_varUsageComputed = false;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1109,7 +1122,9 @@ ExecutionPlan* ExecutionPlan::clone (){
plan->_nextId = _nextId; plan->_nextId = _nextId;
CloneNodeAdder adder(plan); CloneNodeAdder adder(plan);
plan->_root->walk(&adder); plan->_root->walk(&adder);
plan->findVarUsage(); // plan->findVarUsage();
// Let's not do it here, because supposedly the plan is modified as
// the very next thing anyway!
return plan; return plan;
} }
catch (...) { catch (...) {

View File

@ -155,11 +155,17 @@ namespace triagens {
void checkLinkage (); void checkLinkage ();
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief determine and set _varsUsedLater in all nodes /// @brief determine and set _varsUsedLater and _valid and _varSetBy
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void findVarUsage (); void findVarUsage ();
////////////////////////////////////////////////////////////////////////////////
/// @brief determine if the above are already set
////////////////////////////////////////////////////////////////////////////////
bool varUsageComputed ();
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief unlinkNodes, note that this does not delete the removed /// @brief unlinkNodes, note that this does not delete the removed
/// nodes and that one cannot remove the root node of the plan. /// nodes and that one cannot remove the root node of the plan.
@ -358,6 +364,12 @@ namespace triagens {
std::unordered_map<VariableId, ExecutionNode*> _varSetBy; std::unordered_map<VariableId, ExecutionNode*> _varSetBy;
////////////////////////////////////////////////////////////////////////////////
/// @brief flag to indicate whether the variable usage is computed
////////////////////////////////////////////////////////////////////////////////
bool _varUsageComputed;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief auto-increment sequence for node ids /// @brief auto-increment sequence for node ids
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -89,7 +89,9 @@ int Optimizer::createPlans (ExecutionPlan* plan) {
// Find variable usage for all old plans now: // Find variable usage for all old plans now:
for (auto p : oldPlans.list) { for (auto p : oldPlans.list) {
p->findVarUsage(); if (! p->varUsageComputed()) {
p->findVarUsage();
}
} }
// For all rules: // For all rules: