diff --git a/arangod/CMakeLists.txt b/arangod/CMakeLists.txt index b7934d3da0..11fb3a11b1 100644 --- a/arangod/CMakeLists.txt +++ b/arangod/CMakeLists.txt @@ -256,6 +256,7 @@ add_executable( VocBase/shaped-json.cpp VocBase/Shaper.cpp VocBase/transaction.cpp + VocBase/Traverser.cpp VocBase/vocbase.cpp VocBase/vocbase-defaults.cpp VocBase/VocShaper.cpp diff --git a/arangod/Makefile.files b/arangod/Makefile.files index 4a82d762ef..6c1b611f14 100644 --- a/arangod/Makefile.files +++ b/arangod/Makefile.files @@ -218,6 +218,7 @@ arangod_libarangod_a_SOURCES = \ arangod/VocBase/shaped-json.cpp \ arangod/VocBase/Shaper.cpp \ arangod/VocBase/transaction.cpp \ + arangod/VocBase/Traverser.cpp \ arangod/VocBase/vocbase.cpp \ arangod/VocBase/vocbase-defaults.cpp \ arangod/VocBase/VocShaper.cpp \ diff --git a/arangod/V8Server/V8Traverser.cpp b/arangod/V8Server/V8Traverser.cpp index d15c0d24aa..4a1294834d 100644 --- a/arangod/V8Server/V8Traverser.cpp +++ b/arangod/V8Server/V8Traverser.cpp @@ -843,15 +843,13 @@ void DepthFirstTraverser::_defInternalFunctions () { return VertexId(TRI_EXTRACT_MARKER_FROM_CID(&mptr), TRI_EXTRACT_MARKER_FROM_KEY(&mptr)); }; - auto direction = _opts.direction; - auto edgeCols = _edgeCols; - if (direction == TRI_EDGE_ANY) { - _getEdge = [edgeCols] (VertexId& startVertex, std::vector& edges, TRI_doc_mptr_copy_t*& last, size_t& eColIdx, bool& dir) { + if (_opts.direction == TRI_EDGE_ANY) { + _getEdge = [&] (VertexId& startVertex, std::vector& edges, TRI_doc_mptr_copy_t*& last, size_t& eColIdx, bool& dir) { std::vector tmp; - TRI_ASSERT(eColIdx < edgeCols.size()); + TRI_ASSERT(eColIdx < _edgeCols.size()); // TODO fill Statistics // TODO Self referencing edges - triagens::arango::EdgeIndex* edgeIndex = edgeCols.at(eColIdx)->edgeIndex(); + triagens::arango::EdgeIndex* edgeIndex = _edgeCols.at(eColIdx)->edgeIndex(); if (dir) { TRI_edge_index_iterator_t it(TRI_EDGE_OUT, startVertex.cid, startVertex.key); edgeIndex->lookup(&it, tmp, last, 1); @@ -859,12 +857,12 @@ void DepthFirstTraverser::_defInternalFunctions () { // Switch back direction dir = false; ++eColIdx; - if (edgeCols.size() == eColIdx) { + if (_edgeCols.size() == eColIdx) { // No more to do, stop here return; } TRI_edge_index_iterator_t it(TRI_EDGE_IN, startVertex.cid, startVertex.key); - edgeIndex = edgeCols.at(eColIdx)->edgeIndex(); + edgeIndex = _edgeCols.at(eColIdx)->edgeIndex(); edgeIndex->lookup(&it, tmp, last, 1); if (last == nullptr) { dir = true; @@ -884,12 +882,12 @@ void DepthFirstTraverser::_defInternalFunctions () { // The other direction also has no further edges dir = false; ++eColIdx; - if (edgeCols.size() == eColIdx) { + if (_edgeCols.size() == eColIdx) { // No more to do, stop here return; } TRI_edge_index_iterator_t it(TRI_EDGE_IN, startVertex.cid, startVertex.key); - edgeIndex = edgeCols.at(eColIdx)->edgeIndex(); + edgeIndex = _edgeCols.at(eColIdx)->edgeIndex(); edgeIndex->lookup(&it, tmp, last, 1); } } @@ -897,39 +895,62 @@ void DepthFirstTraverser::_defInternalFunctions () { if (last != nullptr) { // sth is stored in tmp. Now push it on edges TRI_ASSERT(tmp.size() == 1); + auto it = _expressions->find(edges.size()); + if (it != _expressions->end()) { + auto shaper = _edgeCols.at(eColIdx)->getShaper(); + for (auto const& exp : it->second) { + if (exp->isEdgeAccess && ! exp->matchesCheck(tmp.back(), shaper)) { + // Retry with the next element + _getEdge(startVertex, edges, last, eColIdx, dir); + return; + } + } + } EdgeInfo e( - edgeCols.at(eColIdx)->_info._cid, + _edgeCols.at(eColIdx)->_info._cid, tmp.back() ); edges.push_back(e); } }; } else { - _getEdge = [edgeCols, direction] (VertexId& startVertex, std::vector& edges, TRI_doc_mptr_copy_t*& last, size_t& eColIdx, bool&) { + _getEdge = [&] (VertexId& startVertex, std::vector& edges, TRI_doc_mptr_copy_t*& last, size_t& eColIdx, bool& dir) { std::vector tmp; - TRI_ASSERT(eColIdx < edgeCols.size()); + TRI_ASSERT(eColIdx < _edgeCols.size()); // Do not touch the bool parameter, as long as it is default the first encountered nullptr is final // TODO fill Statistics - TRI_edge_index_iterator_t it(direction, startVertex.cid, startVertex.key); - triagens::arango::EdgeIndex* edgeIndex = edgeCols.at(eColIdx)->edgeIndex(); + TRI_edge_index_iterator_t it(_opts.direction, startVertex.cid, startVertex.key); + triagens::arango::EdgeIndex* edgeIndex = _edgeCols.at(eColIdx)->edgeIndex(); edgeIndex->lookup(&it, tmp, last, 1); while (last == nullptr) { // This edge collection does not have any more edges for this vertex. Check the next one ++eColIdx; - if (edgeCols.size() == eColIdx) { + if (_edgeCols.size() == eColIdx) { // No more to do, stop here return; } - edgeIndex = edgeCols.at(eColIdx)->edgeIndex(); + edgeIndex = _edgeCols.at(eColIdx)->edgeIndex(); edgeIndex->lookup(&it, tmp, last, 1); } if (last != nullptr) { // sth is stored in tmp. Now push it on edges TRI_ASSERT(tmp.size() == 1); - edges.push_back(EdgeInfo( - edgeCols.at(eColIdx)->_info._cid, + auto it = _expressions->find(edges.size()); + if (it != _expressions->end()) { + auto shaper = _edgeCols.at(eColIdx)->getShaper(); + for (auto const& exp : it->second) { + if (exp->isEdgeAccess && ! exp->matchesCheck(tmp.back(), shaper)) { + // Retry with the next element + _getEdge(startVertex, edges, last, eColIdx, dir); + return; + } + } + } + EdgeInfo e( + _edgeCols.at(eColIdx)->_info._cid, tmp.back() - )); + ); + edges.push_back(e); } }; } diff --git a/arangod/VocBase/Traverser.cpp b/arangod/VocBase/Traverser.cpp new file mode 100644 index 0000000000..d39f5994e2 --- /dev/null +++ b/arangod/VocBase/Traverser.cpp @@ -0,0 +1,62 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief Traverser +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2014-2015 ArangoDB GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is ArangoDB GmbH, Cologne, Germany +/// +/// @author Michael Hackstein +/// @author Copyright 2014-2015, ArangoDB GmbH, Cologne, Germany +/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#include "Traverser.h" + +using TraverserExpression = triagens::arango::traverser::TraverserExpression; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief transforms the expression into json +//////////////////////////////////////////////////////////////////////////////// + +void TraverserExpression::toJson (triagens::basics::Json& json, + TRI_memory_zone_t* zone) const { + auto op = triagens::aql::AstNode::Operators.find(comparisonType); + + if (op == triagens::aql::AstNode::Operators.end()) { + THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_PARSE, "invalid operator for TraverserExpression"); + } + std::string const operatorStr = op->second; + + json("isEdgeAccess", triagens::basics::Json(isEdgeAccess)) + ("comparisonType", triagens::basics::Json(operatorStr)) + ("varAccess", varAccess->toJson(zone, true)); + if (compareTo != nullptr) { + json("compareTo", *compareTo); + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief evalutes if an element matches the given expression +//////////////////////////////////////////////////////////////////////////////// + +bool TraverserExpression::matchesCheck (TRI_doc_mptr_t& element, + VocShaper* shaper) const { + return false; +} diff --git a/arangod/VocBase/Traverser.h b/arangod/VocBase/Traverser.h index a92ebbb1ab..8083198781 100644 --- a/arangod/VocBase/Traverser.h +++ b/arangod/VocBase/Traverser.h @@ -70,21 +70,10 @@ namespace triagens { } void toJson (triagens::basics::Json& json, - TRI_memory_zone_t* zone) const { - auto op = triagens::aql::AstNode::Operators.find(comparisonType); - - if (op == triagens::aql::AstNode::Operators.end()) { - THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_PARSE, "invalid operator for TraverserExpression"); - } - std::string const operatorStr = op->second; + TRI_memory_zone_t* zone) const; - json("isEdgeAccess", triagens::basics::Json(isEdgeAccess)) - ("comparisonType", triagens::basics::Json(operatorStr)) - ("varAccess", varAccess->toJson(zone, true)); - if (compareTo != nullptr) { - json("compareTo", *compareTo); - } - } + bool matchesCheck (TRI_doc_mptr_t& element, + VocShaper* shaper) const; };