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
////////////////////////////////////////////////////////////////////////////////
void ExecutionBlock::walk (WalkerWorker& worker) {
worker.before(this);
void ExecutionBlock::walk (WalkerWorker* worker) {
// 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();
it != _dependencies.end();
++it) {
(*it)->walk(worker);
}
// Now handle a subquery:
if (_exePlan->getType() == ExecutionPlan::SUBQUERY) {
// auto p = static_cast<SubqueryBlock*>(this);
if (worker.enterSubquery(this, nullptr)) { ; // p->_subquery
if (worker->enterSubquery(this, nullptr)) { ; // p->_subquery
// 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 {
public:
ExecutionBlock (ExecutionPlan const* ep)
: _exePlan(ep), _done(false), _nrVars(3), _depth(0) { }
: _exePlan(ep), _done(false), _depth(0) { }
virtual ~ExecutionBlock ();
@ -115,9 +115,23 @@ namespace triagens {
};
virtual void leaveSubquery (ExecutionBlock* super,
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
@ -130,37 +144,54 @@ namespace triagens {
};
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;
// 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;
// Local for the walk:
unsigned int depth;
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 () {};
virtual bool enterSubquery (ExecutionBlock* super,
ExecutionBlock* sub) {
auto vv = new VarOverview();
sub->walk(*vv);
return false;
auto vv = new VarOverview(*this);
sub->walk(vv);
vv->reset();
return false; // do not walk into subquery
}
virtual void after (ExecutionBlock *eb) {
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: {
depth++;
while (depth >= nrVars.size()) {
nrVars.push_back(0);
}
TRI_ASSERT(nrVars[depth] == 0);
nrVars[depth] = 1;
nrVarsHere.push_back(1);
nrVars.push_back(1 + nrVars.back());
auto ep = static_cast<EnumerateCollectionPlan const*>(eb->getPlan());
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrVars)));
@ -169,11 +200,8 @@ namespace triagens {
}
case ExecutionPlan::ENUMERATE_LIST: {
depth++;
while (depth >= nrVars.size()) {
nrVars.push_back(0);
}
TRI_ASSERT(nrVars[depth] == 0);
nrVars[depth] = 1;
nrVarsHere.push_back(1);
nrVars.push_back(1 + nrVars.back());
auto ep = static_cast<EnumerateListPlan const*>(eb->getPlan());
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrVars)));
@ -181,6 +209,7 @@ namespace triagens {
break;
}
case ExecutionPlan::CALCULATION: {
nrVarsHere[depth]++;
nrVars[depth]++;
auto ep = static_cast<CalculationPlan const*>(eb->getPlan());
varInfo.insert(make_pair(ep->_outVariable->id,
@ -189,6 +218,7 @@ namespace triagens {
break;
}
case ExecutionPlan::PROJECTION: {
nrVarsHere[depth]++;
nrVars[depth]++;
auto ep = static_cast<ProjectionPlan const*>(eb->getPlan());
varInfo.insert(make_pair(ep->_outVariable->id,
@ -196,6 +226,15 @@ namespace triagens {
totalNrVars++;
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
default:
break;
@ -208,7 +247,8 @@ namespace triagens {
void staticAnalysis () {
auto v = new VarOverview();
walk(*v);
walk(v);
v->reset();
}
////////////////////////////////////////////////////////////////////////////////
@ -436,12 +476,6 @@ namespace triagens {
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)
////////////////////////////////////////////////////////////////////////////////
@ -521,7 +555,7 @@ namespace triagens {
return nullptr;
}
AqlItemBlock* res(new AqlItemBlock(1, _nrVars));
AqlItemBlock* res(new AqlItemBlock(1, _varOverview->nrVars[_depth]));
_done = true;
return res;
}
@ -535,7 +569,7 @@ namespace triagens {
return nullptr;
}
AqlItemBlock* res(new AqlItemBlock(1, _nrVars));
AqlItemBlock* res(new AqlItemBlock(1, _varOverview->nrVars[_depth]));
_done = true;
return res;
}
@ -662,13 +696,20 @@ namespace triagens {
// If we get here, we do have _buffer.front()
AqlItemBlock* cur = _buffer.front();
auto res = new AqlItemBlock(1, _nrVars);
TRI_ASSERT(cur->getNrVars() <= _nrVars);
// Copy stuff from frames above:
auto res = new AqlItemBlock(1, _varOverview->nrVars[_depth]);
TRI_ASSERT(cur->getNrVars() <= res->getNrVars());
for (VariableId i = 0; i < cur->getNrVars(); i++) {
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(),
new AqlValue( new Json(_allDocs[_posInAllDocs++]->copy()) ) );
// Advance read position:
if (_posInAllDocs >= _allDocs.size()) {
_posInAllDocs = 0;
if (++_pos >= cur->size()) {
@ -704,15 +745,20 @@ namespace triagens {
size_t available = _allDocs.size() - _posInAllDocs;
size_t toSend = std::min(atMost, available);
auto res = new AqlItemBlock(toSend, _nrVars);
TRI_ASSERT(cur->getNrVars() <= _nrVars);
auto res = new AqlItemBlock(toSend, _varOverview->nrVars[_depth]);
TRI_ASSERT(cur->getNrVars() <= res->getNrVars());
for (size_t j = 0; j < toSend; j++) {
for (VariableId i = 0; i < cur->getNrVars(); i++) {
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(),
new AqlValue( new Json(_allDocs[_posInAllDocs++]->copy()) ) );
}
// Advance read position:
if (_posInAllDocs >= _allDocs.size()) {
_posInAllDocs = 0;
if (++_pos >= cur->size()) {
@ -765,8 +811,12 @@ namespace triagens {
// Let's steal the actual result and throw away the vars:
AqlItemBlock* stripped = new AqlItemBlock(1, 1);
stripped->setValue(0, 0, res->getValue(0, 0));
res->setValue(0, 0, nullptr);
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;
stripped->setValue(0, 0, res->getValue(0, index));
res->setValue(0, index, nullptr);
delete res;
return stripped;
}
@ -779,10 +829,14 @@ namespace triagens {
}
// 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);
for (size_t i = 0; i < res->size(); i++) {
stripped->setValue(i, 0, res->getValue(i, 0));
res->setValue(i, 0, nullptr);
stripped->setValue(i, 0, res->getValue(i, index));
res->setValue(i, index, nullptr);
}
delete res;
return stripped;

View File

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