1
0
Fork 0

Merge branch 'aql2' of ssh://github.com/triAGENS/ArangoDB into aql2

This commit is contained in:
Max Neunhoeffer 2014-08-21 13:43:23 +02:00
commit 068faf709b
8 changed files with 344 additions and 128 deletions

View File

@ -438,11 +438,11 @@ void IndexRangeNode::toJsonHelper (triagens::basics::Json& nodes,
} }
// Now put info about vocbase and cid in there // Now put info about vocbase and cid in there
json("database", Json(_vocbase->_name)) /*json("database", Json(_vocbase->_name))
("collection", Json(_collection->name)) ("collection", Json(_collection->name))
("outVariable", _outVariable->toJson()) ("outVariable", _outVariable->toJson())
("index", _index->index()->json(_index->index())) ("index", _index->index()->json(_index->index()))
("ranges", ranges); ("ranges", ranges);*/
// And add it: // And add it:
nodes(json); nodes(json);

View File

@ -178,6 +178,24 @@ namespace triagens {
return _dependencies; return _dependencies;
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief replace a dependency, returns true if the pointer was found and
/// replaced, please note that this does not delete oldNode!
////////////////////////////////////////////////////////////////////////////////
bool replaceDependency (ExecutionNode* oldNode, ExecutionNode* newNode) {
auto it = _dependencies.begin();
while (it != _dependencies.end()) {
if (*it == oldNode) {
*it = newNode;
return true;
}
++it;
}
return false;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief remove a dependency, returns true if the pointer was found and /// @brief remove a dependency, returns true if the pointer was found and
/// removed, please note that this does not delete ep! /// removed, please note that this does not delete ep!
@ -545,6 +563,56 @@ namespace triagens {
return v; return v;
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief get indexes with fields <attrs> or nullptr if none exist
////////////////////////////////////////////////////////////////////////////////
vector<TRI_index_t*> getIndexes (vector<std::string> attrs) const {
vector<TRI_index_t*> out;
TRI_document_collection_t* document = _collection->documentCollection();
size_t const n = document->_allIndexes._length;
for (size_t i = 0; i < n; ++i) {
TRI_index_t* idx = static_cast<TRI_index_t*>(document->_allIndexes._buffer[i]);
size_t seen = 0;
for (size_t j = 0; j < idx->_fields._length; j++) {
bool found = false;
for (size_t k = 0; k < attrs.size(); k++){
if(std::string(idx->_fields._buffer[j]) == attrs[k]) {
found = true;
break;
}
}
if (found) {
seen++;
}
else {
break;
}
}
if (((idx->_type == TRI_IDX_TYPE_HASH_INDEX) && seen == idx->_fields._length )
|| ((idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) && seen > 0 )) {
// all fields equal
out.push_back(idx);
}
}
return out;
}
TRI_vocbase_t* vocbase () const {
return _vocbase;
}
Collection* collection () const {
return _collection;
}
Variable const* outVariable () const {
return _outVariable;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- private variables // --SECTION-- private variables
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -798,28 +866,46 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
~RangesInfo(){} ~RangesInfo(){}
RangeInfo* find(std::string name) const { RangeInfo* find(std::string var, std::string name) const {
auto it = _ranges.find(name); auto it1 = _ranges.find(var);
if (it1 == _ranges.end()) {
return nullptr;
}
auto it2 = it1->second.find(name);
if (it2 == it1->second.end()) {
return nullptr;
}
return (*it2).second;
}
std::unordered_map<std::string, RangeInfo*>* find(std::string var) {
auto it = _ranges.find(var);
if (it == _ranges.end()) { if (it == _ranges.end()) {
return nullptr; return nullptr;
} }
return (*it).second; //std::unordered_map<std::string, RangeInfo*>* out = &((*it).second);
//return out;
return &((*it).second);
} }
/*void insert (std::string name, RangeInfo* range) { void insert (std::string var, std::string name,
if( find(name) == nullptr ){ RangeInfoBound* low, RangeInfoBound* high) {
_ranges.insert(make_pair(name, range)); auto oldMap = find(var);
}
}*/
void insert (std::string name, RangeInfoBound* low, RangeInfoBound* high){
auto oldRange = find(name);
auto newRange = new RangeInfo(low, high); auto newRange = new RangeInfo(low, high);
int cmp;
if (oldMap == nullptr) {
// TODO add exception . . .
auto newMap = std::unordered_map<std::string, RangeInfo*>();
newMap.insert(make_pair(name, newRange));
_ranges.insert(std::make_pair(var, newMap));
return;
}
auto oldRange = find(var, name); //TODO improve
if (oldRange == nullptr) { if (oldRange == nullptr) {
// TODO add exception . . . // TODO add exception . . .
_ranges.insert(make_pair(name, newRange)); oldMap->insert(make_pair(name, newRange));
return; return;
} }
@ -837,7 +923,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
// check the new range bounds are valid // check the new range bounds are valid
if( oldRange->_low != nullptr && oldRange->_high != nullptr){ if( oldRange->_low != nullptr && oldRange->_high != nullptr){
cmp = TRI_CompareValuesJson(oldRange->_low->_bound.json(), int cmp = TRI_CompareValuesJson(oldRange->_low->_bound.json(),
oldRange->_high->_bound.json()); oldRange->_high->_bound.json());
if (cmp == 1 || (cmp == 0 && if (cmp == 1 || (cmp == 0 &&
!(oldRange->_low->_include == true && oldRange->_high->_include == true ))){ !(oldRange->_low->_include == true && oldRange->_high->_include == true ))){
@ -852,7 +938,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
return _ranges.size(); return _ranges.size();
} }
Json toJson () const { /*Json toJson () const {
Json list(Json::List); Json list(Json::List);
for (auto x : _ranges) { for (auto x : _ranges) {
Json item(Json::Array); Json item(Json::Array);
@ -865,10 +951,10 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
std::string toString() const { std::string toString() const {
return this->toJson().toString(); return this->toJson().toString();
} }*/
private: private:
std::unordered_map<std::string, RangeInfo*> _ranges; std::unordered_map<std::string, std::unordered_map<std::string, RangeInfo*>> _ranges;
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -891,7 +977,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
TRI_vocbase_t* vocbase, TRI_vocbase_t* vocbase,
Collection* collection, Collection* collection,
Variable const* outVariable, Variable const* outVariable,
Index* index, TRI_index_t* index,
vector<RangeInfo*>* ranges) vector<RangeInfo*>* ranges)
: ExecutionNode(id), : ExecutionNode(id),
_vocbase(vocbase), _vocbase(vocbase),
@ -984,7 +1070,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
/// @brief the index /// @brief the index
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Index* _index; TRI_index_t* _index;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief the range info /// @brief the range info

View File

@ -51,12 +51,10 @@ using JsonHelper = triagens::basics::JsonHelper;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
ExecutionPlan::ExecutionPlan () ExecutionPlan::ExecutionPlan ()
: _nodes(), : _ids(),
_ids(),
_root(nullptr), _root(nullptr),
_nextId(0) { _nextId(0) {
_nodes.reserve(8);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -64,8 +62,8 @@ ExecutionPlan::ExecutionPlan ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
ExecutionPlan::~ExecutionPlan () { ExecutionPlan::~ExecutionPlan () {
for (auto it = _nodes.begin(); it != _nodes.end(); ++it) { for (auto x : _ids){
delete (*it); delete x.second;
} }
} }
@ -189,23 +187,36 @@ ModificationOptions ExecutionPlan::createOptions (AstNode const* node) {
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief add a node to the plan, will delete node if addition fails /// @brief register a node with the plan, will delete node if addition fails
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
ExecutionNode* ExecutionPlan::addNode (ExecutionNode* node) { ExecutionNode* ExecutionPlan::registerNode (ExecutionNode* node) {
TRI_ASSERT(node != nullptr); TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->id() > 0); TRI_ASSERT(node->id() > 0);
try { try {
_nodes.push_back(node);
_ids.insert(std::make_pair(node->id(), node)); _ids.insert(std::make_pair(node->id(), node));
return node;
} }
catch (...) { catch (...) {
delete node; delete node;
throw; throw;
} }
return node;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief unregister a node to the plan
////////////////////////////////////////////////////////////////////////////////
void ExecutionPlan::unregisterNode (ExecutionNode* node) {
TRI_ASSERT(node != nullptr);
TRI_ASSERT(node->id() > 0);
auto it = _ids.find(node->id());
TRI_ASSERT(it != _ids.end());
TRI_ASSERT(it->second == node);
_ids.erase(it);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -224,9 +235,10 @@ CalculationNode* ExecutionPlan::createTemporaryCalculation (Ast const* ast,
try { try {
auto en = new CalculationNode(nextId(), expr, out); auto en = new CalculationNode(nextId(), expr, out);
addNode(reinterpret_cast<ExecutionNode*>(en)); registerNode(reinterpret_cast<ExecutionNode*>(en));
return en; return en;
} }
catch (...) { catch (...) {
// prevent memleak // prevent memleak
delete expr; delete expr;
@ -285,20 +297,20 @@ ExecutionNode* ExecutionPlan::fromNodeFor (Ast const* ast,
if (collection == nullptr) { if (collection == nullptr) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "no collection for EnumerateCollection"); THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "no collection for EnumerateCollection");
} }
en = addNode(new EnumerateCollectionNode(nextId(), ast->query()->vocbase(), collection, v)); en = registerNode(new EnumerateCollectionNode(nextId(), ast->query()->vocbase(), collection, v));
} }
else if (expression->type == NODE_TYPE_REFERENCE) { else if (expression->type == NODE_TYPE_REFERENCE) {
// second operand is already a variable // second operand is already a variable
auto inVariable = static_cast<Variable*>(expression->getData()); auto inVariable = static_cast<Variable*>(expression->getData());
TRI_ASSERT(inVariable != nullptr); TRI_ASSERT(inVariable != nullptr);
en = addNode(new EnumerateListNode(nextId(), inVariable, v)); en = registerNode(new EnumerateListNode(nextId(), inVariable, v));
} }
else { else {
// second operand is some misc. expression // second operand is some misc. expression
auto calc = createTemporaryCalculation(ast, expression); auto calc = createTemporaryCalculation(ast, expression);
calc->addDependency(previous); calc->addDependency(previous);
en = addNode(new EnumerateListNode(nextId(), calc->outVariable(), v)); en = registerNode(new EnumerateListNode(nextId(), calc->outVariable(), v));
previous = calc; previous = calc;
} }
@ -325,14 +337,14 @@ ExecutionNode* ExecutionPlan::fromNodeFilter (Ast const* ast,
// operand is already a variable // operand is already a variable
auto v = static_cast<Variable*>(expression->getData()); auto v = static_cast<Variable*>(expression->getData());
TRI_ASSERT(v != nullptr); TRI_ASSERT(v != nullptr);
en = addNode(new FilterNode(nextId(), v)); en = registerNode(new FilterNode(nextId(), v));
} }
else { else {
// operand is some misc expression // operand is some misc expression
auto calc = createTemporaryCalculation(ast, expression); auto calc = createTemporaryCalculation(ast, expression);
calc->addDependency(previous); calc->addDependency(previous);
en = addNode(new FilterNode(nextId(), calc->outVariable())); en = registerNode(new FilterNode(nextId(), calc->outVariable()));
previous = calc; previous = calc;
} }
@ -366,14 +378,14 @@ ExecutionNode* ExecutionPlan::fromNodeLet (Ast const* ast,
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY); THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
} }
en = addNode(new SubqueryNode(nextId(), subquery, v)); en = registerNode(new SubqueryNode(nextId(), subquery, v));
} }
else { else {
// operand is some misc expression, including references to other variables // operand is some misc expression, including references to other variables
auto expr = new Expression(ast->query()->executor(), const_cast<AstNode*>(expression)); auto expr = new Expression(ast->query()->executor(), const_cast<AstNode*>(expression));
try { try {
en = addNode(new CalculationNode(nextId(), expr, v)); en = registerNode(new CalculationNode(nextId(), expr, v));
} }
catch (...) { catch (...) {
// prevent memleak // prevent memleak
@ -441,7 +453,7 @@ ExecutionNode* ExecutionPlan::fromNodeSort (Ast const* ast,
previous = (*it); previous = (*it);
} }
auto en = addNode(new SortNode(nextId(), elements)); auto en = registerNode(new SortNode(nextId(), elements));
return addDependency(previous, en); return addDependency(previous, en);
} }
@ -501,7 +513,7 @@ ExecutionNode* ExecutionPlan::fromNodeCollect (Ast const* ast,
} }
// inject a sort node for all expressions / variables that we just picked up... // inject a sort node for all expressions / variables that we just picked up...
auto sort = addNode(new SortNode(nextId(), sortElements)); auto sort = registerNode(new SortNode(nextId(), sortElements));
sort->addDependency(previous); sort->addDependency(previous);
previous = sort; previous = sort;
@ -514,7 +526,7 @@ ExecutionNode* ExecutionPlan::fromNodeCollect (Ast const* ast,
outVariable = static_cast<Variable*>(v->getData()); outVariable = static_cast<Variable*>(v->getData());
} }
auto en = addNode(new AggregateNode(nextId(), aggregateVariables, outVariable, ast->variables()->variables(false))); auto en = registerNode(new AggregateNode(nextId(), aggregateVariables, outVariable, ast->variables()->variables(false)));
return addDependency(previous, en); return addDependency(previous, en);
} }
@ -535,7 +547,7 @@ ExecutionNode* ExecutionPlan::fromNodeLimit (Ast const* ast,
TRI_ASSERT(offset->type == NODE_TYPE_VALUE); TRI_ASSERT(offset->type == NODE_TYPE_VALUE);
TRI_ASSERT(count->type == NODE_TYPE_VALUE); TRI_ASSERT(count->type == NODE_TYPE_VALUE);
auto en = addNode(new LimitNode(nextId(), static_cast<size_t>(offset->getIntValue()), static_cast<size_t>(count->getIntValue()))); auto en = registerNode(new LimitNode(nextId(), static_cast<size_t>(offset->getIntValue()), static_cast<size_t>(count->getIntValue())));
return addDependency(previous, en); return addDependency(previous, en);
} }
@ -558,13 +570,13 @@ ExecutionNode* ExecutionPlan::fromNodeReturn (Ast const* ast,
// operand is already a variable // operand is already a variable
auto v = static_cast<Variable*>(expression->getData()); auto v = static_cast<Variable*>(expression->getData());
TRI_ASSERT(v != nullptr); TRI_ASSERT(v != nullptr);
en = addNode(new ReturnNode(nextId(), v)); en = registerNode(new ReturnNode(nextId(), v));
} }
else { else {
// operand is some misc expression // operand is some misc expression
auto calc = createTemporaryCalculation(ast, expression); auto calc = createTemporaryCalculation(ast, expression);
calc->addDependency(previous); calc->addDependency(previous);
en = addNode(new ReturnNode(nextId(), calc->outVariable())); en = registerNode(new ReturnNode(nextId(), calc->outVariable()));
previous = calc; previous = calc;
} }
@ -597,13 +609,13 @@ ExecutionNode* ExecutionPlan::fromNodeRemove (Ast const* ast,
// operand is already a variable // operand is already a variable
auto v = static_cast<Variable*>(expression->getData()); auto v = static_cast<Variable*>(expression->getData());
TRI_ASSERT(v != nullptr); TRI_ASSERT(v != nullptr);
en = addNode(new RemoveNode(nextId(), ast->query()->vocbase(), collection, options, v, nullptr)); en = registerNode(new RemoveNode(nextId(), ast->query()->vocbase(), collection, options, v, nullptr));
} }
else { else {
// operand is some misc expression // operand is some misc expression
auto calc = createTemporaryCalculation(ast, expression); auto calc = createTemporaryCalculation(ast, expression);
calc->addDependency(previous); calc->addDependency(previous);
en = addNode(new RemoveNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), nullptr)); en = registerNode(new RemoveNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), nullptr));
previous = calc; previous = calc;
} }
@ -631,13 +643,13 @@ ExecutionNode* ExecutionPlan::fromNodeInsert (Ast const* ast,
// operand is already a variable // operand is already a variable
auto v = static_cast<Variable*>(expression->getData()); auto v = static_cast<Variable*>(expression->getData());
TRI_ASSERT(v != nullptr); TRI_ASSERT(v != nullptr);
en = addNode(new InsertNode(nextId(), ast->query()->vocbase(), collection, options, v, nullptr)); en = registerNode(new InsertNode(nextId(), ast->query()->vocbase(), collection, options, v, nullptr));
} }
else { else {
// operand is some misc expression // operand is some misc expression
auto calc = createTemporaryCalculation(ast, expression); auto calc = createTemporaryCalculation(ast, expression);
calc->addDependency(previous); calc->addDependency(previous);
en = addNode(new InsertNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), nullptr)); en = registerNode(new InsertNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), nullptr));
previous = calc; previous = calc;
} }
@ -683,13 +695,13 @@ ExecutionNode* ExecutionPlan::fromNodeUpdate (Ast const* ast,
// document operand is already a variable // document operand is already a variable
auto v = static_cast<Variable*>(docExpression->getData()); auto v = static_cast<Variable*>(docExpression->getData());
TRI_ASSERT(v != nullptr); TRI_ASSERT(v != nullptr);
en = addNode(new UpdateNode(nextId(), ast->query()->vocbase(), collection, options, v, keyVariable, nullptr)); en = registerNode(new UpdateNode(nextId(), ast->query()->vocbase(), collection, options, v, keyVariable, nullptr));
} }
else { else {
// document operand is some misc expression // document operand is some misc expression
auto calc = createTemporaryCalculation(ast, docExpression); auto calc = createTemporaryCalculation(ast, docExpression);
calc->addDependency(previous); calc->addDependency(previous);
en = addNode(new UpdateNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), keyVariable, nullptr)); en = registerNode(new UpdateNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), keyVariable, nullptr));
previous = calc; previous = calc;
} }
@ -735,13 +747,13 @@ ExecutionNode* ExecutionPlan::fromNodeReplace (Ast const* ast,
// operand is already a variable // operand is already a variable
auto v = static_cast<Variable*>(docExpression->getData()); auto v = static_cast<Variable*>(docExpression->getData());
TRI_ASSERT(v != nullptr); TRI_ASSERT(v != nullptr);
en = addNode(new ReplaceNode(nextId(), ast->query()->vocbase(), collection, options, v, keyVariable, nullptr)); en = registerNode(new ReplaceNode(nextId(), ast->query()->vocbase(), collection, options, v, keyVariable, nullptr));
} }
else { else {
// operand is some misc expression // operand is some misc expression
auto calc = createTemporaryCalculation(ast, docExpression); auto calc = createTemporaryCalculation(ast, docExpression);
calc->addDependency(previous); calc->addDependency(previous);
en = addNode(new ReplaceNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), keyVariable, nullptr)); en = registerNode(new ReplaceNode(nextId(), ast->query()->vocbase(), collection, options, calc->outVariable(), keyVariable, nullptr));
previous = calc; previous = calc;
} }
@ -756,7 +768,7 @@ ExecutionNode* ExecutionPlan::fromNode (Ast const* ast,
AstNode const* node) { AstNode const* node) {
TRI_ASSERT(node != nullptr); TRI_ASSERT(node != nullptr);
ExecutionNode* en = addNode(new SingletonNode(nextId())); ExecutionNode* en = registerNode(new SingletonNode(nextId()));
size_t const n = node->numMembers(); size_t const n = node->numMembers();
@ -936,7 +948,7 @@ void ExecutionPlan::findVarUsage () {
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief helper struct for removeNodes /// @brief helper struct for unlinkNodes
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
struct NodeRemover : public WalkerWorker<ExecutionNode> { struct NodeRemover : public WalkerWorker<ExecutionNode> {
@ -963,6 +975,7 @@ struct NodeRemover : public WalkerWorker<ExecutionNode> {
} }
else { else {
auto dep = en->getDependencies(); auto dep = en->getDependencies();
//TODO make exception safe
parents.back()->removeDependency(en); parents.back()->removeDependency(en);
if (dep.size() == 1) { if (dep.size() == 1) {
parents.back()->addDependency(dep[0]); parents.back()->addDependency(dep[0]);
@ -977,29 +990,87 @@ struct NodeRemover : public WalkerWorker<ExecutionNode> {
} }
void after (ExecutionNode* en) { void after (ExecutionNode* en) {
_plan->unregisterNode(en);
parents.pop_back(); parents.pop_back();
} }
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief removeNodes, note that this does not delete the removed /// @brief unlinkNodes, note that this does not delete the removed
/// nodes and that one cannot remove the root node of the plan. /// nodes and that one cannot remove the root node of the plan.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void ExecutionPlan::removeNodes (std::unordered_set<ExecutionNode*>& toRemove) { void ExecutionPlan::unlinkNodes (std::unordered_set<ExecutionNode*>& toRemove) {
NodeRemover remover(this, toRemove); NodeRemover remover(this, toRemove);
root()->walk(&remover); root()->walk(&remover);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief removeNode, note that this does not delete the removed /// @brief unlinkNode, note that this does not delete the removed
/// node and that one cannot remove the root node of the plan. /// node and that one cannot remove the root node of the plan.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void ExecutionPlan::removeNode (ExecutionNode* node) { void ExecutionPlan::unlinkNode (ExecutionNode* node) {
std::unordered_set<ExecutionNode*> toRemove; std::unordered_set<ExecutionNode*> toUnlink;
toRemove.insert(node); toUnlink.insert(node);
return removeNodes(toRemove); return unlinkNodes(toUnlink);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief replaceNode, note that <newNode> must be registered with the plan
/// before this method is called, also this does not delete the old
/// node and that one cannot replace the root node of the plan.
////////////////////////////////////////////////////////////////////////////////
void ExecutionPlan::replaceNode (ExecutionNode* oldNode, ExecutionNode* newNode,
ExecutionNode* oldNodeParent) {
TRI_ASSERT(oldNode->id() != newNode->id());
TRI_ASSERT(newNode->getDependencies().size() ==0);
TRI_ASSERT(oldNode != _root);
std::vector<ExecutionNode*> deps = oldNode->getDependencies();
for (auto x : deps) {
newNode->addDependency(x);
}
if(!oldNodeParent->replaceDependency(oldNode, newNode)){
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"Could not replace dependencies of an old node.");
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief clone the plan by recursively cloning starting from the root
////////////////////////////////////////////////////////////////////////////////
class CloneNodeAdder : public WalkerWorker<ExecutionNode> {
ExecutionPlan* _plan;
public:
CloneNodeAdder (ExecutionPlan* plan) : _plan(plan){}
~CloneNodeAdder (){}
void before (ExecutionNode* node){
_plan->registerNode(node);
}
};
ExecutionPlan* ExecutionPlan::clone (){
auto plan = new ExecutionPlan();
try {
plan->_root = _root->clone();
CloneNodeAdder adder(plan);
plan->_root->walk(&adder);
plan->findVarUsage();
return plan;
}
catch (...) {
delete plan;
throw;
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1029,7 +1100,7 @@ ExecutionNode* ExecutionPlan::fromJson (Ast* ast,
ret = ExecutionNode::fromJsonFactory(ast, ret = ExecutionNode::fromJsonFactory(ast,
oneJsonNode); oneJsonNode);
addNode(ret); registerNode(ret);
TRI_ASSERT(ret != nullptr); TRI_ASSERT(ret != nullptr);

View File

@ -146,18 +146,43 @@ namespace triagens {
void findVarUsage (); void findVarUsage ();
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief removeNodes, note that this does not delete the removed /// @brief unlinkNodes, note that this does not delete the removed
/// nodes and that one cannot remove the root node of the plan. /// nodes and that one cannot remove the root node of the plan.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void removeNodes (std::unordered_set<ExecutionNode*>& toRemove); void unlinkNodes (std::unordered_set<ExecutionNode*>& toUnlink);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief removeNode, note that this does not delete the removed /// @brief unlinkNode, note that this does not delete the removed
/// node and that one cannot remove the root node of the plan. /// node and that one cannot remove the root node of the plan.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void removeNode (ExecutionNode*); void unlinkNode (ExecutionNode*);
////////////////////////////////////////////////////////////////////////////////
/// @brief add a node to the plan, will delete node if addition fails
////////////////////////////////////////////////////////////////////////////////
ExecutionNode* registerNode (ExecutionNode*);
////////////////////////////////////////////////////////////////////////////////
/// @brief unregister a node to the plan
////////////////////////////////////////////////////////////////////////////////
void unregisterNode (ExecutionNode* node);
////////////////////////////////////////////////////////////////////////////////
/// @brief replace oldNode with newNode and fix dependencies
////////////////////////////////////////////////////////////////////////////////
void replaceNode (ExecutionNode* oldNode, ExecutionNode* newNode,
ExecutionNode* oldNodeParent);
////////////////////////////////////////////////////////////////////////////////
/// @brief clone the plan by recursively cloning starting from the root
////////////////////////////////////////////////////////////////////////////////
ExecutionPlan* clone ();
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- private methods // --SECTION-- private methods
@ -171,11 +196,6 @@ namespace triagens {
ModificationOptions createOptions (AstNode const*); ModificationOptions createOptions (AstNode const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief add a node to the plan, will delete node if addition fails
////////////////////////////////////////////////////////////////////////////////
ExecutionNode* addNode (ExecutionNode*);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief creates a calculation node for an arbitrary expression /// @brief creates a calculation node for an arbitrary expression
@ -295,12 +315,6 @@ namespace triagens {
private: private:
////////////////////////////////////////////////////////////////////////////////
/// @brief all nodes registered, used for memory management
////////////////////////////////////////////////////////////////////////////////
std::vector<ExecutionNode*> _nodes;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief map from node id to the actual node /// @brief map from node id to the actual node
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -79,8 +79,6 @@ namespace triagens {
return this->index()->_type; return this->index()->_type;
} }
// anything else??
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- public variables // --SECTION-- public variables
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -42,7 +42,7 @@ Optimizer::Optimizer () {
// List all the rules in the system here: // List all the rules in the system here:
// try to find a filter after an enumerate collection and find an index . . . // try to find a filter after an enumerate collection and find an index . . .
// registerRule (useIndexRange, 999); registerRule (useIndexRange, 999);
// remove filters from the query that are not necessary at all // remove filters from the query that are not necessary at all
// filters that are always true will be removed entirely // filters that are always true will be removed entirely

View File

@ -50,7 +50,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
bool& keep) { bool& keep) {
keep = true; // plan will always be kept keep = true; // plan will always be kept
std::unordered_set<ExecutionNode*> toRemove; std::unordered_set<ExecutionNode*> toUnlink;
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true); std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
for (auto n : nodes) { for (auto n : nodes) {
@ -84,21 +84,20 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
if (root->toBoolean()) { if (root->toBoolean()) {
// filter is always true // filter is always true
// remove filter node and merge with following node // remove filter node and merge with following node
toRemove.insert(n); toUnlink.insert(n);
} }
else { else {
// filter is always false // filter is always false
// TODO: insert a NoResults node below it // TODO: insert a NoResults node below it
//auto noResultsNode = plan->registerNode(new NoResultsNode(plan->nextId())); //auto noResultsNode = plan->registerNode(new NoResultsNode(plan->nextId()));
//TRI_ASSERT(noResultsNode != nullptr); //TRI_ASSERT(noResultsNode != nullptr);
} }
} }
if (! toRemove.empty()) { if (! toUnlink.empty()) {
std::cout << "Removing " << toRemove.size() << " unnecessary " std::cout << "Removing " << toUnlink.size() << " unnecessary "
"nodes..." << std::endl; "nodes..." << std::endl;
plan->removeNodes(toRemove); plan->unlinkNodes(toUnlink);
} }
return TRI_ERROR_NO_ERROR; return TRI_ERROR_NO_ERROR;
@ -171,7 +170,7 @@ std::cout << "LOOKING AT NODE OF TYPE: " << current->getTypeString() << "\n";
// no shared variables found. we can move the calculation up the dependency chain // no shared variables found. we can move the calculation up the dependency chain
// first, delete the calculation from the plan // first, delete the calculation from the plan
plan->removeNode(n); plan->unlinkNode(n);
// fiddle dependencies of calculation node // fiddle dependencies of calculation node
n->removeDependencies(); n->removeDependencies();
@ -208,7 +207,7 @@ int triagens::aql::removeUnnecessaryCalculationsRule (Optimizer* opt,
keep = true; keep = true;
std::vector<ExecutionNode*> nodes std::vector<ExecutionNode*> nodes
= plan->findNodesOfType(triagens::aql::ExecutionNode::CALCULATION, true); = plan->findNodesOfType(triagens::aql::ExecutionNode::CALCULATION, true);
std::unordered_set<ExecutionNode*> toRemove; std::unordered_set<ExecutionNode*> toUnlink;
for (auto n : nodes) { for (auto n : nodes) {
auto nn = static_cast<CalculationNode*>(n); auto nn = static_cast<CalculationNode*>(n);
@ -225,14 +224,14 @@ int triagens::aql::removeUnnecessaryCalculationsRule (Optimizer* opt,
// The variable whose value is calculated here is not used at // The variable whose value is calculated here is not used at
// all further down the pipeline! We remove the whole // all further down the pipeline! We remove the whole
// calculation node, // calculation node,
toRemove.insert(n); toUnlink.insert(n);
} }
} }
if (! toRemove.empty()) { if (! toUnlink.empty()) {
std::cout << "Removing " << toRemove.size() << " unnecessary " std::cout << "Removing " << toUnlink.size() << " unnecessary "
"CalculationNodes..." << std::endl; "CalculationNodes..." << std::endl;
plan->removeNodes(toRemove); plan->unlinkNodes(toUnlink);
} }
return TRI_ERROR_NO_ERROR; return TRI_ERROR_NO_ERROR;
@ -246,10 +245,14 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
RangesInfo* _ranges; RangesInfo* _ranges;
ExecutionPlan* _plan; ExecutionPlan* _plan;
Variable const* _var; Variable const* _var;
Optimizer::PlanList _out;
ExecutionNode* _prev;
//EnumerateCollectionNode const* _enumColl;
public: public:
CalculationNodeFinder (ExecutionPlan* plan, Variable const * var) CalculationNodeFinder (ExecutionPlan* plan, Variable const * var, Optimizer::PlanList& out)
: _plan(plan), _var(var){ : _plan(plan), _var(var), _out(out), _prev(nullptr){
_ranges = new RangesInfo(); _ranges = new RangesInfo();
}; };
@ -259,29 +262,73 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
TRI_ASSERT(outvar.size() == 1); TRI_ASSERT(outvar.size() == 1);
if(outvar[0]->id == _var->id){ if(outvar[0]->id == _var->id){
auto node = static_cast<CalculationNode*>(en); auto node = static_cast<CalculationNode*>(en);
std::string name; std::string attr;
buildRangeInfo(node->expression()->node(), name); std::string enumCollVar;
buildRangeInfo(node->expression()->node(), enumCollVar, attr);
} }
} }
else if (en->getType() == triagens::aql::ExecutionNode::ENUMERATE_COLLECTION) {
auto node = static_cast<EnumerateCollectionNode*>(en);
auto var = node->getVariablesSetHere()[0]; // should only be 1
auto map = _ranges->find(var->name); // check if we have any ranges with this var
if (map != nullptr) {
// check the first components of <map> against indexes of <node> . . .
// FIXME does this need to be done like this? Couldn't we keep track
// earlier?
std::vector<std::string> attrs;
std::vector<RangeInfo*> rangeInfo;
for (auto x : *map){
attrs.push_back(x.first);
rangeInfo.push_back(x.second);
}
std::vector<TRI_index_t*> idxs = node->getIndexes(attrs);
//use make one new plan for every index in <idxs> that replaces the
//enumerate collection node with a RangeIndexNode . . .
for (auto idx: idxs) {
std::cout << "FOUND INDEX!\n";
auto newPlan = _plan->clone();
ExecutionNode* newNode = nullptr;
try{
newNode = new IndexRangeNode( newPlan->nextId(), node->vocbase(),
node->collection(), node->outVariable(), idx, &rangeInfo);
newPlan->registerNode(newNode);
}
catch (...) {
if (newNode != nullptr) {
delete newNode;
}
delete newPlan;
throw;
}
newPlan->replaceNode(newPlan->getNodeById(node->id()), newNode,
newPlan->getNodeById(_prev->id()));
std::cout << newPlan->root()->toJson().toString() << "\n";
_out.push_back(newPlan);
}
}
}
_prev = en;
} }
void buildRangeInfo (AstNode const* node, std::string& name){ void buildRangeInfo (AstNode const* node, std::string& enumCollVar, std::string& attr){
if(node->type == NODE_TYPE_REFERENCE){ if(node->type == NODE_TYPE_REFERENCE){
auto var = static_cast<Variable*>(node->getData()); auto x = static_cast<Variable*>(node->getData());
auto setter = _plan->getVarSetBy(var->id); auto setter = _plan->getVarSetBy(x->id);
if( setter != nullptr && if( setter != nullptr &&
setter->getType() == triagens::aql::ExecutionNode::ENUMERATE_COLLECTION){ setter->getType() == triagens::aql::ExecutionNode::ENUMERATE_COLLECTION){
name = var->name; enumCollVar = x->name;
} }
return; return;
} }
if(node->type == NODE_TYPE_ATTRIBUTE_ACCESS){ if(node->type == NODE_TYPE_ATTRIBUTE_ACCESS){
char const* attributeName = node->getStringValue(); char const* attributeName = node->getStringValue();
buildRangeInfo(node->getMember(0), name); buildRangeInfo(node->getMember(0), enumCollVar, attr);
if(!name.empty()){ if(!enumCollVar.empty()){
name.push_back('.'); attr.append(attributeName);
name.append(attributeName); attr.push_back('.');
} }
} }
@ -303,14 +350,13 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
} }
if(val != nullptr){ if(val != nullptr){
buildRangeInfo(nextNode, name); buildRangeInfo(nextNode, enumCollVar, attr);
if(!name.empty()){ if(!enumCollVar.empty()){
_ranges->insert(name, new RangeInfoBound(val, true), _ranges->insert(enumCollVar, attr.substr(0, attr.size()-1),
new RangeInfoBound(val, true)); new RangeInfoBound(val, true), new RangeInfoBound(val, true));
} }
} }
//std::cout << _ranges->toString() << "\n";
std::cout << _ranges->toString() << "\n";
} }
if(node->type == NODE_TYPE_OPERATOR_BINARY_LT || if(node->type == NODE_TYPE_OPERATOR_BINARY_LT ||
@ -355,21 +401,22 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
} }
if(low != nullptr || high != nullptr){ if(low != nullptr || high != nullptr){
buildRangeInfo(nextNode, name); buildRangeInfo(nextNode, enumCollVar, attr);
if(!name.empty()){ if(!enumCollVar.empty()){
_ranges->insert(name, low, high); _ranges->insert(enumCollVar, attr.substr(0, attr.size()-1), low, high);
} }
} }
std::cout << _ranges->toString() << "\n"; //std::cout << _ranges->toString() << "\n";
} }
if(node->type == NODE_TYPE_OPERATOR_BINARY_AND){ if(node->type == NODE_TYPE_OPERATOR_BINARY_AND){
buildRangeInfo(node->getMember(0), name); attr = "";
buildRangeInfo(node->getMember(1), name); buildRangeInfo(node->getMember(0), enumCollVar, attr);
std::cout << _ranges->toString() << "\n"; attr = "";
buildRangeInfo(node->getMember(1), enumCollVar, attr);
//std::cout << _ranges->toString() << "\n";
} }
} }
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -380,7 +427,7 @@ int triagens::aql::useIndexRange (Optimizer* opt,
ExecutionPlan* plan, ExecutionPlan* plan,
Optimizer::PlanList& out, Optimizer::PlanList& out,
bool& keep) { bool& keep) {
keep = true;
std::vector<ExecutionNode*> nodes std::vector<ExecutionNode*> nodes
= plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true); = plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
@ -388,7 +435,7 @@ int triagens::aql::useIndexRange (Optimizer* opt,
auto nn = static_cast<FilterNode*>(n); auto nn = static_cast<FilterNode*>(n);
auto invars = nn->getVariablesUsedHere(); auto invars = nn->getVariablesUsedHere();
TRI_ASSERT(invars.size() == 1); TRI_ASSERT(invars.size() == 1);
CalculationNodeFinder finder(plan, invars[0]); CalculationNodeFinder finder(plan, invars[0], out);
nn->walk(&finder); nn->walk(&finder);
} }

View File

@ -246,7 +246,7 @@ QueryResult Query::execute () {
opt.createPlans(plan); // Now plan and all derived plans belong to the opt.createPlans(plan); // Now plan and all derived plans belong to the
// optimizer // optimizer
plan = opt.stealBest(); // Now we own the best one again plan = opt.stealBest(); // Now we own the best one again
TRI_ASSERT(plan != nullptr);
triagens::basics::Json json(triagens::basics::Json::List); triagens::basics::Json json(triagens::basics::Json::List);
triagens::basics::Json stats; triagens::basics::Json stats;