mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'verpflanzung' into devel
This commit is contained in:
commit
a688636ce1
|
@ -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]);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue