1
0
Fork 0

Sort out static analysis.

This commit is contained in:
Max Neunhoeffer 2014-08-01 10:28:25 +02:00
parent 15235b1337
commit cd56e35f1f
3 changed files with 135 additions and 61 deletions

View File

@ -46,21 +46,28 @@ int ExecutionBlock::bind (std::map<std::string, struct TRI_json_s*>* params) {
/// @brief functionality to walk an execution plan recursively /// @brief functionality to walk an execution plan recursively
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void ExecutionBlock::walk (WalkerWorker& worker) { void ExecutionBlock::walk (WalkerWorker* worker) {
worker.before(this); // Only do every node exactly once:
if (worker->done(this)) {
return;
}
worker->before(this);
// Now the children in their natural order:
for (auto it = _dependencies.begin(); for (auto it = _dependencies.begin();
it != _dependencies.end(); it != _dependencies.end();
++it) { ++it) {
(*it)->walk(worker); (*it)->walk(worker);
} }
// Now handle a subquery:
if (_exePlan->getType() == ExecutionPlan::SUBQUERY) { if (_exePlan->getType() == ExecutionPlan::SUBQUERY) {
// auto p = static_cast<SubqueryBlock*>(this); // auto p = static_cast<SubqueryBlock*>(this);
if (worker.enterSubquery(this, nullptr)) { ; // p->_subquery if (worker->enterSubquery(this, nullptr)) { ; // p->_subquery
// p->_subquery->walk(worker); // p->_subquery->walk(worker);
worker.leaveSubquery(this, nullptr); // p->_subquery worker->leaveSubquery(this, nullptr); // p->_subquery
} }
} }
worker.after(this); worker->after(this);
} }

View File

@ -49,7 +49,7 @@ namespace triagens {
class ExecutionBlock { class ExecutionBlock {
public: public:
ExecutionBlock (ExecutionPlan const* ep) ExecutionBlock (ExecutionPlan const* ep)
: _exePlan(ep), _done(false), _nrVars(3), _depth(0) { } : _exePlan(ep), _done(false), _depth(0) { }
virtual ~ExecutionBlock (); virtual ~ExecutionBlock ();
@ -115,9 +115,23 @@ namespace triagens {
}; };
virtual void leaveSubquery (ExecutionBlock* super, virtual void leaveSubquery (ExecutionBlock* super,
ExecutionBlock* sub) {}; ExecutionBlock* sub) {};
bool done (ExecutionBlock* eb) {
if (_done.find(eb) == _done.end()) {
_done.insert(eb);
return false;
}
else {
return true;
}
}
void reset () {
_done.clear();
}
private:
std::unordered_set<ExecutionBlock*> _done;
}; };
void walk (WalkerWorker& worker); void walk (WalkerWorker* worker);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief static analysis, walker class and information collector /// @brief static analysis, walker class and information collector
@ -130,37 +144,54 @@ namespace triagens {
}; };
struct VarOverview : public WalkerWorker { struct VarOverview : public WalkerWorker {
// The following are collected for global usage in the ExecutionBlock:
// map VariableIds to their depth and index:
std::unordered_map<VariableId, VarInfo> varInfo; std::unordered_map<VariableId, VarInfo> varInfo;
// number of variables in the frame of the current depth:
std::vector<VariableId> nrVarsHere;
// number of variables in this and all outer frames together,
// the entry with index i here is always the sum of all values
// in nrVarsHere from index 0 to i (inclusively) and the two
// have the same length:
std::vector<VariableId> nrVars; std::vector<VariableId> nrVars;
// Local for the walk:
unsigned int depth; unsigned int depth;
unsigned int totalNrVars; unsigned int totalNrVars;
VarOverview () : depth(0), totalNrVars(0) {};
VarOverview ()
: depth(0), totalNrVars(0) {
nrVarsHere.push_back(0);
nrVars.push_back(0);
};
// Copy constructor used for a subquery:
VarOverview (VarOverview const& v)
: varInfo(v.varInfo), nrVarsHere(v.nrVars), nrVars(v.nrVars),
depth(v.depth+1), totalNrVars(v.totalNrVars) {
nrVarsHere.push_back(0);
nrVars.push_back(0);
}
~VarOverview () {}; ~VarOverview () {};
virtual bool enterSubquery (ExecutionBlock* super, virtual bool enterSubquery (ExecutionBlock* super,
ExecutionBlock* sub) { ExecutionBlock* sub) {
auto vv = new VarOverview(); auto vv = new VarOverview(*this);
sub->walk(*vv); sub->walk(vv);
return false; vv->reset();
return false; // do not walk into subquery
} }
virtual void after (ExecutionBlock *eb) { virtual void after (ExecutionBlock *eb) {
switch (eb->getPlan()->getType()) { switch (eb->getPlan()->getType()) {
case ExecutionPlan::SINGLETON: {
depth = 0;
if (nrVars.size() == 0) {
nrVars.push_back(0);
}
else {
nrVars[0] = 0;
}
break;
}
case ExecutionPlan::ENUMERATE_COLLECTION: { case ExecutionPlan::ENUMERATE_COLLECTION: {
depth++; depth++;
while (depth >= nrVars.size()) { nrVarsHere.push_back(1);
nrVars.push_back(0); nrVars.push_back(1 + nrVars.back());
}
TRI_ASSERT(nrVars[depth] == 0);
nrVars[depth] = 1;
auto ep = static_cast<EnumerateCollectionPlan const*>(eb->getPlan()); auto ep = static_cast<EnumerateCollectionPlan const*>(eb->getPlan());
varInfo.insert(make_pair(ep->_outVariable->id, varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrVars))); VarInfo(depth, totalNrVars)));
@ -169,11 +200,8 @@ namespace triagens {
} }
case ExecutionPlan::ENUMERATE_LIST: { case ExecutionPlan::ENUMERATE_LIST: {
depth++; depth++;
while (depth >= nrVars.size()) { nrVarsHere.push_back(1);
nrVars.push_back(0); nrVars.push_back(1 + nrVars.back());
}
TRI_ASSERT(nrVars[depth] == 0);
nrVars[depth] = 1;
auto ep = static_cast<EnumerateListPlan const*>(eb->getPlan()); auto ep = static_cast<EnumerateListPlan const*>(eb->getPlan());
varInfo.insert(make_pair(ep->_outVariable->id, varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrVars))); VarInfo(depth, totalNrVars)));
@ -181,6 +209,7 @@ namespace triagens {
break; break;
} }
case ExecutionPlan::CALCULATION: { case ExecutionPlan::CALCULATION: {
nrVarsHere[depth]++;
nrVars[depth]++; nrVars[depth]++;
auto ep = static_cast<CalculationPlan const*>(eb->getPlan()); auto ep = static_cast<CalculationPlan const*>(eb->getPlan());
varInfo.insert(make_pair(ep->_outVariable->id, varInfo.insert(make_pair(ep->_outVariable->id,
@ -189,6 +218,7 @@ namespace triagens {
break; break;
} }
case ExecutionPlan::PROJECTION: { case ExecutionPlan::PROJECTION: {
nrVarsHere[depth]++;
nrVars[depth]++; nrVars[depth]++;
auto ep = static_cast<ProjectionPlan const*>(eb->getPlan()); auto ep = static_cast<ProjectionPlan const*>(eb->getPlan());
varInfo.insert(make_pair(ep->_outVariable->id, varInfo.insert(make_pair(ep->_outVariable->id,
@ -196,6 +226,15 @@ namespace triagens {
totalNrVars++; totalNrVars++;
break; break;
} }
case ExecutionPlan::SUBQUERY: {
nrVarsHere[depth]++;
nrVars[depth]++;
auto ep = static_cast<SubqueryPlan const*>(eb->getPlan());
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrVars)));
totalNrVars++;
break;
}
// TODO: potentially more cases // TODO: potentially more cases
default: default:
break; break;
@ -208,7 +247,8 @@ namespace triagens {
void staticAnalysis () { void staticAnalysis () {
auto v = new VarOverview(); auto v = new VarOverview();
walk(*v); walk(v);
v->reset();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -436,12 +476,6 @@ namespace triagens {
bool _done; bool _done;
////////////////////////////////////////////////////////////////////////////////
/// @brief this is the number of variables in items coming out of this node
////////////////////////////////////////////////////////////////////////////////
VariableId _nrVars; // will be filled in by staticAnalysis
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief depth of frames (number of FOR statements here or above) /// @brief depth of frames (number of FOR statements here or above)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -521,7 +555,7 @@ namespace triagens {
return nullptr; return nullptr;
} }
AqlItemBlock* res(new AqlItemBlock(1, _nrVars)); AqlItemBlock* res(new AqlItemBlock(1, _varOverview->nrVars[_depth]));
_done = true; _done = true;
return res; return res;
} }
@ -535,7 +569,7 @@ namespace triagens {
return nullptr; return nullptr;
} }
AqlItemBlock* res(new AqlItemBlock(1, _nrVars)); AqlItemBlock* res(new AqlItemBlock(1, _varOverview->nrVars[_depth]));
_done = true; _done = true;
return res; return res;
} }
@ -662,13 +696,20 @@ namespace triagens {
// If we get here, we do have _buffer.front() // If we get here, we do have _buffer.front()
AqlItemBlock* cur = _buffer.front(); AqlItemBlock* cur = _buffer.front();
auto res = new AqlItemBlock(1, _nrVars); // Copy stuff from frames above:
TRI_ASSERT(cur->getNrVars() <= _nrVars); auto res = new AqlItemBlock(1, _varOverview->nrVars[_depth]);
TRI_ASSERT(cur->getNrVars() <= res->getNrVars());
for (VariableId i = 0; i < cur->getNrVars(); i++) { for (VariableId i = 0; i < cur->getNrVars(); i++) {
res->setValue(0, i, cur->getValue(_pos, i)->clone()); res->setValue(0, i, cur->getValue(_pos, i)->clone());
} }
// The result is in the first variable of this depth,
// we do not need to do a lookup in _varOverview->varInfo,
// but can just take cur->getNrVars() as index:
res->setValue(0, cur->getNrVars(), res->setValue(0, cur->getNrVars(),
new AqlValue( new Json(_allDocs[_posInAllDocs++]->copy()) ) ); new AqlValue( new Json(_allDocs[_posInAllDocs++]->copy()) ) );
// Advance read position:
if (_posInAllDocs >= _allDocs.size()) { if (_posInAllDocs >= _allDocs.size()) {
_posInAllDocs = 0; _posInAllDocs = 0;
if (++_pos >= cur->size()) { if (++_pos >= cur->size()) {
@ -704,15 +745,20 @@ namespace triagens {
size_t available = _allDocs.size() - _posInAllDocs; size_t available = _allDocs.size() - _posInAllDocs;
size_t toSend = std::min(atMost, available); size_t toSend = std::min(atMost, available);
auto res = new AqlItemBlock(toSend, _nrVars); auto res = new AqlItemBlock(toSend, _varOverview->nrVars[_depth]);
TRI_ASSERT(cur->getNrVars() <= _nrVars); TRI_ASSERT(cur->getNrVars() <= res->getNrVars());
for (size_t j = 0; j < toSend; j++) { for (size_t j = 0; j < toSend; j++) {
for (VariableId i = 0; i < cur->getNrVars(); i++) { for (VariableId i = 0; i < cur->getNrVars(); i++) {
res->setValue(j, i, cur->getValue(_pos, i)->clone()); res->setValue(j, i, cur->getValue(_pos, i)->clone());
} }
// The result is in the first variable of this depth,
// we do not need to do a lookup in _varOverview->varInfo,
// but can just take cur->getNrVars() as index:
res->setValue(j, cur->getNrVars(), res->setValue(j, cur->getNrVars(),
new AqlValue( new Json(_allDocs[_posInAllDocs++]->copy()) ) ); new AqlValue( new Json(_allDocs[_posInAllDocs++]->copy()) ) );
} }
// Advance read position:
if (_posInAllDocs >= _allDocs.size()) { if (_posInAllDocs >= _allDocs.size()) {
_posInAllDocs = 0; _posInAllDocs = 0;
if (++_pos >= cur->size()) { if (++_pos >= cur->size()) {
@ -765,8 +811,12 @@ namespace triagens {
// Let's steal the actual result and throw away the vars: // Let's steal the actual result and throw away the vars:
AqlItemBlock* stripped = new AqlItemBlock(1, 1); AqlItemBlock* stripped = new AqlItemBlock(1, 1);
stripped->setValue(0, 0, res->getValue(0, 0)); auto ep = static_cast<RootPlan const*>(getPlan());
res->setValue(0, 0, nullptr); auto it = _varOverview->varInfo.find(ep->_inVariable->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
unsigned int index = it->second.index;
stripped->setValue(0, 0, res->getValue(0, index));
res->setValue(0, index, nullptr);
delete res; delete res;
return stripped; return stripped;
} }
@ -779,10 +829,14 @@ namespace triagens {
} }
// Let's steal the actual result and throw away the vars: // Let's steal the actual result and throw away the vars:
auto ep = static_cast<RootPlan const*>(getPlan());
auto it = _varOverview->varInfo.find(ep->_inVariable->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
unsigned int index = it->second.index;
AqlItemBlock* stripped = new AqlItemBlock(res->size(), 1); AqlItemBlock* stripped = new AqlItemBlock(res->size(), 1);
for (size_t i = 0; i < res->size(); i++) { for (size_t i = 0; i < res->size(); i++) {
stripped->setValue(i, 0, res->getValue(i, 0)); stripped->setValue(i, 0, res->getValue(i, index));
res->setValue(i, 0, nullptr); res->setValue(i, index, nullptr);
} }
delete res; delete res;
return stripped; return stripped;

View File

@ -118,10 +118,14 @@ namespace triagens {
AqlItemBlock (size_t nrItems, VariableId nrVars) AqlItemBlock (size_t nrItems, VariableId nrVars)
: _nrItems(nrItems), _nrVars(nrVars) { : _nrItems(nrItems), _nrVars(nrVars) {
TRI_ASSERT(nrItems > 0 && nrVars > 0); if (nrItems > 0 && nrVars > 0) {
_data = new AqlValue* [nrItems * nrVars]; _data = new AqlValue* [nrItems * nrVars];
for (size_t i = 0; i < nrItems * nrVars; i++) { for (size_t i = 0; i < nrItems * nrVars; i++) {
_data[i] = nullptr; _data[i] = nullptr;
}
}
else {
_data = nullptr;
} }
} }
@ -131,16 +135,18 @@ namespace triagens {
~AqlItemBlock () { ~AqlItemBlock () {
std::unordered_set<AqlValue*> cache; std::unordered_set<AqlValue*> cache;
for (size_t i = 0; i < _nrItems * _nrVars; i++) { if (_data != nullptr) {
if (_data[i] != nullptr) { for (size_t i = 0; i < _nrItems * _nrVars; i++) {
auto it = cache.find(_data[i]); if (_data[i] != nullptr) {
if (it == cache.end()) { auto it = cache.find(_data[i]);
cache.insert(_data[i]); if (it == cache.end()) {
delete _data[i]; cache.insert(_data[i]);
delete _data[i];
}
} }
} }
delete[] _data;
} }
delete[] _data;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -148,7 +154,12 @@ namespace triagens {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AqlValue* getValue (size_t index, VariableId varNr) { AqlValue* getValue (size_t index, VariableId varNr) {
return _data[index * _nrVars + varNr - 1]; if (_data == nullptr) {
return nullptr;
}
else {
return _data[index * _nrVars + varNr];
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -156,7 +167,9 @@ namespace triagens {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void setValue (size_t index, VariableId varNr, AqlValue* zeug) { void setValue (size_t index, VariableId varNr, AqlValue* zeug) {
_data[index * _nrVars + varNr - 1] = zeug; if (_data != nullptr) {
_data[index * _nrVars + varNr] = zeug;
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////