1
0
Fork 0

Merge branch 'verpflanzung' into devel

This commit is contained in:
Max Neunhoeffer 2014-09-30 23:31:30 +02:00
commit a688636ce1
8 changed files with 469 additions and 427 deletions

View File

@ -242,7 +242,7 @@ void AqlItemBlock::shrink (size_t nrItems) {
/// necessary, using the reference count.
////////////////////////////////////////////////////////////////////////////////
void AqlItemBlock::clearRegisters (std::unordered_set<RegisterId>& toClear) {
void AqlItemBlock::clearRegisters (std::unordered_set<RegisterId> const& toClear) {
for (auto reg : toClear) {
for (size_t i = 0; i < _nrItems; i++) {
AqlValue& a(_data[_nrRegs * i + reg]);

View File

@ -251,7 +251,7 @@ namespace triagens {
/// necessary, using the reference count.
////////////////////////////////////////////////////////////////////////////////
void clearRegisters (std::unordered_set<RegisterId>& toClear);
void clearRegisters (std::unordered_set<RegisterId> const& toClear);
////////////////////////////////////////////////////////////////////////////////
/// @brief slice/clone, this does a deep copy of all entries

View File

@ -120,8 +120,6 @@ ExecutionBlock::ExecutionBlock (ExecutionEngine* engine,
: _engine(engine),
_trx(engine->getTransaction()),
_exeNode(ep),
_varOverview(nullptr),
_depth(0),
_done(false) {
}
@ -203,76 +201,6 @@ bool ExecutionBlock::walk (WalkerWorker<ExecutionBlock>* worker) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief static analysis
////////////////////////////////////////////////////////////////////////////////
struct StaticAnalysisDebugger : public WalkerWorker<ExecutionBlock> {
StaticAnalysisDebugger () : indent(0) {};
~StaticAnalysisDebugger () {};
int indent;
bool enterSubquery (ExecutionBlock*, ExecutionBlock*) {
indent++;
return true;
}
void leaveSubquery (ExecutionBlock*, ExecutionBlock*) {
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) {
// The super is only for the case of subqueries.
shared_ptr<VarOverview> v;
if (super == nullptr) {
v.reset(new VarOverview());
}
else {
v.reset(new VarOverview(*(super->_varOverview), super->_depth));
}
v->setSharedPtr(&v);
walk(v.get());
// Now handle the subqueries:
for (auto s : v->subQueryBlocks) {
auto sq = static_cast<SubqueryBlock*>(s);
sq->getSubquery()->staticAnalysis(s);
}
v->reset();
// Just for debugging:
/*
std::cout << std::endl;
StaticAnalysisDebugger debugger;
walk(&debugger);
std::cout << std::endl;
*/
}
////////////////////////////////////////////////////////////////////////////////
/// @brief initialize
////////////////////////////////////////////////////////////////////////////////
@ -366,7 +294,8 @@ void ExecutionBlock::inheritRegisters (AqlItemBlock const* src,
RegisterId const n = src->getNrRegs();
for (RegisterId i = 0; i < n; i++) {
if (_regsToClear.find(i) == _regsToClear.end()) {
if (getPlanNode()->_regsToClear.find(i) ==
getPlanNode()->_regsToClear.end()) {
if (! src->getValue(row, i).isEmpty()) {
AqlValue a = src->getValue(row, i).clone();
try {
@ -427,7 +356,7 @@ AqlItemBlock* ExecutionBlock::getSomeWithoutRegisterClearout (
void ExecutionBlock::clearRegisters (AqlItemBlock* result) {
// Clear out registers not needed later on:
if (result != nullptr) {
result->clearRegisters(_regsToClear);
result->clearRegisters(getPlanNode()->_regsToClear);
}
}
@ -627,7 +556,7 @@ int SingletonBlock::getOrSkipSome (size_t, // atLeast,
}
if(! skipping){
result = new AqlItemBlock(1, _varOverview->nrRegs[_depth]);
result = new AqlItemBlock(1, getPlanNode()->getVarOverview()->nrRegs[getPlanNode()->getDepth()]);
try {
if (_inputRegisterValues != nullptr) {
skipped++;
@ -752,7 +681,7 @@ AqlItemBlock* EnumerateCollectionBlock::getSome (size_t, // atLeast,
size_t available = _documents.size() - _posInAllDocs;
size_t toSend = (std::min)(atMost, available);
unique_ptr<AqlItemBlock> res(new AqlItemBlock(toSend, _varOverview->nrRegs[_depth]));
unique_ptr<AqlItemBlock> res(new AqlItemBlock(toSend, getPlanNode()->getVarOverview()->nrRegs[getPlanNode()->getDepth()]));
// automatically freed if we throw
TRI_ASSERT(curRegs <= res->getNrRegs());
@ -773,7 +702,7 @@ AqlItemBlock* EnumerateCollectionBlock::getSome (size_t, // atLeast,
}
// The result is in the first variable of this depth,
// we do not need to do a lookup in _varOverview->varInfo,
// we do not need to do a lookup in getPlanNode()->_varOverview->varInfo,
// but can just take cur->getNrRegs() as registerId:
res->setValue(j, static_cast<triagens::aql::RegisterId>(curRegs),
AqlValue(reinterpret_cast<TRI_df_marker_t
@ -912,8 +841,8 @@ int IndexRangeBlock::initialize () {
std::unordered_set<Variable*> inVars = e->variables();
for (auto v : inVars) {
inVarsCur.push_back(v);
auto it = _varOverview->varInfo.find(v->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
auto it = getPlanNode()->getVarOverview()->varInfo.find(v->id);
TRI_ASSERT(it != getPlanNode()->getVarOverview()->varInfo.end());
inRegsCur.push_back(it->second.registerId);
}
@ -1108,7 +1037,7 @@ AqlItemBlock* IndexRangeBlock::getSome (size_t, // atLeast
if (toSend > 0) {
res.reset(new AqlItemBlock(toSend, _varOverview->nrRegs[_depth]));
res.reset(new AqlItemBlock(toSend, getPlanNode()->getVarOverview()->nrRegs[getPlanNode()->getDepth()]));
// automatically freed should we throw
TRI_ASSERT(curRegs <= res->getNrRegs());
@ -1130,7 +1059,7 @@ AqlItemBlock* IndexRangeBlock::getSome (size_t, // atLeast
}
// The result is in the first variable of this depth,
// we do not need to do a lookup in _varOverview->varInfo,
// we do not need to do a lookup in getPlanNode()->_varOverview->varInfo,
// but can just take cur->getNrRegs() as registerId:
res->setValue(j, static_cast<triagens::aql::RegisterId>(curRegs),
AqlValue(reinterpret_cast<TRI_df_marker_t
@ -1561,10 +1490,10 @@ int EnumerateListBlock::initialize () {
auto en = reinterpret_cast<EnumerateListNode const*>(_exeNode);
// get the inVariable register id . . .
// staticAnalysis has been run, so _varOverview is set up
auto it = _varOverview->varInfo.find(en->_inVariable->id);
// staticAnalysis has been run, so getPlanNode()->_varOverview is set up
auto it = getPlanNode()->getVarOverview()->varInfo.find(en->_inVariable->id);
if (it == _varOverview->varInfo.end()){
if (it == getPlanNode()->getVarOverview()->varInfo.end()){
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "variable not found");
}
@ -1668,7 +1597,7 @@ AqlItemBlock* EnumerateListBlock::getSome (size_t, size_t atMost) {
size_t toSend = (std::min)(atMost, sizeInVar - _index);
// create the result
res.reset(new AqlItemBlock(toSend, _varOverview->nrRegs[_depth]));
res.reset(new AqlItemBlock(toSend, getPlanNode()->getVarOverview()->nrRegs[getPlanNode()->getDepth()]));
inheritRegisters(cur, res.get(), _pos);
@ -1838,7 +1767,7 @@ int CalculationBlock::initialize () {
return res;
}
// We know that staticAnalysis has been run, so _varOverview is set up
// We know that staticAnalysis has been run, so getPlanNode()->_varOverview is set up
auto en = static_cast<CalculationNode const*>(getPlanNode());
std::unordered_set<Variable*> inVars = _expression->variables();
@ -1847,9 +1776,9 @@ int CalculationBlock::initialize () {
for (auto it = inVars.begin(); it != inVars.end(); ++it) {
_inVars.push_back(*it);
auto it2 = _varOverview->varInfo.find((*it)->id);
auto it2 = en->getVarOverview()->varInfo.find((*it)->id);
TRI_ASSERT(it2 != _varOverview->varInfo.end());
TRI_ASSERT(it2 != en->getVarOverview()->varInfo.end());
_inRegs.push_back(it2->second.registerId);
}
@ -1861,8 +1790,8 @@ int CalculationBlock::initialize () {
TRI_ASSERT(_inRegs.size() == 1);
}
auto it3 = _varOverview->varInfo.find(en->_outVariable->id);
TRI_ASSERT(it3 != _varOverview->varInfo.end());
auto it3 = en->getVarOverview()->varInfo.find(en->_outVariable->id);
TRI_ASSERT(it3 != en->getVarOverview()->varInfo.end());
_outReg = it3->second.registerId;
return TRI_ERROR_NO_ERROR;
@ -1940,12 +1869,12 @@ int SubqueryBlock::initialize () {
return res;
}
// We know that staticAnalysis has been run, so _varOverview is set up
// We know that staticAnalysis has been run, so getPlanNode()->_varOverview is set up
auto en = static_cast<SubqueryNode const*>(getPlanNode());
auto it3 = _varOverview->varInfo.find(en->_outVariable->id);
TRI_ASSERT(it3 != _varOverview->varInfo.end());
auto it3 = en->getVarOverview()->varInfo.find(en->_outVariable->id);
TRI_ASSERT(it3 != en->getVarOverview()->varInfo.end());
_outReg = it3->second.registerId;
return getSubquery()->initialize();
@ -2005,12 +1934,12 @@ int FilterBlock::initialize () {
return res;
}
// We know that staticAnalysis has been run, so _varOverview is set up
// We know that staticAnalysis has been run, so getPlanNode()->_varOverview is set up
auto en = static_cast<FilterNode const*>(getPlanNode());
auto it = _varOverview->varInfo.find(en->_inVariable->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
auto it = en->getVarOverview()->varInfo.find(en->_inVariable->id);
TRI_ASSERT(it != en->getVarOverview()->varInfo.end());
_inReg = it->second.registerId;
return TRI_ERROR_NO_ERROR;
@ -2189,18 +2118,18 @@ int AggregateBlock::initialize () {
_variableNames.clear();
for (auto p : en->_aggregateVariables){
//We know that staticAnalysis has been run, so _varOverview is set up
auto itOut = _varOverview->varInfo.find(p.first->id);
TRI_ASSERT(itOut != _varOverview->varInfo.end());
// We know that staticAnalysis has been run, so getPlanNode()->_varOverview is set up
auto itOut = en->getVarOverview()->varInfo.find(p.first->id);
TRI_ASSERT(itOut != en->getVarOverview()->varInfo.end());
auto itIn = _varOverview->varInfo.find(p.second->id);
TRI_ASSERT(itIn != _varOverview->varInfo.end());
auto itIn = en->getVarOverview()->varInfo.find(p.second->id);
TRI_ASSERT(itIn != en->getVarOverview()->varInfo.end());
_aggregateRegisters.push_back(make_pair((*itOut).second.registerId, (*itIn).second.registerId));
}
if (en->_outVariable != nullptr) {
auto it = _varOverview->varInfo.find(en->_outVariable->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
auto it = en->getVarOverview()->varInfo.find(en->_outVariable->id);
TRI_ASSERT(it != en->getVarOverview()->varInfo.end());
_groupRegister = (*it).second.registerId;
TRI_ASSERT(_groupRegister > 0);
@ -2208,12 +2137,13 @@ int AggregateBlock::initialize () {
// construct a mapping of all register ids to variable names
// we need this mapping to generate the grouped output
for (size_t i = 0; i < _varOverview->varInfo.size(); ++i) {
for (size_t i = 0; i < en->getVarOverview()->varInfo.size(); ++i) {
_variableNames.push_back(""); // initialize with some default value
}
// iterate over all our variables
for (auto it = _varOverview->varInfo.begin(); it != _varOverview->varInfo.end(); ++it) {
for (auto it = en->getVarOverview()->varInfo.begin();
it != en->getVarOverview()->varInfo.end(); ++it) {
// find variable in the global variable map
auto itVar = en->_variableMap.find((*it).first);
@ -2253,7 +2183,7 @@ int AggregateBlock::getOrSkipSome (size_t atLeast,
unique_ptr<AqlItemBlock> res;
if(!skipping){
res.reset(new AqlItemBlock(atMost, _varOverview->nrRegs[_depth]));
res.reset(new AqlItemBlock(atMost, getPlanNode()->getVarOverview()->nrRegs[getPlanNode()->getDepth()]));
TRI_ASSERT(cur->getNrRegs() <= res->getNrRegs());
inheritRegisters(cur, res.get(), _pos);
@ -2421,9 +2351,9 @@ int SortBlock::initialize () {
_sortRegisters.clear();
for( auto p: en->_elements){
//We know that staticAnalysis has been run, so _varOverview is set up
auto it = _varOverview->varInfo.find(p.first->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
// We know that staticAnalysis has been run, so getPlanNode()->_varOverview is set up
auto it = en->getVarOverview()->varInfo.find(p.first->id);
TRI_ASSERT(it != en->getVarOverview()->varInfo.end());
_sortRegisters.push_back(make_pair(it->second.registerId, p.second));
}
@ -2713,8 +2643,8 @@ AqlItemBlock* ReturnBlock::getSome (size_t atLeast,
// Let's steal the actual result and throw away the vars:
auto ep = static_cast<ReturnNode const*>(getPlanNode());
auto it = _varOverview->varInfo.find(ep->_inVariable->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
auto it = ep->getVarOverview()->varInfo.find(ep->_inVariable->id);
TRI_ASSERT(it != ep->getVarOverview()->varInfo.end());
RegisterId const registerId = it->second.registerId;
AqlItemBlock* stripped = new AqlItemBlock(n, 1);
@ -2867,8 +2797,8 @@ RemoveBlock::~RemoveBlock () {
void RemoveBlock::work (std::vector<AqlItemBlock*>& blocks) {
auto ep = static_cast<RemoveNode const*>(getPlanNode());
auto it = _varOverview->varInfo.find(ep->_inVariable->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
auto it = ep->getVarOverview()->varInfo.find(ep->_inVariable->id);
TRI_ASSERT(it != ep->getVarOverview()->varInfo.end());
RegisterId const registerId = it->second.registerId;
auto trxCollection = _trx->trxCollection(_collection->cid());
@ -2944,8 +2874,8 @@ InsertBlock::~InsertBlock () {
void InsertBlock::work (std::vector<AqlItemBlock*>& blocks) {
auto ep = static_cast<InsertNode const*>(getPlanNode());
auto it = _varOverview->varInfo.find(ep->_inVariable->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
auto it = ep->getVarOverview()->varInfo.find(ep->_inVariable->id);
TRI_ASSERT(it != ep->getVarOverview()->varInfo.end());
RegisterId const registerId = it->second.registerId;
auto trxCollection = _trx->trxCollection(_collection->cid());
@ -3056,16 +2986,16 @@ UpdateBlock::~UpdateBlock () {
void UpdateBlock::work (std::vector<AqlItemBlock*>& blocks) {
auto ep = static_cast<UpdateNode const*>(getPlanNode());
auto it = _varOverview->varInfo.find(ep->_inDocVariable->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
auto it = ep->getVarOverview()->varInfo.find(ep->_inDocVariable->id);
TRI_ASSERT(it != ep->getVarOverview()->varInfo.end());
RegisterId const docRegisterId = it->second.registerId;
RegisterId keyRegisterId = 0; // default initialization
bool const hasKeyVariable = (ep->_inKeyVariable != nullptr);
if (hasKeyVariable) {
it = _varOverview->varInfo.find(ep->_inKeyVariable->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
it = ep->getVarOverview()->varInfo.find(ep->_inKeyVariable->id);
TRI_ASSERT(it != ep->getVarOverview()->varInfo.end());
keyRegisterId = it->second.registerId;
}
@ -3174,16 +3104,16 @@ ReplaceBlock::~ReplaceBlock () {
void ReplaceBlock::work (std::vector<AqlItemBlock*>& blocks) {
auto ep = static_cast<ReplaceNode const*>(getPlanNode());
auto it = _varOverview->varInfo.find(ep->_inDocVariable->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
auto it = ep->getVarOverview()->varInfo.find(ep->_inDocVariable->id);
TRI_ASSERT(it != ep->getVarOverview()->varInfo.end());
RegisterId const registerId = it->second.registerId;
RegisterId keyRegisterId = 0; // default initialization
bool const hasKeyVariable = (ep->_inKeyVariable != nullptr);
if (hasKeyVariable) {
it = _varOverview->varInfo.find(ep->_inKeyVariable->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
it = ep->getVarOverview()->varInfo.find(ep->_inKeyVariable->id);
TRI_ASSERT(it != ep->getVarOverview()->varInfo.end());
keyRegisterId = it->second.registerId;
}
@ -3245,201 +3175,6 @@ void ReplaceBlock::work (std::vector<AqlItemBlock*>& blocks) {
}
}
// -----------------------------------------------------------------------------
// --SECTION-- struct ExecutionBlock::VarOverview
// -----------------------------------------------------------------------------
// Copy constructor used for a subquery:
ExecutionBlock::VarOverview::VarOverview (VarOverview const& v,
unsigned int newdepth)
: varInfo(v.varInfo),
nrRegsHere(v.nrRegsHere),
nrRegs(v.nrRegs),
subQueryBlocks(),
depth(newdepth+1),
totalNrRegs(v.nrRegs[newdepth]),
me(nullptr) {
nrRegs.resize(depth);
nrRegsHere.resize(depth);
nrRegsHere.push_back(0);
nrRegs.push_back(nrRegs.back());
}
void ExecutionBlock::VarOverview::after (ExecutionBlock *eb) {
switch (eb->getPlanNode()->getType()) {
case ExecutionNode::ENUMERATE_COLLECTION:
case ExecutionNode::INDEX_RANGE: {
depth++;
nrRegsHere.push_back(1);
nrRegs.push_back(1 + nrRegs.back());
auto ep = static_cast<EnumerateCollectionNode const*>(eb->getPlanNode());
TRI_ASSERT(ep != nullptr);
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
break;
}
case ExecutionNode::ENUMERATE_LIST: {
depth++;
nrRegsHere.push_back(1);
nrRegs.push_back(1 + nrRegs.back());
auto ep = static_cast<EnumerateListNode const*>(eb->getPlanNode());
TRI_ASSERT(ep != nullptr);
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
break;
}
case ExecutionNode::CALCULATION: {
nrRegsHere[depth]++;
nrRegs[depth]++;
auto ep = static_cast<CalculationNode const*>(eb->getPlanNode());
TRI_ASSERT(ep != nullptr);
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
break;
}
case ExecutionNode::SUBQUERY: {
nrRegsHere[depth]++;
nrRegs[depth]++;
auto ep = static_cast<SubqueryNode const*>(eb->getPlanNode());
TRI_ASSERT(ep != nullptr);
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
subQueryBlocks.push_back(eb);
break;
}
case ExecutionNode::AGGREGATE: {
depth++;
nrRegsHere.push_back(0);
nrRegs.push_back(nrRegs.back());
auto ep = static_cast<AggregateNode const*>(eb->getPlanNode());
for (auto p : ep->_aggregateVariables) {
// p is std::pair<Variable const*,Variable const*>
// and the first is the to be assigned output variable
// for which we need to create a register in the current
// frame:
nrRegsHere[depth]++;
nrRegs[depth]++;
varInfo.insert(make_pair(p.first->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
}
if (ep->_outVariable != nullptr) {
nrRegsHere[depth]++;
nrRegs[depth]++;
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
}
break;
}
case ExecutionNode::SORT: {
// sort sorts in place and does not produce new registers
break;
}
case ExecutionNode::RETURN: {
// return is special. it produces a result but is the last step in the pipeline
break;
}
case ExecutionNode::REMOVE: {
auto ep = static_cast<RemoveNode const*>(eb->getPlanNode());
if (ep->_outVariable != nullptr) {
nrRegsHere[depth]++;
nrRegs[depth]++;
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
}
break;
}
case ExecutionNode::INSERT: {
auto ep = static_cast<InsertNode const*>(eb->getPlanNode());
if (ep->_outVariable != nullptr) {
nrRegsHere[depth]++;
nrRegs[depth]++;
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
}
break;
}
case ExecutionNode::UPDATE: {
auto ep = static_cast<UpdateNode const*>(eb->getPlanNode());
if (ep->_outVariable != nullptr) {
nrRegsHere[depth]++;
nrRegs[depth]++;
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
}
break;
}
case ExecutionNode::REPLACE: {
auto ep = static_cast<ReplaceNode const*>(eb->getPlanNode());
if (ep->_outVariable != nullptr) {
nrRegsHere[depth]++;
nrRegs[depth]++;
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
}
break;
}
case ExecutionNode::SINGLETON:
case ExecutionNode::FILTER:
case ExecutionNode::LIMIT:
case ExecutionNode::SCATTER:
case ExecutionNode::GATHER:
case ExecutionNode::REMOTE:
case ExecutionNode::NORESULTS: {
// these node types do not produce any new registers
break;
}
case ExecutionNode::ILLEGAL: {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_NOT_IMPLEMENTED, "node type not implemented");
}
}
eb->_depth = depth;
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);
}
}
// -----------------------------------------------------------------------------
// --SECTION-- class NoResultsBlock
// -----------------------------------------------------------------------------
@ -3499,9 +3234,9 @@ int GatherBlock::initialize () {
_sortRegisters.clear();
for( auto p: en->_elements){
// We know that staticAnalysis has been run, so _varOverview is set up
auto it = _varOverview->varInfo.find(p.first->id);
TRI_ASSERT(it != _varOverview->varInfo.end());
// We know that staticAnalysis has been run, so getPlanNode()->_varOverview is set up
auto it = en->getVarOverview()->varInfo.find(p.first->id);
TRI_ASSERT(it != en->getVarOverview()->varInfo.end());
_sortRegisters.push_back(make_pair(it->second.registerId, p.second));
}
}

View File

@ -154,74 +154,10 @@ namespace triagens {
return _dependencies.at(pos);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief static analysis, walker class and information collector
////////////////////////////////////////////////////////////////////////////////
struct VarInfo {
unsigned int const depth;
RegisterId const registerId;
VarInfo () = delete;
VarInfo (int depth, int registerId)
: depth(depth), registerId(registerId) {
}
};
struct VarOverview : public WalkerWorker<ExecutionBlock> {
// The following are collected for global usage in the ExecutionBlock:
// map VariableIds to their depth and registerId:
std::unordered_map<VariableId, VarInfo> varInfo;
// number of variables in the frame of the current depth:
std::vector<RegisterId> nrRegsHere;
// number of variables in this and all outer frames together,
// the entry with index i here is always the sum of all values
// in nrRegsHere from index 0 to i (inclusively) and the two
// have the same length:
std::vector<RegisterId> nrRegs;
// We collect the subquery blocks to deal with them at the end:
std::vector<ExecutionBlock*> subQueryBlocks;
// Local for the walk:
unsigned int depth;
unsigned int totalNrRegs;
// This is used to tell all Blocks and share a pointer to ourselves
shared_ptr<VarOverview>* me;
VarOverview ()
: depth(0), totalNrRegs(0), me(nullptr) {
nrRegsHere.push_back(0);
nrRegs.push_back(0);
};
void setSharedPtr (shared_ptr<VarOverview>* shared) {
me = shared;
}
// Copy constructor used for a subquery:
VarOverview (VarOverview const& v, unsigned int newdepth);
~VarOverview () {};
virtual bool enterSubquery (ExecutionBlock*,
ExecutionBlock*) {
return false; // do not walk into subquery
}
virtual void after (ExecutionBlock *eb);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief Methods for execution
/// Lifecycle is:
/// CONSTRUCTOR
/// then the ExecutionEngine automatically calls
/// staticAnalysis() once, including subqueries
/// then the ExecutionEngine automatically calls
/// initialize() once, including subqueries
/// possibly repeat many times:
@ -232,12 +168,6 @@ namespace triagens {
/// DESTRUCTOR
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief static analysis
////////////////////////////////////////////////////////////////////////////////
void staticAnalysis (ExecutionBlock* super = nullptr);
////////////////////////////////////////////////////////////////////////////////
/// @brief initialize
////////////////////////////////////////////////////////////////////////////////
@ -351,14 +281,6 @@ namespace triagens {
return _exeNode;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief set regs to be deleted
////////////////////////////////////////////////////////////////////////////////
void setRegsToClear (std::unordered_set<RegisterId>& toClear) {
_regsToClear = toClear;
}
protected:
////////////////////////////////////////////////////////////////////////////////
@ -407,41 +329,18 @@ namespace triagens {
std::deque<AqlItemBlock*> _buffer;
////////////////////////////////////////////////////////////////////////////////
/// @brief info about variables, filled in by staticAnalysis
////////////////////////////////////////////////////////////////////////////////
public:
std::shared_ptr<VarOverview> _varOverview;
////////////////////////////////////////////////////////////////////////////////
/// @brief current working position in the first entry of _buffer
////////////////////////////////////////////////////////////////////////////////
size_t _pos;
////////////////////////////////////////////////////////////////////////////////
/// @brief depth of frames (number of FOR statements here or above)
////////////////////////////////////////////////////////////////////////////////
int _depth; // will be filled in by staticAnalysis
////////////////////////////////////////////////////////////////////////////////
/// @brief if this is set, we are done, this is reset to false by execute()
////////////////////////////////////////////////////////////////////////////////
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
// -----------------------------------------------------------------------------

View File

@ -695,6 +695,7 @@ ExecutionEngine* ExecutionEngine::instanciateFromPlan (QueryRegistry* queryRegis
if (! plan->varUsageComputed()) {
plan->findVarUsage();
}
plan->staticAnalysis();
ExecutionBlock* root = nullptr;
@ -716,7 +717,6 @@ ExecutionEngine* ExecutionEngine::instanciateFromPlan (QueryRegistry* queryRegis
}
TRI_ASSERT(root != nullptr);
root->staticAnalysis();
root->initialize();
root->initializeCursor(nullptr, 0);

View File

@ -429,6 +429,273 @@ triagens::basics::Json ExecutionNode::toJsonHelperGeneric (triagens::basics::Jso
return json;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief static analysis debugger
////////////////////////////////////////////////////////////////////////////////
struct StaticAnalysisDebugger : public WalkerWorker<ExecutionNode> {
StaticAnalysisDebugger () : indent(0) {};
~StaticAnalysisDebugger () {};
int indent;
bool enterSubquery (ExecutionNode*, ExecutionNode*) {
indent++;
return true;
}
void leaveSubquery (ExecutionNode*, ExecutionNode*) {
indent--;
}
void after (ExecutionNode* ep) {
for (int i = 0; i < indent; i++) {
std::cout << " ";
}
std::cout << ep->getTypeString() << " ";
std::cout << "regsUsedHere: ";
for (auto v : ep->getVariablesUsedHere()) {
std::cout << ep->getVarOverview()->varInfo.find(v->id)->second.registerId
<< " ";
}
std::cout << "regsSetHere: ";
for (auto v : ep->getVariablesSetHere()) {
std::cout << ep->getVarOverview()->varInfo.find(v->id)->second.registerId
<< " ";
}
std::cout << "regsToClear: ";
for (auto r : ep->getRegsToClear()) {
std::cout << r << " ";
}
std::cout << std::endl;
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief staticAnalysis
////////////////////////////////////////////////////////////////////////////////
void ExecutionNode::staticAnalysis (ExecutionNode* super) {
// The super is only for the case of subqueries.
shared_ptr<VarOverview> v;
if (super == nullptr) {
v.reset(new VarOverview());
}
else {
v.reset(new VarOverview(*(super->_varOverview), super->_depth));
}
v->setSharedPtr(&v);
walk(v.get());
// Now handle the subqueries:
for (auto s : v->subQueryNodes) {
auto sq = static_cast<SubqueryNode*>(s);
sq->getSubquery()->staticAnalysis(s);
}
v->reset();
// Just for debugging:
/*
std::cout << std::endl;
StaticAnalysisDebugger debugger;
walk(&debugger);
std::cout << std::endl;
*/
}
// -----------------------------------------------------------------------------
// --SECTION-- struct ExecutionNode::VarOverview
// -----------------------------------------------------------------------------
// Copy constructor used for a subquery:
ExecutionNode::VarOverview::VarOverview (VarOverview const& v,
unsigned int newdepth)
: varInfo(v.varInfo),
nrRegsHere(v.nrRegsHere),
nrRegs(v.nrRegs),
subQueryNodes(),
depth(newdepth+1),
totalNrRegs(v.nrRegs[newdepth]),
me(nullptr) {
nrRegs.resize(depth);
nrRegsHere.resize(depth);
nrRegsHere.push_back(0);
nrRegs.push_back(nrRegs.back());
}
void ExecutionNode::VarOverview::after (ExecutionNode *en) {
switch (en->getType()) {
case ExecutionNode::ENUMERATE_COLLECTION:
case ExecutionNode::INDEX_RANGE: {
depth++;
nrRegsHere.push_back(1);
nrRegs.push_back(1 + nrRegs.back());
auto ep = static_cast<EnumerateCollectionNode const*>(en);
TRI_ASSERT(ep != nullptr);
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
break;
}
case ExecutionNode::ENUMERATE_LIST: {
depth++;
nrRegsHere.push_back(1);
nrRegs.push_back(1 + nrRegs.back());
auto ep = static_cast<EnumerateListNode const*>(en);
TRI_ASSERT(ep != nullptr);
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
break;
}
case ExecutionNode::CALCULATION: {
nrRegsHere[depth]++;
nrRegs[depth]++;
auto ep = static_cast<CalculationNode const*>(en);
TRI_ASSERT(ep != nullptr);
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
break;
}
case ExecutionNode::SUBQUERY: {
nrRegsHere[depth]++;
nrRegs[depth]++;
auto ep = static_cast<SubqueryNode const*>(en);
TRI_ASSERT(ep != nullptr);
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
subQueryNodes.push_back(en);
break;
}
case ExecutionNode::AGGREGATE: {
depth++;
nrRegsHere.push_back(0);
nrRegs.push_back(nrRegs.back());
auto ep = static_cast<AggregateNode const*>(en);
for (auto p : ep->_aggregateVariables) {
// p is std::pair<Variable const*,Variable const*>
// and the first is the to be assigned output variable
// for which we need to create a register in the current
// frame:
nrRegsHere[depth]++;
nrRegs[depth]++;
varInfo.insert(make_pair(p.first->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
}
if (ep->_outVariable != nullptr) {
nrRegsHere[depth]++;
nrRegs[depth]++;
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
}
break;
}
case ExecutionNode::SORT: {
// sort sorts in place and does not produce new registers
break;
}
case ExecutionNode::RETURN: {
// return is special. it produces a result but is the last step in the pipeline
break;
}
case ExecutionNode::REMOVE: {
auto ep = static_cast<RemoveNode const*>(en);
if (ep->_outVariable != nullptr) {
nrRegsHere[depth]++;
nrRegs[depth]++;
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
}
break;
}
case ExecutionNode::INSERT: {
auto ep = static_cast<InsertNode const*>(en);
if (ep->_outVariable != nullptr) {
nrRegsHere[depth]++;
nrRegs[depth]++;
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
}
break;
}
case ExecutionNode::UPDATE: {
auto ep = static_cast<UpdateNode const*>(en);
if (ep->_outVariable != nullptr) {
nrRegsHere[depth]++;
nrRegs[depth]++;
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
}
break;
}
case ExecutionNode::REPLACE: {
auto ep = static_cast<ReplaceNode const*>(en);
if (ep->_outVariable != nullptr) {
nrRegsHere[depth]++;
nrRegs[depth]++;
varInfo.insert(make_pair(ep->_outVariable->id,
VarInfo(depth, totalNrRegs)));
totalNrRegs++;
}
break;
}
case ExecutionNode::SINGLETON:
case ExecutionNode::FILTER:
case ExecutionNode::LIMIT:
case ExecutionNode::SCATTER:
case ExecutionNode::GATHER:
case ExecutionNode::REMOTE:
case ExecutionNode::NORESULTS: {
// these node types do not produce any new registers
break;
}
case ExecutionNode::ILLEGAL: {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_NOT_IMPLEMENTED, "node type not implemented");
}
}
en->_depth = depth;
en->_varOverview = *me;
// Now find out which registers ought to be erased after this node:
if (en->getType() != ExecutionNode::RETURN) {
// ReturnNodes are special, since they return a single column anyway
std::unordered_set<Variable const*> const& varsUsedLater = en->getVarsUsedLater();
std::vector<Variable const*> const& varsUsedHere = en->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);
}
}
en->setRegsToClear(regsToClear);
}
}
// -----------------------------------------------------------------------------
// --SECTION-- methods of SingletonNode
// -----------------------------------------------------------------------------

View File

@ -75,6 +75,8 @@ namespace triagens {
/// @brief node type
////////////////////////////////////////////////////////////////////////////////
friend class ExecutionBlock;
public:
enum NodeType {
@ -113,7 +115,8 @@ namespace triagens {
_estimatedCost(0.0),
_estimatedCostSet(false),
_varUsageValid(false),
_plan(plan) {
_plan(plan),
_depth(0) {
}
////////////////////////////////////////////////////////////////////////////////
@ -496,6 +499,99 @@ namespace triagens {
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief static analysis, walker class and information collector
////////////////////////////////////////////////////////////////////////////////
struct VarInfo {
unsigned int const depth;
RegisterId const registerId;
VarInfo () = delete;
VarInfo (int depth, int registerId)
: depth(depth), registerId(registerId) {
}
};
struct VarOverview : public WalkerWorker<ExecutionNode> {
// The following are collected for global usage in the ExecutionBlock,
// although they are stored here in the node:
// map VariableIds to their depth and registerId:
std::unordered_map<VariableId, VarInfo> varInfo;
// number of variables in the frame of the current depth:
std::vector<RegisterId> nrRegsHere;
// number of variables in this and all outer frames together,
// the entry with index i here is always the sum of all values
// in nrRegsHere from index 0 to i (inclusively) and the two
// have the same length:
std::vector<RegisterId> nrRegs;
// We collect the subquery nodes to deal with them at the end:
std::vector<ExecutionNode*> subQueryNodes;
// Local for the walk:
unsigned int depth;
unsigned int totalNrRegs;
// This is used to tell all nodes and share a pointer to ourselves
shared_ptr<VarOverview>* me;
VarOverview ()
: depth(0), totalNrRegs(0), me(nullptr) {
nrRegsHere.push_back(0);
nrRegs.push_back(0);
};
void setSharedPtr (shared_ptr<VarOverview>* shared) {
me = shared;
}
// Copy constructor used for a subquery:
VarOverview (VarOverview const& v, unsigned int newdepth);
~VarOverview () {};
virtual bool enterSubquery (ExecutionNode*,
ExecutionNode*) {
return false; // do not walk into subquery
}
virtual void after (ExecutionNode *eb);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief static analysis
////////////////////////////////////////////////////////////////////////////////
void staticAnalysis (ExecutionNode* super = nullptr);
////////////////////////////////////////////////////////////////////////////////
/// @brief get varOverview
////////////////////////////////////////////////////////////////////////////////
VarOverview const* getVarOverview () const {
return _varOverview.get();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get depth
////////////////////////////////////////////////////////////////////////////////
int getDepth () const {
return _depth;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get registers to clear
////////////////////////////////////////////////////////////////////////////////
std::unordered_set<RegisterId> const& getRegsToClear () const {
return _regsToClear;
}
// -----------------------------------------------------------------------------
// --SECTION-- protected functions
// -----------------------------------------------------------------------------
@ -528,6 +624,14 @@ namespace triagens {
TRI_memory_zone_t*,
bool) const;
////////////////////////////////////////////////////////////////////////////////
/// @brief set regs to be deleted
////////////////////////////////////////////////////////////////////////////////
void setRegsToClear (std::unordered_set<RegisterId>& toClear) {
_regsToClear = toClear;
}
// -----------------------------------------------------------------------------
// --SECTION-- protected variables
// -----------------------------------------------------------------------------
@ -589,6 +693,26 @@ namespace triagens {
ExecutionPlan* _plan;
////////////////////////////////////////////////////////////////////////////////
/// @brief info about variables, filled in by staticAnalysis
////////////////////////////////////////////////////////////////////////////////
std::shared_ptr<VarOverview> _varOverview;
////////////////////////////////////////////////////////////////////////////////
/// @brief depth of the current frame, will be filled in by staticAnalysis
////////////////////////////////////////////////////////////////////////////////
int _depth;
////////////////////////////////////////////////////////////////////////////////
/// @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.
////////////////////////////////////////////////////////////////////////////////
std::unordered_set<RegisterId> _regsToClear;
};
// -----------------------------------------------------------------------------
@ -665,7 +789,7 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
class EnumerateCollectionNode : public ExecutionNode {
friend class ExecutionNode;
friend class ExecutionBlock;
friend class EnumerateCollectionBlock;
@ -819,6 +943,7 @@ namespace triagens {
class EnumerateListNode : public ExecutionNode {
friend class ExecutionNode;
friend class ExecutionBlock;
friend class EnumerateListBlock;
friend class RedundantCalculationsReplacer;
@ -1178,6 +1303,7 @@ namespace triagens {
class CalculationNode : public ExecutionNode {
friend class ExecutionNode;
friend class ExecutionBlock;
friend class CalculationBlock;
friend class RedundantCalculationsReplacer;
@ -1323,6 +1449,7 @@ namespace triagens {
class SubqueryNode : public ExecutionNode {
friend class ExecutionNode;
friend class ExecutionBlock;
friend class SubqueryBlock;
@ -1733,6 +1860,7 @@ namespace triagens {
class AggregateNode : public ExecutionNode {
friend class ExecutionNode;
friend class ExecutionBlock;
friend class AggregateBlock;
friend class RedundantCalculationsReplacer;
@ -2041,6 +2169,7 @@ namespace triagens {
class RemoveNode : public ModificationNode {
friend class ExecutionNode;
friend class ExecutionBlock;
friend class RemoveBlock;
@ -2153,6 +2282,7 @@ namespace triagens {
class InsertNode : public ModificationNode {
friend class ExecutionNode;
friend class ExecutionBlock;
friend class InsertBlock;
@ -2264,6 +2394,7 @@ namespace triagens {
class UpdateNode : public ModificationNode {
friend class ExecutionNode;
friend class ExecutionBlock;
friend class UpdateBlock;
@ -2388,6 +2519,7 @@ namespace triagens {
class ReplaceNode : public ModificationNode {
friend class ExecutionNode;
friend class ExecutionBlock;
friend class ReplaceBlock;

View File

@ -95,6 +95,7 @@ namespace triagens {
/// @brief create an execution plan identical to this one
/// keep the memory of the plan on the query object specified.
////////////////////////////////////////////////////////////////////////////////
ExecutionPlan* clone(Query &onThatQuery);
////////////////////////////////////////////////////////////////////////////////
@ -229,6 +230,14 @@ namespace triagens {
bool varUsageComputed ();
////////////////////////////////////////////////////////////////////////////////
/// @brief static analysis
////////////////////////////////////////////////////////////////////////////////
void staticAnalysis () {
_root->staticAnalysis();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief unlinkNodes, note that this does not delete the removed
/// nodes and that one cannot remove the root node of the plan.