//////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// /// Copyright 2014-2016 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 //////////////////////////////////////////////////////////////////////////////// #ifndef ARANGOD_VOC_BASE_TRAVERSER_H #define ARANGOD_VOC_BASE_TRAVERSER_H 1 #include "Basics/Common.h" #include "Basics/hashes.h" #include "Basics/ShortestPathFinder.h" #include "Basics/VelocyPackHelper.h" #include "Aql/AqlValue.h" #include "Aql/AstNode.h" #include "VocBase/PathEnumerator.h" #include "VocBase/voc-types.h" namespace arangodb { class ManagedDocumentResult; class Transaction; namespace velocypack { class Builder; class Slice; } namespace aql { struct AstNode; class Expression; class Query; } namespace traverser { struct TraverserOptions; class ShortestPath { friend class arangodb::basics::DynamicDistanceFinder< arangodb::velocypack::Slice, arangodb::velocypack::Slice, double, ShortestPath>; friend class arangodb::basics::ConstDistanceFinder< arangodb::velocypack::Slice, arangodb::velocypack::Slice, arangodb::basics::VelocyPackHelper::VPackStringHash, arangodb::basics::VelocyPackHelper::VPackStringEqual, ShortestPath>; public: ////////////////////////////////////////////////////////////////////////////// /// @brief Constructor. This is an abstract only class. ////////////////////////////////////////////////////////////////////////////// ShortestPath() : _readDocuments(0) {} ~ShortestPath() {} /// @brief Clears the path void clear(); /// @brief Builds only the last edge pointing to the vertex at position as /// VelocyPack void edgeToVelocyPack(Transaction*, ManagedDocumentResult*, size_t, arangodb::velocypack::Builder&); ////////////////////////////////////////////////////////////////////////////// /// @brief Builds only the vertex at position as VelocyPack ////////////////////////////////////////////////////////////////////////////// void vertexToVelocyPack(Transaction*, ManagedDocumentResult*, size_t, arangodb::velocypack::Builder&); ////////////////////////////////////////////////////////////////////////////// /// @brief Gets the amount of read documents ////////////////////////////////////////////////////////////////////////////// size_t getReadDocuments() const { return _readDocuments; } /// @brief Gets the length of the path. (Number of vertices) size_t length() { return _vertices.size(); }; private: /// @brief Count how many documents have been read size_t _readDocuments; // Convention _vertices.size() -1 === _edges.size() // path is _vertices[0] , _edges[0], _vertices[1] etc. /// @brief vertices std::deque _vertices; /// @brief edges std::deque _edges; }; class TraversalPath { public: ////////////////////////////////////////////////////////////////////////////// /// @brief Constructor. This is an abstract only class. ////////////////////////////////////////////////////////////////////////////// TraversalPath() : _readDocuments(0) {} virtual ~TraversalPath() {} ////////////////////////////////////////////////////////////////////////////// /// @brief Builds the complete path as VelocyPack /// Has the format: /// { /// vertices: [], /// edges: [] /// } ////////////////////////////////////////////////////////////////////////////// virtual void pathToVelocyPack(Transaction*, arangodb::velocypack::Builder&) = 0; ////////////////////////////////////////////////////////////////////////////// /// @brief Builds only the last edge on the path as VelocyPack ////////////////////////////////////////////////////////////////////////////// virtual void lastEdgeToVelocyPack(Transaction*, arangodb::velocypack::Builder&) = 0; ////////////////////////////////////////////////////////////////////////////// /// @brief Builds only the last vertex as VelocyPack ////////////////////////////////////////////////////////////////////////////// virtual aql::AqlValue lastVertexToAqlValue(Transaction*) = 0; ////////////////////////////////////////////////////////////////////////////// /// @brief Gets the amount of read documents ////////////////////////////////////////////////////////////////////////////// virtual size_t getReadDocuments() const { return _readDocuments; } protected: ////////////////////////////////////////////////////////////////////////////// /// @brief Count how many documents have been read ////////////////////////////////////////////////////////////////////////////// size_t _readDocuments; }; class Traverser { friend class BreadthFirstEnumerator; friend class DepthFirstEnumerator; friend class NeighborsEnumerator; #ifdef USE_ENTERPRISE friend class SmartDepthFirstPathEnumerator; friend class SmartBreadthFirstPathEnumerator; #endif protected: ////////////////////////////////////////////////////////////////////////////// /// @brief Class to read vertices. ///////////////////////////////////////////////////////////////////////////// class VertexGetter { public: explicit VertexGetter(Traverser* traverser) : _traverser(traverser) {} virtual ~VertexGetter() = default; virtual bool getVertex(arangodb::velocypack::Slice, std::vector&); virtual bool getSingleVertex(arangodb::velocypack::Slice, arangodb::velocypack::Slice, size_t, arangodb::velocypack::Slice&); virtual void reset(arangodb::velocypack::Slice); protected: Traverser* _traverser; }; ////////////////////////////////////////////////////////////////////////////// /// @brief Class to read vertices. Will return each vertex exactly once! ///////////////////////////////////////////////////////////////////////////// class UniqueVertexGetter : public VertexGetter { public: explicit UniqueVertexGetter(Traverser* traverser) : VertexGetter(traverser) {} ~UniqueVertexGetter() = default; bool getVertex(arangodb::velocypack::Slice, std::vector&) override; bool getSingleVertex(arangodb::velocypack::Slice, arangodb::velocypack::Slice, size_t, arangodb::velocypack::Slice&) override; void reset(arangodb::velocypack::Slice) override; private: std::unordered_set _returnedVertices; }; public: ////////////////////////////////////////////////////////////////////////////// /// @brief Constructor. This is an abstract only class. ////////////////////////////////////////////////////////////////////////////// Traverser(TraverserOptions* opts, Transaction* trx, ManagedDocumentResult*); ////////////////////////////////////////////////////////////////////////////// /// @brief Destructor ////////////////////////////////////////////////////////////////////////////// virtual ~Traverser() {} ////////////////////////////////////////////////////////////////////////////// /// @brief Reset the traverser to use another start vertex ////////////////////////////////////////////////////////////////////////////// virtual void setStartVertex(std::string const& value) = 0; ////////////////////////////////////////////////////////////////////////////// /// @brief Skip amount many paths of the graph. ////////////////////////////////////////////////////////////////////////////// size_t skip(size_t amount) { size_t skipped = 0; for (size_t i = 0; i < amount; ++i) { if (!next()) { _done = true; break; } ++skipped; } return skipped; } /// @brief Get the next possible path in the graph. bool next(); /// @brief Function to load the other sides vertex of an edge /// Returns true if the vertex passes filtering conditions /// Also appends the _id value of the vertex in the given vector protected: virtual bool getVertex(arangodb::velocypack::Slice, std::vector&) = 0; /// @brief Function to load the other sides vertex of an edge /// Returns true if the vertex passes filtering conditions virtual bool getSingleVertex(arangodb::velocypack::Slice, arangodb::velocypack::Slice, size_t, arangodb::velocypack::Slice&) = 0; public: ////////////////////////////////////////////////////////////////////////////// /// @brief Builds only the last vertex as AQLValue ////////////////////////////////////////////////////////////////////////////// aql::AqlValue lastVertexToAqlValue(); ////////////////////////////////////////////////////////////////////////////// /// @brief Builds only the last edge as AQLValue ////////////////////////////////////////////////////////////////////////////// aql::AqlValue lastEdgeToAqlValue(); ////////////////////////////////////////////////////////////////////////////// /// @brief Builds the complete path as AQLValue /// Has the format: /// { /// vertices: [], /// edges: [] /// } /// NOTE: Will clear the given buffer and will leave the path in it. ////////////////////////////////////////////////////////////////////////////// aql::AqlValue pathToAqlValue(arangodb::velocypack::Builder&); ////////////////////////////////////////////////////////////////////////////// /// @brief Get the number of filtered paths ////////////////////////////////////////////////////////////////////////////// size_t getAndResetFilteredPaths() { size_t tmp = _filteredPaths; _filteredPaths = 0; return tmp; } ////////////////////////////////////////////////////////////////////////////// /// @brief Get the number of documents loaded ////////////////////////////////////////////////////////////////////////////// size_t getAndResetReadDocuments() { size_t tmp = _readDocuments; _readDocuments = 0; return tmp; } TraverserOptions const* options() { return _opts; } ManagedDocumentResult* mmdr() const { return _mmdr; } ////////////////////////////////////////////////////////////////////////////// /// @brief Simple check if there are 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. ////////////////////////////////////////////////////////////////////////////// bool hasMore() { return !_done; } bool edgeMatchesConditions(arangodb::velocypack::Slice, arangodb::velocypack::Slice, size_t, size_t); bool vertexMatchesConditions(arangodb::velocypack::Slice, size_t); void allowOptimizedNeighbors(); protected: /// @brief Outer top level transaction Transaction* _trx; ManagedDocumentResult* _mmdr; /// @brief internal cursor to enumerate the paths of a graph std::unique_ptr _enumerator; /// @brief internal getter to extract an edge std::unique_ptr _vertexGetter; /// @brief Builder for the start value slice. Leased from transaction TransactionBuilderLeaser _startIdBuilder; /// @brief counter for all read documents size_t _readDocuments; /// @brief counter for all filtered paths size_t _filteredPaths; /// @brief toggle if this path should be pruned on next step bool _pruneNext; /// @brief indicator if this traversal is done bool _done; /// @brief options for traversal TraverserOptions* _opts; bool _canUseOptimizedNeighbors; /// @brief Function to fetch the real data of a vertex into an AQLValue virtual aql::AqlValue fetchVertexData(arangodb::velocypack::Slice) = 0; /// @brief Function to fetch the real data of an edge into an AQLValue virtual aql::AqlValue fetchEdgeData(arangodb::velocypack::Slice) = 0; /// @brief Function to add the real data of a vertex into a velocypack builder virtual void addVertexToVelocyPack(arangodb::velocypack::Slice, arangodb::velocypack::Builder&) = 0; /// @brief Function to add the real data of an edge into a velocypack builder virtual void addEdgeToVelocyPack(arangodb::velocypack::Slice, arangodb::velocypack::Builder&) = 0; }; } // traverser } // arangodb #endif