1
0
Fork 0

Included two Abstract classes for Traversals. Traverser and TraversalPath. Implemented both of them for Single-Server Traversals.

This commit is contained in:
Michael Hackstein 2015-11-12 16:25:36 +01:00
parent e18e1fa75b
commit 8d0d921ab6
11 changed files with 430 additions and 291 deletions

View File

@ -126,7 +126,7 @@ BOOST_FIXTURE_TEST_SUITE (PathEnumeratorTest, PathEnumeratorSetup)
BOOST_AUTO_TEST_CASE (test_fullPathEnumerator) {
int startVertex = 1;
PathEnumerator<int, int, int> it(integerEdgeEnumerator, integerVertexEnumerator, startVertex);
TraversalPath<int, int, int> path;
EnumeratedPath<int, int> path;
for (int k = 1; k < 4; k++) {
path = it.next();
BOOST_CHECK_EQUAL(path.edges.size(), (size_t)1);

View File

@ -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);

View File

@ -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 <iostream> /// 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<TRI_document_collection_t*> 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<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& 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 <iostream>
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
);

View File

@ -113,7 +113,7 @@ namespace triagens {
/// @brief Depth first Traverser object
////////////////////////////////////////////////////////////////////////////////
std::unique_ptr<triagens::basics::traverser::DepthFirstTraverser> _traverser;
std::unique_ptr<triagens::arango::traverser::Traverser> _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<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& p
);
};
} // namespace triagens::aql
} // namespace triagens

View File

@ -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;

View File

@ -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<TRI_voc_cid_t> const edgeCids () const {
return _edgeCids;

View File

@ -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<Json> 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<Json> 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<EdgeInfo, VertexId, TRI_doc_mptr_copy_t> p;
for (size_t i = 0; i < amount; ++i) {
p = next();
if (p.edges.size() == 0) {
std::unique_ptr<const TraversalPath> p(next());
if (p == nullptr) {
break;
}
++skipped;
@ -871,21 +951,22 @@ bool DepthFirstTraverser::hasMore () {
return !_done;
}
const TraversalPath<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& DepthFirstTraverser::next () {
const TraversalPath* DepthFirstTraverser::next () {
TRI_ASSERT(!_done);
if (_pruneNext) {
_pruneNext = false;
_enumerator->prune();
}
TRI_ASSERT(!_pruneNext);
const TraversalPath<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& p = _enumerator->next();
size_t countEdges = p.edges.size();
const EnumeratedPath<EdgeInfo, VertexId>& 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<SingleServerTraversalPath> p(new SingleServerTraversalPath(path));
if (_opts.shouldPrunePath(p.get())) {
_enumerator->prune();
return next();
}
@ -895,7 +976,7 @@ const TraversalPath<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& DepthFirstTraverse
if (countEdges < _opts.minDepth) {
return next();
}
return p;
return p.release();
}
void DepthFirstTraverser::prune () {

View File

@ -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<VertexId> {
public:
size_t operator() (VertexId const& s) const {
size_t h1 = std::hash<TRI_voc_cid_t>()(s.cid);
size_t h2 = TRI_FnvHashString(s.key);
return h1 ^ ( h2 << 1 );
}
};
template<>
struct equal_to<VertexId> {
public:
bool operator() (VertexId const& s, VertexId const& t) const {
return s.cid == t.cid && strcmp(s.key, t.key) == 0;
}
};
template<>
struct less<VertexId> {
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<VertexId, EdgeId, double>
typedef triagens::basics::PathFinder<triagens::arango::traverser::VertexId,
triagens::arango::traverser::EdgeId,
double>
ArangoDBPathFinder;
typedef triagens::basics::ConstDistanceFinder<VertexId, EdgeId>
typedef triagens::basics::ConstDistanceFinder<triagens::arango::traverser::VertexId,
triagens::arango::traverser::EdgeId>
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<bool (const TraversalPath<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& path)> pruningFunction;
std::function<bool (const TraversalPath* path)> pruningFunction;
public:
TRI_edge_direction_e direction;
@ -282,14 +221,14 @@ namespace triagens {
{ };
void setPruningFunction (
std::function<bool (const TraversalPath<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& path)> callback
std::function<bool (const TraversalPath* path)> callback
) {
pruningFunction = callback;
usesPrune = true;
}
bool shouldPrunePath (
const TraversalPath<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& 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<EdgeInfo, VertexId>& 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<EdgeInfo, VertexId> _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<PathEnumerator<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>> _enumerator;
std::unique_ptr<triagens::basics::PathEnumerator<EdgeInfo,
VertexId,
TRI_doc_mptr_copy_t>> _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<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& 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<TRI_doc_mptr_copy_t> 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<char*>(vertexId.key));
}
@ -525,13 +516,13 @@ class VertexCollectionInfo {
std::unique_ptr<ArangoDBPathFinder::Path> TRI_RunShortestPathSearch (
std::vector<EdgeCollectionInfo*>& collectionInfos,
triagens::basics::traverser::ShortestPathOptions& opts
triagens::arango::traverser::ShortestPathOptions& opts
);
std::unique_ptr<ArangoDBConstDistancePathFinder::Path> TRI_RunSimpleShortestPathSearch (
std::vector<EdgeCollectionInfo*>& collectionInfos,
triagens::basics::traverser::ShortestPathOptions& opts
triagens::arango::traverser::ShortestPathOptions& opts
);
////////////////////////////////////////////////////////////////////////////////
@ -539,7 +530,7 @@ std::unique_ptr<ArangoDBConstDistancePathFinder::Path> TRI_RunSimpleShortestPath
////////////////////////////////////////////////////////////////////////////////
void TRI_RunNeighborsSearch (std::vector<EdgeCollectionInfo*>& collectionInfos,
triagens::basics::traverser::NeighborsOptions& opts,
std::unordered_set<VertexId>& distinct);
triagens::arango::traverser::NeighborsOptions& opts,
std::unordered_set<triagens::arango::traverser::VertexId>& distinct);
#endif

View File

@ -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;

215
arangod/VocBase/Traverser.h Normal file
View File

@ -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: [<vertex-as-json>],
/// edges: [<edge-as-json>]
/// }
////////////////////////////////////////////////////////////////////////////////
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<triagens::arango::traverser::VertexId> {
public:
size_t operator() (triagens::arango::traverser::VertexId const& s) const {
size_t h1 = std::hash<TRI_voc_cid_t>()(s.cid);
size_t h2 = TRI_FnvHashString(s.key);
return h1 ^ ( h2 << 1 );
}
};
template<>
struct equal_to<triagens::arango::traverser::VertexId> {
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<triagens::arango::traverser::VertexId> {
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

View File

@ -1232,14 +1232,14 @@ namespace triagens {
};
// -----------------------------------------------------------------------------
// --SECTION-- struct TraversalPath
// --SECTION-- struct EnumeratedPath
// -----------------------------------------------------------------------------
template <typename edgeIdentifier, typename vertexIdentifier, typename edgeItem>
struct TraversalPath {
template <typename edgeIdentifier, typename vertexIdentifier>
struct EnumeratedPath {
std::vector<edgeIdentifier> edges;
std::vector<vertexIdentifier> vertices;
TraversalPath () {}
EnumeratedPath () {}
};
// -----------------------------------------------------------------------------
@ -1262,7 +1262,7 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
/// @brief List of the last path is used to
////////////////////////////////////////////////////////////////////////////////
TraversalPath<edgeIdentifier, vertexIdentifier, edgeItem> _traversalPath;
EnumeratedPath<edgeIdentifier, vertexIdentifier> _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<edgeIdentifier, vertexIdentifier, edgeItem>& next () {
const EnumeratedPath<edgeIdentifier, vertexIdentifier>& 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();
}
}
}