From 8d0d921ab6b5296e295b87be3b4168ded46a9aaa Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Thu, 12 Nov 2015 16:25:36 +0100 Subject: [PATCH] Included two Abstract classes for Traversals. Traverser and TraversalPath. Implemented both of them for Single-Server Traversals. --- UnitTests/Basics/PathEnumeratorTest.cpp | 2 +- arangod/Aql/Functions.cpp | 3 +- arangod/Aql/TraversalBlock.cpp | 141 ++-------------- arangod/Aql/TraversalBlock.h | 44 +---- arangod/Aql/TraversalNode.cpp | 2 +- arangod/Aql/TraversalNode.h | 2 +- arangod/V8Server/V8Traverser.cpp | 103 ++++++++++-- arangod/V8Server/V8Traverser.h | 163 +++++++++--------- arangod/V8Server/v8-vocbase.cpp | 2 +- arangod/VocBase/Traverser.h | 215 ++++++++++++++++++++++++ lib/Basics/Traverser.h | 44 ++--- 11 files changed, 430 insertions(+), 291 deletions(-) create mode 100644 arangod/VocBase/Traverser.h diff --git a/UnitTests/Basics/PathEnumeratorTest.cpp b/UnitTests/Basics/PathEnumeratorTest.cpp index 9525502809..b4e36336f8 100644 --- a/UnitTests/Basics/PathEnumeratorTest.cpp +++ b/UnitTests/Basics/PathEnumeratorTest.cpp @@ -126,7 +126,7 @@ BOOST_FIXTURE_TEST_SUITE (PathEnumeratorTest, PathEnumeratorSetup) BOOST_AUTO_TEST_CASE (test_fullPathEnumerator) { int startVertex = 1; PathEnumerator it(integerEdgeEnumerator, integerVertexEnumerator, startVertex); - TraversalPath path; + EnumeratedPath path; for (int k = 1; k < 4; k++) { path = it.next(); BOOST_CHECK_EQUAL(path.edges.size(), (size_t)1); diff --git a/arangod/Aql/Functions.cpp b/arangod/Aql/Functions.cpp index 4ab1cc99aa..e8b70aad51 100644 --- a/arangod/Aql/Functions.cpp +++ b/arangod/Aql/Functions.cpp @@ -47,6 +47,7 @@ using namespace triagens::aql; using Json = triagens::basics::Json; using CollectionNameResolver = triagens::arango::CollectionNameResolver; +using VertexId = triagens::arango::traverser::VertexId; //////////////////////////////////////////////////////////////////////////////// /// @brief thread-local cache for compiled regexes @@ -2255,7 +2256,7 @@ AqlValue Functions::Neighbors (triagens::aql::Query* query, triagens::arango::AqlTransaction* trx, FunctionParameters const& parameters) { size_t const n = parameters.size(); - basics::traverser::NeighborsOptions opts; + triagens::arango::traverser::NeighborsOptions opts; if (n < 4 || n > 6) { THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH, "NEIGHBORS", (int) 4, (int) 6); diff --git a/arangod/Aql/TraversalBlock.cpp b/arangod/Aql/TraversalBlock.cpp index 38c1541f34..9caac85168 100644 --- a/arangod/Aql/TraversalBlock.cpp +++ b/arangod/Aql/TraversalBlock.cpp @@ -30,8 +30,6 @@ #include "Aql/ExecutionPlan.h" #include "Aql/TraversalBlock.h" #include "Aql/ExecutionNode.h" -#include "Utils/ShapedJsonTransformer.h" -#include "Utils/SingleCollectionReadOnlyTransaction.h" #include /// TODO: remove me. using namespace std; @@ -39,6 +37,8 @@ using namespace triagens::basics; using namespace triagens::arango; using namespace triagens::aql; +using VertexId = triagens::arango::traverser::VertexId; + // ----------------------------------------------------------------------------- // --SECTION-- class TraversalBlock // ----------------------------------------------------------------------------- @@ -53,29 +53,17 @@ TraversalBlock::TraversalBlock (ExecutionEngine* engine, _edgeReg(0), _pathReg(0), _condition((ep->condition()) ? ep->condition()->root(): nullptr), - _hasV8Expression(false), - _AccessP(Json::Object, 1), - _currentJsonPath(Json::Array, 10) -{ + _hasV8Expression(false) { - basics::traverser::TraverserOptions opts; + triagens::arango::traverser::TraverserOptions opts; ep->fillTraversalOptions(opts); std::vector edgeCollections; auto cids = ep->edgeCids(); - Json theCurrentJsonPath(Json::Array, 10), - _currentPath(TRI_UNKNOWN_MEM_ZONE, theCurrentJsonPath.json(), Json::NOFREE); - _AccessP = Json(Json::Object, 1) - ("p", Json(Json::Object, 1) - ("edges", theCurrentJsonPath) - ); - - - for (auto const& cid : cids) { edgeCollections.push_back(_trx->documentCollection(cid)); } - _traverser.reset(new basics::traverser::DepthFirstTraverser(edgeCollections, opts)); + _traverser.reset(new triagens::arango::traverser::DepthFirstTraverser(edgeCollections, opts)); _resolver = new CollectionNameResolver(_trx->vocbase()); if (!ep->usesInVariable()) { _vertexId = ep->getStartVertex(); @@ -217,105 +205,9 @@ int TraversalBlock::initializeCursor (AqlItemBlock* items, return TRI_ERROR_NO_ERROR; } -Json TraversalBlock::extractVertexJson ( - VertexId const& v -) { - auto collection = _trx->trxCollection(v.cid); - if (collection == nullptr) { - SingleCollectionReadOnlyTransaction intTrx(new StandaloneTransactionContext(), _trx->vocbase(), v.cid); - int res = intTrx.begin(); - - if (res != TRI_ERROR_NO_ERROR) { - THROW_ARANGO_EXCEPTION(res); - } - collection = intTrx.trxCollection(); - TRI_doc_mptr_copy_t mptr; - intTrx.read(&mptr, v.key); - Json tmp = TRI_ExpandShapedJson( - collection->_collection->_collection->getShaper(), - _resolver, - v.cid, - &mptr - ); - intTrx.finish(res); - return tmp; - } - TRI_doc_mptr_copy_t mptr; - _trx->readSingle(collection, &mptr, v.key); - return TRI_ExpandShapedJson( - collection->_collection->_collection->getShaper(), - _resolver, - v.cid, - &mptr - ); -} - - -Json TraversalBlock::extractEdgeJson ( - EdgeInfo const& e -) { - auto cid = e.cid; - auto collection = _trx->trxCollection(cid); - TRI_shaped_json_t shapedJson; - TRI_EXTRACT_SHAPED_JSON_MARKER(shapedJson, &e.mptr); - return TRI_ExpandShapedJson( - collection->_collection->_collection->getShaper(), - _resolver, - cid, - &e.mptr - ); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Transform the VertexId to AQLValue object -//////////////////////////////////////////////////////////////////////////////// - -AqlValue TraversalBlock::vertexToAqlValue ( - VertexId const& v -) { - // This json is freed by the AqlValue. No unique_ptr here. - Json* result = new Json(extractVertexJson(v)); - return AqlValue(result); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Transform the EdgeInfo to AQLValue object -//////////////////////////////////////////////////////////////////////////////// - -AqlValue TraversalBlock::edgeToAqlValue ( - EdgeInfo const& e -) { - // This json is freed by the AqlValue. No unique_ptr here. - Json* result = new Json(extractEdgeJson(e)); - return AqlValue(result); -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Transform the path to AQLValue object -//////////////////////////////////////////////////////////////////////////////// - -AqlValue TraversalBlock::pathToAqlValue ( - const TraversalPath& p -) { - // This json is freed by the AqlValue. No unique_ptr here. - Json* path = new Json(Json::Object, 2); - Json vertices(Json::Array); - for (size_t i = 0; i < p.vertices.size(); ++i) { - vertices(extractVertexJson(p.vertices[i])); - } - Json edges(Json::Array); - for (size_t i = 0; i < p.edges.size(); ++i) { - edges(extractEdgeJson(p.edges[i])); - } - (*path)("vertices", vertices) - ("edges", edges); - - return AqlValue(path); -} - - bool TraversalBlock::executeExpressions (AqlValue& pathValue) { TRI_ASSERT(_condition != nullptr); + return true; auto& toReplace = _nonConstExpressions[0]; @@ -338,7 +230,7 @@ bool TraversalBlock::executeExpressions (AqlValue& pathValue) { //////////////////////////////////////////////////////////////////////////////// /// @brief read more paths //////////////////////////////////////////////////////////////////////////////// - +#include bool TraversalBlock::morePaths (size_t hint) { freeCaches(); _posInPaths = 0; @@ -349,29 +241,28 @@ bool TraversalBlock::morePaths (size_t hint) { for (size_t j = 0; j < hint; ++j) { auto p = _traverser->next(); - if (p.edges.size() == 0) { + if (p == nullptr) { // There are no further paths available. break; } - _currentJsonPath.add(extractEdgeJson(p.edges.back())); AqlValue pathValue; - if (usesPathOutput() || (en->condition() != NULL)) { - pathValue = pathToAqlValue(p); + if (usesPathOutput() || (en->condition() != nullptr)) { + pathValue = AqlValue(p->pathToJson(_trx, _resolver)); } - if ((en->condition() != NULL) && - !executeExpressions(pathValue)) { + if ((en->condition() != nullptr) && + ! executeExpressions(pathValue)) { _traverser->prune(); continue; } if ( usesVertexOutput() ) { - _vertices.push_back(vertexToAqlValue(p.vertices.back())); + _vertices.emplace_back(p->lastVertexToJson(_trx, _resolver)); } if ( usesEdgeOutput() ) { - _edges.push_back(edgeToAqlValue(p.edges.back())); + _edges.emplace_back(p->lastEdgeToJson(_trx, _resolver)); } if ( usesPathOutput() ) { _paths.push_back(pathValue); @@ -422,7 +313,7 @@ void TraversalBlock::initializePaths (AqlItemBlock const* items) { Json _idJson = input.get("_id"); if (_idJson.isString()) { _vertexId = JsonHelper::getStringValue(_idJson.json(), ""); - VertexId v = triagens::basics::traverser::IdStringToVertexId ( + VertexId v = triagens::arango::traverser::IdStringToVertexId ( _resolver, _vertexId ); @@ -436,7 +327,7 @@ void TraversalBlock::initializePaths (AqlItemBlock const* items) { Json _idJson = vertexJson.get("_id"); if (_idJson.isString()) { _vertexId = JsonHelper::getStringValue(_idJson.json(), ""); - VertexId v = triagens::basics::traverser::IdStringToVertexId ( + VertexId v = triagens::arango::traverser::IdStringToVertexId ( _resolver, _vertexId ); diff --git a/arangod/Aql/TraversalBlock.h b/arangod/Aql/TraversalBlock.h index 054a5a80f9..151edb9001 100644 --- a/arangod/Aql/TraversalBlock.h +++ b/arangod/Aql/TraversalBlock.h @@ -113,7 +113,7 @@ namespace triagens { /// @brief Depth first Traverser object //////////////////////////////////////////////////////////////////////////////// - std::unique_ptr _traverser; + std::unique_ptr _traverser; //////////////////////////////////////////////////////////////////////////////// /// @brief The information to get the starting point. Can either be a constant @@ -122,7 +122,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// union { - VertexId _startId; + triagens::arango::traverser::VertexId _startId; size_t _reg; }; @@ -282,46 +282,6 @@ namespace triagens { return _pathVar != nullptr; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief Helper function to extract JSON from a vertexId object -//////////////////////////////////////////////////////////////////////////////// - - basics::Json extractVertexJson ( - VertexId const& v - ); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief Helper function to extract JSON from a EdgeInfo object -//////////////////////////////////////////////////////////////////////////////// - - basics::Json extractEdgeJson ( - EdgeInfo const& e - ); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief transform a VertexId to AqlValue -//////////////////////////////////////////////////////////////////////////////// - - AqlValue vertexToAqlValue ( - VertexId const& v - ); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief transform a EdgeInfo to AqlValue -//////////////////////////////////////////////////////////////////////////////// - - AqlValue edgeToAqlValue ( - EdgeInfo const& e - ); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief transform the Traversalpath object to AqlValue -//////////////////////////////////////////////////////////////////////////////// - - AqlValue pathToAqlValue ( - const basics::TraversalPath& p - ); - }; } // namespace triagens::aql } // namespace triagens diff --git a/arangod/Aql/TraversalNode.cpp b/arangod/Aql/TraversalNode.cpp index ccb7f3b7fd..fa993ccc7a 100644 --- a/arangod/Aql/TraversalNode.cpp +++ b/arangod/Aql/TraversalNode.cpp @@ -362,7 +362,7 @@ double TraversalNode::estimateCost (size_t& nrItems) const { return depCost + nrItems; } -void TraversalNode::fillTraversalOptions (basics::traverser::TraverserOptions& opts) const { +void TraversalNode::fillTraversalOptions (triagens::arango::traverser::TraverserOptions& opts) const { opts.direction = _direction; opts.minDepth = _minDepth; opts.maxDepth = _maxDepth; diff --git a/arangod/Aql/TraversalNode.h b/arangod/Aql/TraversalNode.h index 470852109a..4cdc3ec0bd 100644 --- a/arangod/Aql/TraversalNode.h +++ b/arangod/Aql/TraversalNode.h @@ -267,7 +267,7 @@ namespace triagens { /// with default values. //////////////////////////////////////////////////////////////////////////////// - void fillTraversalOptions (basics::traverser::TraverserOptions& opts) const; + void fillTraversalOptions (triagens::arango::traverser::TraverserOptions& opts) const; std::vector const edgeCids () const { return _edgeCids; diff --git a/arangod/V8Server/V8Traverser.cpp b/arangod/V8Server/V8Traverser.cpp index 7676942600..1a0bd5045c 100644 --- a/arangod/V8Server/V8Traverser.cpp +++ b/arangod/V8Server/V8Traverser.cpp @@ -32,14 +32,16 @@ #include "Utils/transactions.h" #include "Utils/V8ResolverGuard.h" #include "Utils/CollectionNameResolver.h" +#include "Utils/ShapedJsonTransformer.h" +#include "Utils/SingleCollectionReadOnlyTransaction.h" #include "VocBase/document-collection.h" #include "VocBase/KeyGenerator.h" #include "VocBase/VocShaper.h" using namespace std; using namespace triagens::basics; -using namespace triagens::basics::traverser; using namespace triagens::arango; +using namespace triagens::arango::traverser; //////////////////////////////////////////////////////////////////////////////// /// @brief extract the _from Id out of mptr, we return an RValue reference @@ -68,7 +70,7 @@ static VertexId ExtractToId (TRI_doc_mptr_copy_t const& ptr) { /// VertexId is in use //////////////////////////////////////////////////////////////////////////////// -VertexId triagens::basics::traverser::IdStringToVertexId ( +VertexId triagens::arango::traverser::IdStringToVertexId ( CollectionNameResolver const* resolver, string const& vertex ) { @@ -718,6 +720,85 @@ void TRI_RunNeighborsSearch ( } } +// ----------------------------------------------------------------------------- +// --SECTION-- class SingleServerTraversalPath +// ----------------------------------------------------------------------------- + +Json* SingleServerTraversalPath::pathToJson (Transaction* trx, + CollectionNameResolver* resolver) const { + std::unique_ptr path(new Json(Json::Object, 2)); + Json vertices(Json::Array); + for (size_t i = 0; i < _path.vertices.size(); ++i) { + vertices(*vertexToJson(trx, resolver, _path.vertices[i])); + } + Json edges(Json::Array); + for (size_t i = 0; i < _path.edges.size(); ++i) { + edges(*edgeToJson(trx, resolver, _path.edges[i])); + } + (*path)("vertices", vertices) + ("edges", edges); + + return path.release(); +} + + +Json* SingleServerTraversalPath::lastEdgeToJson (Transaction* trx, + CollectionNameResolver* resolver) const { + return edgeToJson(trx, resolver, _path.edges.back()); +} + +Json* SingleServerTraversalPath::lastVertexToJson (Transaction* trx, + CollectionNameResolver* resolver) const { + return vertexToJson(trx, resolver, _path.vertices.back()); +} + +Json* SingleServerTraversalPath::edgeToJson (Transaction* trx, + CollectionNameResolver* resolver, + EdgeInfo const& e) const { + auto collection = trx->trxCollection(e.cid); + TRI_shaped_json_t shapedJson; + TRI_EXTRACT_SHAPED_JSON_MARKER(shapedJson, &e.mptr); + return new Json(TRI_ExpandShapedJson( + collection->_collection->_collection->getShaper(), + resolver, + e.cid, + &e.mptr + )); +} + +Json* SingleServerTraversalPath::vertexToJson (Transaction* trx, + CollectionNameResolver* resolver, + VertexId const& v) const { + auto collection = trx->trxCollection(v.cid); + if (collection == nullptr) { + SingleCollectionReadOnlyTransaction intTrx(new StandaloneTransactionContext(), trx->vocbase(), v.cid); + int res = intTrx.begin(); + + if (res != TRI_ERROR_NO_ERROR) { + THROW_ARANGO_EXCEPTION(res); + } + collection = intTrx.trxCollection(); + TRI_doc_mptr_copy_t mptr; + intTrx.read(&mptr, v.key); + std::unique_ptr tmp(new Json(TRI_ExpandShapedJson( + collection->_collection->_collection->getShaper(), + resolver, + v.cid, + &mptr + ))); + intTrx.finish(res); + return tmp.release(); + } + TRI_doc_mptr_copy_t mptr; + trx->readSingle(collection, &mptr, v.key); + return new Json(TRI_ExpandShapedJson( + collection->_collection->_collection->getShaper(), + resolver, + v.cid, + &mptr + )); +} + // ----------------------------------------------------------------------------- // --SECTION-- class DepthFirstTraverser // ----------------------------------------------------------------------------- @@ -856,10 +937,9 @@ void DepthFirstTraverser::setStartVertex (VertexId& v) { size_t DepthFirstTraverser::skip (size_t amount) { size_t skipped = 0; - TraversalPath p; for (size_t i = 0; i < amount; ++i) { - p = next(); - if (p.edges.size() == 0) { + std::unique_ptr p(next()); + if (p == nullptr) { break; } ++skipped; @@ -871,21 +951,22 @@ bool DepthFirstTraverser::hasMore () { return !_done; } -const TraversalPath& DepthFirstTraverser::next () { +const TraversalPath* DepthFirstTraverser::next () { TRI_ASSERT(!_done); if (_pruneNext) { _pruneNext = false; _enumerator->prune(); } TRI_ASSERT(!_pruneNext); - const TraversalPath& p = _enumerator->next(); - size_t countEdges = p.edges.size(); + const EnumeratedPath& path = _enumerator->next(); + size_t countEdges = path.edges.size(); if (countEdges == 0) { _done = true; // Done traversing - return p; + return nullptr; } - if (_opts.shouldPrunePath(p)) { + std::unique_ptr p(new SingleServerTraversalPath(path)); + if (_opts.shouldPrunePath(p.get())) { _enumerator->prune(); return next(); } @@ -895,7 +976,7 @@ const TraversalPath& DepthFirstTraverse if (countEdges < _opts.minDepth) { return next(); } - return p; + return p.release(); } void DepthFirstTraverser::prune () { diff --git a/arangod/V8Server/V8Traverser.h b/arangod/V8Server/V8Traverser.h index 2304e1373a..3051b0421a 100644 --- a/arangod/V8Server/V8Traverser.h +++ b/arangod/V8Server/V8Traverser.h @@ -35,39 +35,10 @@ #include "Utils/ExplicitTransaction.h" #include "VocBase/edge-collection.h" #include "VocBase/ExampleMatcher.h" +#include "VocBase/Traverser.h" class VocShaper; -//////////////////////////////////////////////////////////////////////////////// -/// @brief Template for a vertex id. Is simply a pair of cid and key -/// NOTE: This struct will never free the value asigned to char const* key -/// The environment has to make sure that the string it points to is -/// not freed as long as this struct is in use! -//////////////////////////////////////////////////////////////////////////////// - -struct VertexId { - TRI_voc_cid_t cid; - char const* key; - - VertexId () - : cid(0), - key("") { - } - - VertexId (TRI_voc_cid_t cid, char const* key) - : cid(cid), - key(key) { - } - - bool operator== (const VertexId& other) const { - if (cid == other.cid) { - return strcmp(key, other.key) == 0; - } - return false; - } - -}; - struct EdgeInfo { TRI_voc_cid_t cid; TRI_doc_mptr_copy_t mptr; @@ -78,41 +49,6 @@ struct EdgeInfo { ) : cid(pcid), mptr(pmptr) { } }; -namespace std { - template<> - struct hash { - public: - size_t operator() (VertexId const& s) const { - size_t h1 = std::hash()(s.cid); - size_t h2 = TRI_FnvHashString(s.key); - return h1 ^ ( h2 << 1 ); - } - }; - - template<> - struct equal_to { - public: - bool operator() (VertexId const& s, VertexId const& t) const { - return s.cid == t.cid && strcmp(s.key, t.key) == 0; - } - }; - - template<> - struct less { - public: - bool operator() (const VertexId& lhs, const VertexId& rhs) { - if (lhs.cid != rhs.cid) { - return lhs.cid < rhs.cid; - } - return strcmp(lhs.key, rhs.key) < 0; - } - }; - -} - -// EdgeId and VertexId are similar here. both have a key and a cid -typedef VertexId EdgeId; - //////////////////////////////////////////////////////////////////////////////// /// @brief Template for information required by vertex filter. /// Contains transaction, barrier and the Matcher Class. @@ -137,14 +73,17 @@ struct VertexFilterInfo { /// @brief typedef the template instantiation of the PathFinder //////////////////////////////////////////////////////////////////////////////// -typedef triagens::basics::PathFinder +typedef triagens::basics::PathFinder ArangoDBPathFinder; -typedef triagens::basics::ConstDistanceFinder +typedef triagens::basics::ConstDistanceFinder ArangoDBConstDistancePathFinder; namespace triagens { - namespace basics { + namespace arango { namespace traverser { //////////////////////////////////////////////////////////////////////////////// @@ -189,7 +128,7 @@ namespace triagens { TRI_voc_cid_t const& cid, std::string& errorMessage); - void addEdgeFilter (Json const& example, + void addEdgeFilter (triagens::basics::Json const& example, VocShaper* shaper, TRI_voc_cid_t const& cid, triagens::arango::CollectionNameResolver const* resolver); @@ -262,7 +201,7 @@ namespace triagens { struct TraverserOptions { private: - std::function& path)> pruningFunction; + std::function pruningFunction; public: TRI_edge_direction_e direction; @@ -282,14 +221,14 @@ namespace triagens { { }; void setPruningFunction ( - std::function& path)> callback + std::function callback ) { pruningFunction = callback; usesPrune = true; } bool shouldPrunePath ( - const TraversalPath& path + const TraversalPath* path ) { if (!usesPrune) { return false; @@ -299,10 +238,60 @@ namespace triagens { }; +// ----------------------------------------------------------------------------- +// --SECTION-- class SingleServerTraversalPath +// ----------------------------------------------------------------------------- + + class SingleServerTraversalPath : public TraversalPath { + +// ----------------------------------------------------------------------------- +// --SECTION-- public functions +// ----------------------------------------------------------------------------- + public: + + SingleServerTraversalPath ( + const triagens::basics::EnumeratedPath& path + ) : _path(path) { + } + + ~SingleServerTraversalPath () { + } + + triagens::basics::Json* pathToJson (Transaction*, + CollectionNameResolver*) const override; + + triagens::basics::Json* lastEdgeToJson (Transaction*, + CollectionNameResolver*) const override; + + triagens::basics::Json* lastVertexToJson (Transaction*, + CollectionNameResolver*) const override; + + private: + +// ----------------------------------------------------------------------------- +// --SECTION-- private functions +// ----------------------------------------------------------------------------- + + triagens::basics::Json* edgeToJson (Transaction* trx, + CollectionNameResolver* resolver, + EdgeInfo const& e) const; + + triagens::basics::Json* vertexToJson (Transaction* trx, + CollectionNameResolver* resolver, + VertexId const& v) const; + +// ----------------------------------------------------------------------------- +// --SECTION-- private variables +// ----------------------------------------------------------------------------- + + triagens::basics::EnumeratedPath _path; + + }; + // ----------------------------------------------------------------------------- // --SECTION-- class DepthFirstTraverser // ----------------------------------------------------------------------------- - class DepthFirstTraverser { + class DepthFirstTraverser : public Traverser { private: @@ -328,7 +317,9 @@ namespace triagens { /// @brief internal cursor to enumerate the paths of a graph //////////////////////////////////////////////////////////////////////////////// - std::unique_ptr> _enumerator; + std::unique_ptr> _enumerator; //////////////////////////////////////////////////////////////////////////////// /// @brief internal function to extract an edge @@ -375,25 +366,25 @@ namespace triagens { /// @brief Reset the traverser to use another start vertex //////////////////////////////////////////////////////////////////////////////// - void setStartVertex (VertexId& v); + void setStartVertex (VertexId& v) override; //////////////////////////////////////////////////////////////////////////////// /// @brief Skip amount many paths of the graph. //////////////////////////////////////////////////////////////////////////////// - size_t skip (size_t amount); + size_t skip (size_t amount) override; //////////////////////////////////////////////////////////////////////////////// /// @brief Get the next possible path in the graph. //////////////////////////////////////////////////////////////////////////////// - const TraversalPath& next (); + const TraversalPath* next () override; //////////////////////////////////////////////////////////////////////////////// /// @brief Prune the current path prefix. Do not evaluate it any further. //////////////////////////////////////////////////////////////////////////////// - void prune (); + void prune () override; //////////////////////////////////////////////////////////////////////////////// /// @brief Simple check if there potentially more paths. @@ -401,7 +392,7 @@ namespace triagens { /// If it returns false it is guaranteed that there are no more paths. //////////////////////////////////////////////////////////////////////////////// - bool hasMore (); + bool hasMore () override; }; @@ -453,12 +444,12 @@ class EdgeCollectionInfo { _weighter(weighter) { } - EdgeId extractEdgeId (TRI_doc_mptr_copy_t& ptr) { - return EdgeId(_edgeCollectionCid, TRI_EXTRACT_MARKER_KEY(&ptr)); + triagens::arango::traverser::EdgeId extractEdgeId (TRI_doc_mptr_copy_t& ptr) { + return triagens::arango::traverser::EdgeId(_edgeCollectionCid, TRI_EXTRACT_MARKER_KEY(&ptr)); } std::vector getEdges (TRI_edge_direction_e direction, - VertexId const& vertexId) const { + triagens::arango::traverser::VertexId const& vertexId) const { return TRI_LookupEdgesDocumentCollection(_edgeCollection, direction, vertexId.cid, const_cast(vertexId.key)); } @@ -525,13 +516,13 @@ class VertexCollectionInfo { std::unique_ptr TRI_RunShortestPathSearch ( std::vector& collectionInfos, - triagens::basics::traverser::ShortestPathOptions& opts + triagens::arango::traverser::ShortestPathOptions& opts ); std::unique_ptr TRI_RunSimpleShortestPathSearch ( std::vector& collectionInfos, - triagens::basics::traverser::ShortestPathOptions& opts + triagens::arango::traverser::ShortestPathOptions& opts ); //////////////////////////////////////////////////////////////////////////////// @@ -539,7 +530,7 @@ std::unique_ptr TRI_RunSimpleShortestPath //////////////////////////////////////////////////////////////////////////////// void TRI_RunNeighborsSearch (std::vector& collectionInfos, - triagens::basics::traverser::NeighborsOptions& opts, - std::unordered_set& distinct); + triagens::arango::traverser::NeighborsOptions& opts, + std::unordered_set& distinct); #endif diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index 13964edbd8..3f7cee4886 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -73,8 +73,8 @@ using namespace std; using namespace triagens::basics; -using namespace triagens::basics::traverser; using namespace triagens::arango; +using namespace triagens::arango::traverser; using namespace triagens::rest; using namespace arangodb; diff --git a/arangod/VocBase/Traverser.h b/arangod/VocBase/Traverser.h new file mode 100644 index 0000000000..9a675daf46 --- /dev/null +++ b/arangod/VocBase/Traverser.h @@ -0,0 +1,215 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ARANGODB_VOCBASE_TRAVERSER_H +#define ARANGODB_VOCBASE_TRAVERSER_H 1 + +#include "basics/Traverser.h" + +namespace triagens { + namespace arango { + namespace traverser { + + +// ----------------------------------------------------------------------------- +// --SECTION-- struct VertexId +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Template for a vertex id. Is simply a pair of cid and key +/// NOTE: This struct will never free the value asigned to char const* key +/// The environment has to make sure that the string it points to is +/// not freed as long as this struct is in use! +//////////////////////////////////////////////////////////////////////////////// + + struct VertexId { + TRI_voc_cid_t cid; + char const* key; + + VertexId () + : cid(0), + key("") { + } + + VertexId (TRI_voc_cid_t cid, char const* key) + : cid(cid), + key(key) { + } + + bool operator== (const VertexId& other) const { + if (cid == other.cid) { + return strcmp(key, other.key) == 0; + } + return false; + } + + }; + + // EdgeId and VertexId are similar here. both have a key and a cid + typedef VertexId EdgeId; + +// ----------------------------------------------------------------------------- +// --SECTION-- class TraversalPath +// ----------------------------------------------------------------------------- + + class TraversalPath { + + public: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Constructor. This is an abstract only class. +//////////////////////////////////////////////////////////////////////////////// + + TraversalPath () { + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Builds the complete path as Json +/// Has the format: +/// { +/// vertices: [], +/// edges: [] +/// } +//////////////////////////////////////////////////////////////////////////////// + + virtual triagens::basics::Json* pathToJson (Transaction*, + CollectionNameResolver*) const = 0; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Builds only the last edge on the path as Json +//////////////////////////////////////////////////////////////////////////////// + + virtual triagens::basics::Json* lastEdgeToJson (Transaction*, + CollectionNameResolver*) const = 0; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Builds only the last vertex as Json +//////////////////////////////////////////////////////////////////////////////// + + virtual triagens::basics::Json* lastVertexToJson (Transaction*, + CollectionNameResolver*) const = 0; + + }; + +// ----------------------------------------------------------------------------- +// --SECTION-- class Traverser +// ----------------------------------------------------------------------------- + + class Traverser { + + public: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Constructor. This is an abstract only class. +//////////////////////////////////////////////////////////////////////////////// + + Traverser () { + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Destructor +//////////////////////////////////////////////////////////////////////////////// + + ~Traverser () { + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Reset the traverser to use another start vertex +//////////////////////////////////////////////////////////////////////////////// + + virtual void setStartVertex (VertexId& v) = 0; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Skip amount many paths of the graph. +//////////////////////////////////////////////////////////////////////////////// + + virtual size_t skip (size_t amount) = 0; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Get the next possible path in the graph. +//////////////////////////////////////////////////////////////////////////////// + + virtual const TraversalPath* next () = 0; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Prune the current path prefix. Do not evaluate it any further. +//////////////////////////////////////////////////////////////////////////////// + + virtual void prune () = 0; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Simple check if there potentially more paths. +/// It might return true although there are no more paths available. +/// If it returns false it is guaranteed that there are no more paths. +//////////////////////////////////////////////////////////////////////////////// + + virtual bool hasMore () = 0; + + }; + + } // traverser + } // arango +} // triagens + +// ----------------------------------------------------------------------------- +// --SECTION-- functions for std::containers +// ----------------------------------------------------------------------------- + +namespace std { + template<> + struct hash { + public: + size_t operator() (triagens::arango::traverser::VertexId const& s) const { + size_t h1 = std::hash()(s.cid); + size_t h2 = TRI_FnvHashString(s.key); + return h1 ^ ( h2 << 1 ); + } + }; + + template<> + struct equal_to { + public: + bool operator() (triagens::arango::traverser::VertexId const& s, triagens::arango::traverser::VertexId const& t) const { + return s.cid == t.cid && strcmp(s.key, t.key) == 0; + } + }; + + template<> + struct less { + public: + bool operator() (const triagens::arango::traverser::VertexId& lhs, const triagens::arango::traverser::VertexId& rhs) { + if (lhs.cid != rhs.cid) { + return lhs.cid < rhs.cid; + } + return strcmp(lhs.key, rhs.key) < 0; + } + }; +} + +#endif diff --git a/lib/Basics/Traverser.h b/lib/Basics/Traverser.h index f42851d87b..ad9badc7f2 100644 --- a/lib/Basics/Traverser.h +++ b/lib/Basics/Traverser.h @@ -1232,14 +1232,14 @@ namespace triagens { }; // ----------------------------------------------------------------------------- -// --SECTION-- struct TraversalPath +// --SECTION-- struct EnumeratedPath // ----------------------------------------------------------------------------- - template - struct TraversalPath { + template + struct EnumeratedPath { std::vector edges; std::vector vertices; - TraversalPath () {} + EnumeratedPath () {} }; // ----------------------------------------------------------------------------- @@ -1262,7 +1262,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// /// @brief List of the last path is used to //////////////////////////////////////////////////////////////////////////////// - TraversalPath _traversalPath; + EnumeratedPath _enumeratedPath; //////////////////////////////////////////////////////////////////////////////// /// @brief The pointers returned for edge indexes on this path. Used to continue @@ -1310,11 +1310,11 @@ namespace triagens { vertexIdentifier& startVertex ) : _getEdge(getEdge), _getVertex(getVertex) { - _traversalPath.vertices.push_back(startVertex); + _enumeratedPath.vertices.push_back(startVertex); _lastEdges.push(nullptr); _lastEdgesDir.push(false); _lastEdgesIdx.push(0); - TRI_ASSERT(_traversalPath.vertices.size() == 1); + TRI_ASSERT(_enumeratedPath.vertices.size() == 1); TRI_ASSERT(_lastEdges.size() == 1); TRI_ASSERT(_lastEdgesDir.size() == 1); }; @@ -1329,32 +1329,32 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// /// @brief Get the next Path element from the traversal. //////////////////////////////////////////////////////////////////////////////// - const TraversalPath& next () { + const EnumeratedPath& next () { if (_lastEdges.size() == 0) { - _traversalPath.edges.clear(); - _traversalPath.vertices.clear(); - return _traversalPath; + _enumeratedPath.edges.clear(); + _enumeratedPath.vertices.clear(); + return _enumeratedPath; } - _getEdge(_traversalPath.vertices.back(), _traversalPath.edges, _lastEdges.top(), _lastEdgesIdx.top(), _lastEdgesDir.top()); + _getEdge(_enumeratedPath.vertices.back(), _enumeratedPath.edges, _lastEdges.top(), _lastEdgesIdx.top(), _lastEdgesDir.top()); if (_lastEdges.top() != nullptr) { // Could continue the path in the next depth. _lastEdges.push(nullptr); _lastEdgesDir.push(false); _lastEdgesIdx.push(0); - vertexIdentifier v = _getVertex(_traversalPath.edges.back(), _traversalPath.vertices.back()); - _traversalPath.vertices.push_back(v); - TRI_ASSERT(_traversalPath.vertices.size() == _traversalPath.edges.size() + 1); + vertexIdentifier v = _getVertex(_enumeratedPath.edges.back(), _enumeratedPath.vertices.back()); + _enumeratedPath.vertices.push_back(v); + TRI_ASSERT(_enumeratedPath.vertices.size() == _enumeratedPath.edges.size() + 1); } else { - if (_traversalPath.edges.size() == 0) { + if (_enumeratedPath.edges.size() == 0) { // We are done with enumerating paths - _traversalPath.edges.clear(); - _traversalPath.vertices.clear(); + _enumeratedPath.edges.clear(); + _enumeratedPath.vertices.clear(); } else { prune(); return next(); } } - return _traversalPath; + return _enumeratedPath; } //////////////////////////////////////////////////////////////////////////////// @@ -1366,9 +1366,9 @@ namespace triagens { _lastEdges.pop(); _lastEdgesDir.pop(); _lastEdgesIdx.pop(); - if (_traversalPath.edges.size() > 0) { - _traversalPath.edges.pop_back(); - _traversalPath.vertices.pop_back(); + if (_enumeratedPath.edges.size() > 0) { + _enumeratedPath.edges.pop_back(); + _enumeratedPath.vertices.pop_back(); } } }