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
json("database", Json(_vocbase->_name))
/*json("database", Json(_vocbase->_name))
("collection", Json(_collection->name))
("outVariable", _outVariable->toJson())
("index", _index->index()->json(_index->index()))
("ranges", ranges);
("ranges", ranges);*/
// And add it:
nodes(json);

View File

@ -178,6 +178,24 @@ namespace triagens {
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
/// removed, please note that this does not delete ep!
@ -545,6 +563,56 @@ namespace triagens {
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
// -----------------------------------------------------------------------------
@ -555,7 +623,7 @@ namespace triagens {
/// @brief the database
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_t* _vocbase;
TRI_vocbase_t* _vocbase;
////////////////////////////////////////////////////////////////////////////////
/// @brief collection
@ -567,7 +635,7 @@ namespace triagens {
/// @brief output variable
////////////////////////////////////////////////////////////////////////////////
Variable const* _outVariable;
Variable const* _outVariable;
};
@ -798,28 +866,46 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
~RangesInfo(){}
RangeInfo* find(std::string name) const {
auto it = _ranges.find(name);
RangeInfo* find(std::string var, std::string name) const {
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()) {
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) {
if( find(name) == nullptr ){
_ranges.insert(make_pair(name, range));
}
}*/
void insert (std::string name, RangeInfoBound* low, RangeInfoBound* high){
auto oldRange = find(name);
auto newRange = new RangeInfo(low, high);
int cmp;
if( oldRange == nullptr ){
void insert (std::string var, std::string name,
RangeInfoBound* low, RangeInfoBound* high) {
auto oldMap = find(var);
auto newRange = new RangeInfo(low, high);
if (oldMap == nullptr) {
// TODO add exception . . .
_ranges.insert(make_pair(name, newRange));
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) {
// TODO add exception . . .
oldMap->insert(make_pair(name, newRange));
return;
}
@ -837,7 +923,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
// check the new range bounds are valid
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());
if (cmp == 1 || (cmp == 0 &&
!(oldRange->_low->_include == true && oldRange->_high->_include == true ))){
@ -852,7 +938,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
return _ranges.size();
}
Json toJson () const {
/*Json toJson () const {
Json list(Json::List);
for (auto x : _ranges) {
Json item(Json::Array);
@ -865,10 +951,10 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
std::string toString() const {
return this->toJson().toString();
}
}*/
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,
Collection* collection,
Variable const* outVariable,
Index* index,
TRI_index_t* index,
vector<RangeInfo*>* ranges)
: ExecutionNode(id),
_vocbase(vocbase),
@ -984,7 +1070,7 @@ static int CompareRangeInfoBound (RangeInfoBound const* left, RangeInfoBound con
/// @brief the index
////////////////////////////////////////////////////////////////////////////////
Index* _index;
TRI_index_t* _index;
////////////////////////////////////////////////////////////////////////////////
/// @brief the range info

View File

@ -51,12 +51,10 @@ using JsonHelper = triagens::basics::JsonHelper;
////////////////////////////////////////////////////////////////////////////////
ExecutionPlan::ExecutionPlan ()
: _nodes(),
_ids(),
: _ids(),
_root(nullptr),
_nextId(0) {
_nodes.reserve(8);
}
////////////////////////////////////////////////////////////////////////////////
@ -64,8 +62,8 @@ ExecutionPlan::ExecutionPlan ()
////////////////////////////////////////////////////////////////////////////////
ExecutionPlan::~ExecutionPlan () {
for (auto it = _nodes.begin(); it != _nodes.end(); ++it) {
delete (*it);
for (auto x : _ids){
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->id() > 0);
try {
_nodes.push_back(node);
_ids.insert(std::make_pair(node->id(), node));
return node;
}
catch (...) {
delete node;
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 {
auto en = new CalculationNode(nextId(), expr, out);
addNode(reinterpret_cast<ExecutionNode*>(en));
registerNode(reinterpret_cast<ExecutionNode*>(en));
return en;
}
catch (...) {
// prevent memleak
delete expr;
@ -285,20 +297,20 @@ ExecutionNode* ExecutionPlan::fromNodeFor (Ast const* ast,
if (collection == nullptr) {
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) {
// second operand is already a variable
auto inVariable = static_cast<Variable*>(expression->getData());
TRI_ASSERT(inVariable != nullptr);
en = addNode(new EnumerateListNode(nextId(), inVariable, v));
en = registerNode(new EnumerateListNode(nextId(), inVariable, v));
}
else {
// second operand is some misc. expression
auto calc = createTemporaryCalculation(ast, expression);
calc->addDependency(previous);
en = addNode(new EnumerateListNode(nextId(), calc->outVariable(), v));
en = registerNode(new EnumerateListNode(nextId(), calc->outVariable(), v));
previous = calc;
}
@ -325,14 +337,14 @@ ExecutionNode* ExecutionPlan::fromNodeFilter (Ast const* ast,
// operand is already a variable
auto v = static_cast<Variable*>(expression->getData());
TRI_ASSERT(v != nullptr);
en = addNode(new FilterNode(nextId(), v));
en = registerNode(new FilterNode(nextId(), v));
}
else {
// operand is some misc expression
auto calc = createTemporaryCalculation(ast, expression);
calc->addDependency(previous);
en = addNode(new FilterNode(nextId(), calc->outVariable()));
en = registerNode(new FilterNode(nextId(), calc->outVariable()));
previous = calc;
}
@ -366,14 +378,14 @@ ExecutionNode* ExecutionPlan::fromNodeLet (Ast const* ast,
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
en = addNode(new SubqueryNode(nextId(), subquery, v));
en = registerNode(new SubqueryNode(nextId(), subquery, v));
}
else {
// operand is some misc expression, including references to other variables
auto expr = new Expression(ast->query()->executor(), const_cast<AstNode*>(expression));
try {
en = addNode(new CalculationNode(nextId(), expr, v));
en = registerNode(new CalculationNode(nextId(), expr, v));
}
catch (...) {
// prevent memleak
@ -441,7 +453,7 @@ ExecutionNode* ExecutionPlan::fromNodeSort (Ast const* ast,
previous = (*it);
}
auto en = addNode(new SortNode(nextId(), elements));
auto en = registerNode(new SortNode(nextId(), elements));
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...
auto sort = addNode(new SortNode(nextId(), sortElements));
auto sort = registerNode(new SortNode(nextId(), sortElements));
sort->addDependency(previous);
previous = sort;
@ -514,7 +526,7 @@ ExecutionNode* ExecutionPlan::fromNodeCollect (Ast const* ast,
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);
}
@ -535,7 +547,7 @@ ExecutionNode* ExecutionPlan::fromNodeLimit (Ast const* ast,
TRI_ASSERT(offset->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);
}
@ -558,13 +570,13 @@ ExecutionNode* ExecutionPlan::fromNodeReturn (Ast const* ast,
// operand is already a variable
auto v = static_cast<Variable*>(expression->getData());
TRI_ASSERT(v != nullptr);
en = addNode(new ReturnNode(nextId(), v));
en = registerNode(new ReturnNode(nextId(), v));
}
else {
// operand is some misc expression
auto calc = createTemporaryCalculation(ast, expression);
calc->addDependency(previous);
en = addNode(new ReturnNode(nextId(), calc->outVariable()));
en = registerNode(new ReturnNode(nextId(), calc->outVariable()));
previous = calc;
}
@ -597,13 +609,13 @@ ExecutionNode* ExecutionPlan::fromNodeRemove (Ast const* ast,
// operand is already a variable
auto v = static_cast<Variable*>(expression->getData());
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 {
// operand is some misc expression
auto calc = createTemporaryCalculation(ast, expression);
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;
}
@ -631,13 +643,13 @@ ExecutionNode* ExecutionPlan::fromNodeInsert (Ast const* ast,
// operand is already a variable
auto v = static_cast<Variable*>(expression->getData());
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 {
// operand is some misc expression
auto calc = createTemporaryCalculation(ast, expression);
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;
}
@ -683,13 +695,13 @@ ExecutionNode* ExecutionPlan::fromNodeUpdate (Ast const* ast,
// document operand is already a variable
auto v = static_cast<Variable*>(docExpression->getData());
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 {
// document operand is some misc expression
auto calc = createTemporaryCalculation(ast, docExpression);
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;
}
@ -735,13 +747,13 @@ ExecutionNode* ExecutionPlan::fromNodeReplace (Ast const* ast,
// operand is already a variable
auto v = static_cast<Variable*>(docExpression->getData());
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 {
// operand is some misc expression
auto calc = createTemporaryCalculation(ast, docExpression);
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;
}
@ -756,7 +768,7 @@ ExecutionNode* ExecutionPlan::fromNode (Ast const* ast,
AstNode const* node) {
TRI_ASSERT(node != nullptr);
ExecutionNode* en = addNode(new SingletonNode(nextId()));
ExecutionNode* en = registerNode(new SingletonNode(nextId()));
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> {
@ -963,6 +975,7 @@ struct NodeRemover : public WalkerWorker<ExecutionNode> {
}
else {
auto dep = en->getDependencies();
//TODO make exception safe
parents.back()->removeDependency(en);
if (dep.size() == 1) {
parents.back()->addDependency(dep[0]);
@ -977,29 +990,87 @@ struct NodeRemover : public WalkerWorker<ExecutionNode> {
}
void after (ExecutionNode* en) {
_plan->unregisterNode(en);
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.
////////////////////////////////////////////////////////////////////////////////
void ExecutionPlan::removeNodes (std::unordered_set<ExecutionNode*>& toRemove) {
void ExecutionPlan::unlinkNodes (std::unordered_set<ExecutionNode*>& toRemove) {
NodeRemover remover(this, toRemove);
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.
////////////////////////////////////////////////////////////////////////////////
void ExecutionPlan::removeNode (ExecutionNode* node) {
std::unordered_set<ExecutionNode*> toRemove;
toRemove.insert(node);
return removeNodes(toRemove);
void ExecutionPlan::unlinkNode (ExecutionNode* node) {
std::unordered_set<ExecutionNode*> toUnlink;
toUnlink.insert(node);
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,
oneJsonNode);
addNode(ret);
registerNode(ret);
TRI_ASSERT(ret != nullptr);

View File

@ -146,18 +146,43 @@ namespace triagens {
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.
////////////////////////////////////////////////////////////////////////////////
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.
////////////////////////////////////////////////////////////////////////////////
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
@ -171,11 +196,6 @@ namespace triagens {
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
@ -295,12 +315,6 @@ namespace triagens {
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief all nodes registered, used for memory management
////////////////////////////////////////////////////////////////////////////////
std::vector<ExecutionNode*> _nodes;
////////////////////////////////////////////////////////////////////////////////
/// @brief map from node id to the actual node
////////////////////////////////////////////////////////////////////////////////

View File

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

View File

@ -42,7 +42,7 @@ Optimizer::Optimizer () {
// List all the rules in the system here:
// 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
// filters that are always true will be removed entirely

View File

@ -50,7 +50,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
bool& keep) {
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);
for (auto n : nodes) {
@ -84,21 +84,20 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
if (root->toBoolean()) {
// filter is always true
// remove filter node and merge with following node
toRemove.insert(n);
toUnlink.insert(n);
}
else {
// filter is always false
// TODO: insert a NoResults node below it
//auto noResultsNode = plan->registerNode(new NoResultsNode(plan->nextId()));
//TRI_ASSERT(noResultsNode != nullptr);
}
}
if (! toRemove.empty()) {
std::cout << "Removing " << toRemove.size() << " unnecessary "
if (! toUnlink.empty()) {
std::cout << "Removing " << toUnlink.size() << " unnecessary "
"nodes..." << std::endl;
plan->removeNodes(toRemove);
plan->unlinkNodes(toUnlink);
}
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
// first, delete the calculation from the plan
plan->removeNode(n);
plan->unlinkNode(n);
// fiddle dependencies of calculation node
n->removeDependencies();
@ -208,7 +207,7 @@ int triagens::aql::removeUnnecessaryCalculationsRule (Optimizer* opt,
keep = true;
std::vector<ExecutionNode*> nodes
= plan->findNodesOfType(triagens::aql::ExecutionNode::CALCULATION, true);
std::unordered_set<ExecutionNode*> toRemove;
std::unordered_set<ExecutionNode*> toUnlink;
for (auto n : nodes) {
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
// all further down the pipeline! We remove the whole
// calculation node,
toRemove.insert(n);
toUnlink.insert(n);
}
}
if (! toRemove.empty()) {
std::cout << "Removing " << toRemove.size() << " unnecessary "
if (! toUnlink.empty()) {
std::cout << "Removing " << toUnlink.size() << " unnecessary "
"CalculationNodes..." << std::endl;
plan->removeNodes(toRemove);
plan->unlinkNodes(toUnlink);
}
return TRI_ERROR_NO_ERROR;
@ -246,10 +245,14 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
RangesInfo* _ranges;
ExecutionPlan* _plan;
Variable const* _var;
Optimizer::PlanList _out;
ExecutionNode* _prev;
//EnumerateCollectionNode const* _enumColl;
public:
CalculationNodeFinder (ExecutionPlan* plan, Variable const * var)
: _plan(plan), _var(var){
CalculationNodeFinder (ExecutionPlan* plan, Variable const * var, Optimizer::PlanList& out)
: _plan(plan), _var(var), _out(out), _prev(nullptr){
_ranges = new RangesInfo();
};
@ -259,29 +262,73 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
TRI_ASSERT(outvar.size() == 1);
if(outvar[0]->id == _var->id){
auto node = static_cast<CalculationNode*>(en);
std::string name;
buildRangeInfo(node->expression()->node(), name);
std::string attr;
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){
auto var = static_cast<Variable*>(node->getData());
auto setter = _plan->getVarSetBy(var->id);
auto x = static_cast<Variable*>(node->getData());
auto setter = _plan->getVarSetBy(x->id);
if( setter != nullptr &&
setter->getType() == triagens::aql::ExecutionNode::ENUMERATE_COLLECTION){
name = var->name;
setter->getType() == triagens::aql::ExecutionNode::ENUMERATE_COLLECTION){
enumCollVar = x->name;
}
return;
}
if(node->type == NODE_TYPE_ATTRIBUTE_ACCESS){
char const* attributeName = node->getStringValue();
buildRangeInfo(node->getMember(0), name);
if(!name.empty()){
name.push_back('.');
name.append(attributeName);
buildRangeInfo(node->getMember(0), enumCollVar, attr);
if(!enumCollVar.empty()){
attr.append(attributeName);
attr.push_back('.');
}
}
@ -303,14 +350,13 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
}
if(val != nullptr){
buildRangeInfo(nextNode, name);
if(!name.empty()){
_ranges->insert(name, new RangeInfoBound(val, true),
new RangeInfoBound(val, true));
buildRangeInfo(nextNode, enumCollVar, attr);
if(!enumCollVar.empty()){
_ranges->insert(enumCollVar, attr.substr(0, attr.size()-1),
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 ||
@ -355,21 +401,22 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
}
if(low != nullptr || high != nullptr){
buildRangeInfo(nextNode, name);
if(!name.empty()){
_ranges->insert(name, low, high);
buildRangeInfo(nextNode, enumCollVar, attr);
if(!enumCollVar.empty()){
_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){
buildRangeInfo(node->getMember(0), name);
buildRangeInfo(node->getMember(1), name);
std::cout << _ranges->toString() << "\n";
attr = "";
buildRangeInfo(node->getMember(0), enumCollVar, attr);
attr = "";
buildRangeInfo(node->getMember(1), enumCollVar, attr);
//std::cout << _ranges->toString() << "\n";
}
}
};
////////////////////////////////////////////////////////////////////////////////
@ -380,7 +427,7 @@ int triagens::aql::useIndexRange (Optimizer* opt,
ExecutionPlan* plan,
Optimizer::PlanList& out,
bool& keep) {
keep = true;
std::vector<ExecutionNode*> nodes
= plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
@ -388,7 +435,7 @@ int triagens::aql::useIndexRange (Optimizer* opt,
auto nn = static_cast<FilterNode*>(n);
auto invars = nn->getVariablesUsedHere();
TRI_ASSERT(invars.size() == 1);
CalculationNodeFinder finder(plan, invars[0]);
CalculationNodeFinder finder(plan, invars[0], out);
nn->walk(&finder);
}

View File

@ -246,7 +246,7 @@ QueryResult Query::execute () {
opt.createPlans(plan); // Now plan and all derived plans belong to the
// optimizer
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 stats;