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) { BOOST_AUTO_TEST_CASE (test_fullPathEnumerator) {
int startVertex = 1; int startVertex = 1;
PathEnumerator<int, int, int> it(integerEdgeEnumerator, integerVertexEnumerator, startVertex); PathEnumerator<int, int, int> it(integerEdgeEnumerator, integerVertexEnumerator, startVertex);
TraversalPath<int, int, int> path; EnumeratedPath<int, int> path;
for (int k = 1; k < 4; k++) { for (int k = 1; k < 4; k++) {
path = it.next(); path = it.next();
BOOST_CHECK_EQUAL(path.edges.size(), (size_t)1); BOOST_CHECK_EQUAL(path.edges.size(), (size_t)1);

View File

@ -47,6 +47,7 @@
using namespace triagens::aql; using namespace triagens::aql;
using Json = triagens::basics::Json; using Json = triagens::basics::Json;
using CollectionNameResolver = triagens::arango::CollectionNameResolver; using CollectionNameResolver = triagens::arango::CollectionNameResolver;
using VertexId = triagens::arango::traverser::VertexId;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief thread-local cache for compiled regexes /// @brief thread-local cache for compiled regexes
@ -2255,7 +2256,7 @@ AqlValue Functions::Neighbors (triagens::aql::Query* query,
triagens::arango::AqlTransaction* trx, triagens::arango::AqlTransaction* trx,
FunctionParameters const& parameters) { FunctionParameters const& parameters) {
size_t const n = parameters.size(); size_t const n = parameters.size();
basics::traverser::NeighborsOptions opts; triagens::arango::traverser::NeighborsOptions opts;
if (n < 4 || n > 6) { if (n < 4 || n > 6) {
THROW_ARANGO_EXCEPTION_PARAMS(TRI_ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH, "NEIGHBORS", (int) 4, (int) 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/ExecutionPlan.h"
#include "Aql/TraversalBlock.h" #include "Aql/TraversalBlock.h"
#include "Aql/ExecutionNode.h" #include "Aql/ExecutionNode.h"
#include "Utils/ShapedJsonTransformer.h"
#include "Utils/SingleCollectionReadOnlyTransaction.h"
#include <iostream> /// TODO: remove me. #include <iostream> /// TODO: remove me.
using namespace std; using namespace std;
@ -39,6 +37,8 @@ using namespace triagens::basics;
using namespace triagens::arango; using namespace triagens::arango;
using namespace triagens::aql; using namespace triagens::aql;
using VertexId = triagens::arango::traverser::VertexId;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- class TraversalBlock // --SECTION-- class TraversalBlock
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -53,29 +53,17 @@ TraversalBlock::TraversalBlock (ExecutionEngine* engine,
_edgeReg(0), _edgeReg(0),
_pathReg(0), _pathReg(0),
_condition((ep->condition()) ? ep->condition()->root(): nullptr), _condition((ep->condition()) ? ep->condition()->root(): nullptr),
_hasV8Expression(false), _hasV8Expression(false) {
_AccessP(Json::Object, 1),
_currentJsonPath(Json::Array, 10)
{
basics::traverser::TraverserOptions opts; triagens::arango::traverser::TraverserOptions opts;
ep->fillTraversalOptions(opts); ep->fillTraversalOptions(opts);
std::vector<TRI_document_collection_t*> edgeCollections; std::vector<TRI_document_collection_t*> edgeCollections;
auto cids = ep->edgeCids(); 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) { for (auto const& cid : cids) {
edgeCollections.push_back(_trx->documentCollection(cid)); 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()); _resolver = new CollectionNameResolver(_trx->vocbase());
if (!ep->usesInVariable()) { if (!ep->usesInVariable()) {
_vertexId = ep->getStartVertex(); _vertexId = ep->getStartVertex();
@ -217,105 +205,9 @@ int TraversalBlock::initializeCursor (AqlItemBlock* items,
return TRI_ERROR_NO_ERROR; 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) { bool TraversalBlock::executeExpressions (AqlValue& pathValue) {
TRI_ASSERT(_condition != nullptr); TRI_ASSERT(_condition != nullptr);
return true;
auto& toReplace = _nonConstExpressions[0]; auto& toReplace = _nonConstExpressions[0];
@ -338,7 +230,7 @@ bool TraversalBlock::executeExpressions (AqlValue& pathValue) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief read more paths /// @brief read more paths
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <iostream>
bool TraversalBlock::morePaths (size_t hint) { bool TraversalBlock::morePaths (size_t hint) {
freeCaches(); freeCaches();
_posInPaths = 0; _posInPaths = 0;
@ -349,29 +241,28 @@ bool TraversalBlock::morePaths (size_t hint) {
for (size_t j = 0; j < hint; ++j) { for (size_t j = 0; j < hint; ++j) {
auto p = _traverser->next(); auto p = _traverser->next();
if (p.edges.size() == 0) { if (p == nullptr) {
// There are no further paths available. // There are no further paths available.
break; break;
} }
_currentJsonPath.add(extractEdgeJson(p.edges.back()));
AqlValue pathValue; AqlValue pathValue;
if (usesPathOutput() || (en->condition() != NULL)) { if (usesPathOutput() || (en->condition() != nullptr)) {
pathValue = pathToAqlValue(p); pathValue = AqlValue(p->pathToJson(_trx, _resolver));
} }
if ((en->condition() != NULL) && if ((en->condition() != nullptr) &&
!executeExpressions(pathValue)) { ! executeExpressions(pathValue)) {
_traverser->prune(); _traverser->prune();
continue; continue;
} }
if ( usesVertexOutput() ) { if ( usesVertexOutput() ) {
_vertices.push_back(vertexToAqlValue(p.vertices.back())); _vertices.emplace_back(p->lastVertexToJson(_trx, _resolver));
} }
if ( usesEdgeOutput() ) { if ( usesEdgeOutput() ) {
_edges.push_back(edgeToAqlValue(p.edges.back())); _edges.emplace_back(p->lastEdgeToJson(_trx, _resolver));
} }
if ( usesPathOutput() ) { if ( usesPathOutput() ) {
_paths.push_back(pathValue); _paths.push_back(pathValue);
@ -422,7 +313,7 @@ void TraversalBlock::initializePaths (AqlItemBlock const* items) {
Json _idJson = input.get("_id"); Json _idJson = input.get("_id");
if (_idJson.isString()) { if (_idJson.isString()) {
_vertexId = JsonHelper::getStringValue(_idJson.json(), ""); _vertexId = JsonHelper::getStringValue(_idJson.json(), "");
VertexId v = triagens::basics::traverser::IdStringToVertexId ( VertexId v = triagens::arango::traverser::IdStringToVertexId (
_resolver, _resolver,
_vertexId _vertexId
); );
@ -436,7 +327,7 @@ void TraversalBlock::initializePaths (AqlItemBlock const* items) {
Json _idJson = vertexJson.get("_id"); Json _idJson = vertexJson.get("_id");
if (_idJson.isString()) { if (_idJson.isString()) {
_vertexId = JsonHelper::getStringValue(_idJson.json(), ""); _vertexId = JsonHelper::getStringValue(_idJson.json(), "");
VertexId v = triagens::basics::traverser::IdStringToVertexId ( VertexId v = triagens::arango::traverser::IdStringToVertexId (
_resolver, _resolver,
_vertexId _vertexId
); );

View File

@ -113,7 +113,7 @@ namespace triagens {
/// @brief Depth first Traverser object /// @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 /// @brief The information to get the starting point. Can either be a constant
@ -122,7 +122,7 @@ namespace triagens {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
union { union {
VertexId _startId; triagens::arango::traverser::VertexId _startId;
size_t _reg; size_t _reg;
}; };
@ -282,46 +282,6 @@ namespace triagens {
return _pathVar != nullptr; 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::aql
} // namespace triagens } // namespace triagens

View File

@ -362,7 +362,7 @@ double TraversalNode::estimateCost (size_t& nrItems) const {
return depCost + nrItems; return depCost + nrItems;
} }
void TraversalNode::fillTraversalOptions (basics::traverser::TraverserOptions& opts) const { void TraversalNode::fillTraversalOptions (triagens::arango::traverser::TraverserOptions& opts) const {
opts.direction = _direction; opts.direction = _direction;
opts.minDepth = _minDepth; opts.minDepth = _minDepth;
opts.maxDepth = _maxDepth; opts.maxDepth = _maxDepth;

View File

@ -267,7 +267,7 @@ namespace triagens {
/// with default values. /// 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 { std::vector<TRI_voc_cid_t> const edgeCids () const {
return _edgeCids; return _edgeCids;

View File

@ -32,14 +32,16 @@
#include "Utils/transactions.h" #include "Utils/transactions.h"
#include "Utils/V8ResolverGuard.h" #include "Utils/V8ResolverGuard.h"
#include "Utils/CollectionNameResolver.h" #include "Utils/CollectionNameResolver.h"
#include "Utils/ShapedJsonTransformer.h"
#include "Utils/SingleCollectionReadOnlyTransaction.h"
#include "VocBase/document-collection.h" #include "VocBase/document-collection.h"
#include "VocBase/KeyGenerator.h" #include "VocBase/KeyGenerator.h"
#include "VocBase/VocShaper.h" #include "VocBase/VocShaper.h"
using namespace std; using namespace std;
using namespace triagens::basics; using namespace triagens::basics;
using namespace triagens::basics::traverser;
using namespace triagens::arango; using namespace triagens::arango;
using namespace triagens::arango::traverser;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief extract the _from Id out of mptr, we return an RValue reference /// @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 is in use
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
VertexId triagens::basics::traverser::IdStringToVertexId ( VertexId triagens::arango::traverser::IdStringToVertexId (
CollectionNameResolver const* resolver, CollectionNameResolver const* resolver,
string const& vertex 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 // --SECTION-- class DepthFirstTraverser
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -856,10 +937,9 @@ void DepthFirstTraverser::setStartVertex (VertexId& v) {
size_t DepthFirstTraverser::skip (size_t amount) { size_t DepthFirstTraverser::skip (size_t amount) {
size_t skipped = 0; size_t skipped = 0;
TraversalPath<EdgeInfo, VertexId, TRI_doc_mptr_copy_t> p;
for (size_t i = 0; i < amount; ++i) { for (size_t i = 0; i < amount; ++i) {
p = next(); std::unique_ptr<const TraversalPath> p(next());
if (p.edges.size() == 0) { if (p == nullptr) {
break; break;
} }
++skipped; ++skipped;
@ -871,21 +951,22 @@ bool DepthFirstTraverser::hasMore () {
return !_done; return !_done;
} }
const TraversalPath<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& DepthFirstTraverser::next () { const TraversalPath* DepthFirstTraverser::next () {
TRI_ASSERT(!_done); TRI_ASSERT(!_done);
if (_pruneNext) { if (_pruneNext) {
_pruneNext = false; _pruneNext = false;
_enumerator->prune(); _enumerator->prune();
} }
TRI_ASSERT(!_pruneNext); TRI_ASSERT(!_pruneNext);
const TraversalPath<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& p = _enumerator->next(); const EnumeratedPath<EdgeInfo, VertexId>& path = _enumerator->next();
size_t countEdges = p.edges.size(); size_t countEdges = path.edges.size();
if (countEdges == 0) { if (countEdges == 0) {
_done = true; _done = true;
// Done traversing // 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(); _enumerator->prune();
return next(); return next();
} }
@ -895,7 +976,7 @@ const TraversalPath<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& DepthFirstTraverse
if (countEdges < _opts.minDepth) { if (countEdges < _opts.minDepth) {
return next(); return next();
} }
return p; return p.release();
} }
void DepthFirstTraverser::prune () { void DepthFirstTraverser::prune () {

View File

@ -35,39 +35,10 @@
#include "Utils/ExplicitTransaction.h" #include "Utils/ExplicitTransaction.h"
#include "VocBase/edge-collection.h" #include "VocBase/edge-collection.h"
#include "VocBase/ExampleMatcher.h" #include "VocBase/ExampleMatcher.h"
#include "VocBase/Traverser.h"
class VocShaper; 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 { struct EdgeInfo {
TRI_voc_cid_t cid; TRI_voc_cid_t cid;
TRI_doc_mptr_copy_t mptr; TRI_doc_mptr_copy_t mptr;
@ -78,41 +49,6 @@ struct EdgeInfo {
) : cid(pcid), mptr(pmptr) { } ) : 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. /// @brief Template for information required by vertex filter.
/// Contains transaction, barrier and the Matcher Class. /// Contains transaction, barrier and the Matcher Class.
@ -137,14 +73,17 @@ struct VertexFilterInfo {
/// @brief typedef the template instantiation of the PathFinder /// @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; ArangoDBPathFinder;
typedef triagens::basics::ConstDistanceFinder<VertexId, EdgeId> typedef triagens::basics::ConstDistanceFinder<triagens::arango::traverser::VertexId,
triagens::arango::traverser::EdgeId>
ArangoDBConstDistancePathFinder; ArangoDBConstDistancePathFinder;
namespace triagens { namespace triagens {
namespace basics { namespace arango {
namespace traverser { namespace traverser {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -189,7 +128,7 @@ namespace triagens {
TRI_voc_cid_t const& cid, TRI_voc_cid_t const& cid,
std::string& errorMessage); std::string& errorMessage);
void addEdgeFilter (Json const& example, void addEdgeFilter (triagens::basics::Json const& example,
VocShaper* shaper, VocShaper* shaper,
TRI_voc_cid_t const& cid, TRI_voc_cid_t const& cid,
triagens::arango::CollectionNameResolver const* resolver); triagens::arango::CollectionNameResolver const* resolver);
@ -262,7 +201,7 @@ namespace triagens {
struct TraverserOptions { struct TraverserOptions {
private: private:
std::function<bool (const TraversalPath<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& path)> pruningFunction; std::function<bool (const TraversalPath* path)> pruningFunction;
public: public:
TRI_edge_direction_e direction; TRI_edge_direction_e direction;
@ -282,14 +221,14 @@ namespace triagens {
{ }; { };
void setPruningFunction ( 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; pruningFunction = callback;
usesPrune = true; usesPrune = true;
} }
bool shouldPrunePath ( bool shouldPrunePath (
const TraversalPath<EdgeInfo, VertexId, TRI_doc_mptr_copy_t>& path const TraversalPath* path
) { ) {
if (!usesPrune) { if (!usesPrune) {
return false; 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 // --SECTION-- class DepthFirstTraverser
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
class DepthFirstTraverser { class DepthFirstTraverser : public Traverser {
private: private:
@ -328,7 +317,9 @@ namespace triagens {
/// @brief internal cursor to enumerate the paths of a graph /// @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 /// @brief internal function to extract an edge
@ -375,25 +366,25 @@ namespace triagens {
/// @brief Reset the traverser to use another start vertex /// @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. /// @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. /// @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. /// @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. /// @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. /// 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) { _weighter(weighter) {
} }
EdgeId extractEdgeId (TRI_doc_mptr_copy_t& ptr) { triagens::arango::traverser::EdgeId extractEdgeId (TRI_doc_mptr_copy_t& ptr) {
return EdgeId(_edgeCollectionCid, TRI_EXTRACT_MARKER_KEY(&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, 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, return TRI_LookupEdgesDocumentCollection(_edgeCollection,
direction, vertexId.cid, const_cast<char*>(vertexId.key)); direction, vertexId.cid, const_cast<char*>(vertexId.key));
} }
@ -525,13 +516,13 @@ class VertexCollectionInfo {
std::unique_ptr<ArangoDBPathFinder::Path> TRI_RunShortestPathSearch ( std::unique_ptr<ArangoDBPathFinder::Path> TRI_RunShortestPathSearch (
std::vector<EdgeCollectionInfo*>& collectionInfos, std::vector<EdgeCollectionInfo*>& collectionInfos,
triagens::basics::traverser::ShortestPathOptions& opts triagens::arango::traverser::ShortestPathOptions& opts
); );
std::unique_ptr<ArangoDBConstDistancePathFinder::Path> TRI_RunSimpleShortestPathSearch ( std::unique_ptr<ArangoDBConstDistancePathFinder::Path> TRI_RunSimpleShortestPathSearch (
std::vector<EdgeCollectionInfo*>& collectionInfos, 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, void TRI_RunNeighborsSearch (std::vector<EdgeCollectionInfo*>& collectionInfos,
triagens::basics::traverser::NeighborsOptions& opts, triagens::arango::traverser::NeighborsOptions& opts,
std::unordered_set<VertexId>& distinct); std::unordered_set<triagens::arango::traverser::VertexId>& distinct);
#endif #endif

View File

@ -73,8 +73,8 @@
using namespace std; using namespace std;
using namespace triagens::basics; using namespace triagens::basics;
using namespace triagens::basics::traverser;
using namespace triagens::arango; using namespace triagens::arango;
using namespace triagens::arango::traverser;
using namespace triagens::rest; using namespace triagens::rest;
using namespace arangodb; 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> template <typename edgeIdentifier, typename vertexIdentifier>
struct TraversalPath { struct EnumeratedPath {
std::vector<edgeIdentifier> edges; std::vector<edgeIdentifier> edges;
std::vector<vertexIdentifier> vertices; std::vector<vertexIdentifier> vertices;
TraversalPath () {} EnumeratedPath () {}
}; };
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -1262,7 +1262,7 @@ namespace triagens {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief List of the last path is used to /// @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 /// @brief The pointers returned for edge indexes on this path. Used to continue
@ -1310,11 +1310,11 @@ namespace triagens {
vertexIdentifier& startVertex vertexIdentifier& startVertex
) : _getEdge(getEdge), ) : _getEdge(getEdge),
_getVertex(getVertex) { _getVertex(getVertex) {
_traversalPath.vertices.push_back(startVertex); _enumeratedPath.vertices.push_back(startVertex);
_lastEdges.push(nullptr); _lastEdges.push(nullptr);
_lastEdgesDir.push(false); _lastEdgesDir.push(false);
_lastEdgesIdx.push(0); _lastEdgesIdx.push(0);
TRI_ASSERT(_traversalPath.vertices.size() == 1); TRI_ASSERT(_enumeratedPath.vertices.size() == 1);
TRI_ASSERT(_lastEdges.size() == 1); TRI_ASSERT(_lastEdges.size() == 1);
TRI_ASSERT(_lastEdgesDir.size() == 1); TRI_ASSERT(_lastEdgesDir.size() == 1);
}; };
@ -1329,32 +1329,32 @@ namespace triagens {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief Get the next Path element from the traversal. /// @brief Get the next Path element from the traversal.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
const TraversalPath<edgeIdentifier, vertexIdentifier, edgeItem>& next () { const EnumeratedPath<edgeIdentifier, vertexIdentifier>& next () {
if (_lastEdges.size() == 0) { if (_lastEdges.size() == 0) {
_traversalPath.edges.clear(); _enumeratedPath.edges.clear();
_traversalPath.vertices.clear(); _enumeratedPath.vertices.clear();
return _traversalPath; 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) { if (_lastEdges.top() != nullptr) {
// Could continue the path in the next depth. // Could continue the path in the next depth.
_lastEdges.push(nullptr); _lastEdges.push(nullptr);
_lastEdgesDir.push(false); _lastEdgesDir.push(false);
_lastEdgesIdx.push(0); _lastEdgesIdx.push(0);
vertexIdentifier v = _getVertex(_traversalPath.edges.back(), _traversalPath.vertices.back()); vertexIdentifier v = _getVertex(_enumeratedPath.edges.back(), _enumeratedPath.vertices.back());
_traversalPath.vertices.push_back(v); _enumeratedPath.vertices.push_back(v);
TRI_ASSERT(_traversalPath.vertices.size() == _traversalPath.edges.size() + 1); TRI_ASSERT(_enumeratedPath.vertices.size() == _enumeratedPath.edges.size() + 1);
} else { } else {
if (_traversalPath.edges.size() == 0) { if (_enumeratedPath.edges.size() == 0) {
// We are done with enumerating paths // We are done with enumerating paths
_traversalPath.edges.clear(); _enumeratedPath.edges.clear();
_traversalPath.vertices.clear(); _enumeratedPath.vertices.clear();
} else { } else {
prune(); prune();
return next(); return next();
} }
} }
return _traversalPath; return _enumeratedPath;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1366,9 +1366,9 @@ namespace triagens {
_lastEdges.pop(); _lastEdges.pop();
_lastEdgesDir.pop(); _lastEdgesDir.pop();
_lastEdgesIdx.pop(); _lastEdgesIdx.pop();
if (_traversalPath.edges.size() > 0) { if (_enumeratedPath.edges.size() > 0) {
_traversalPath.edges.pop_back(); _enumeratedPath.edges.pop_back();
_traversalPath.vertices.pop_back(); _enumeratedPath.vertices.pop_back();
} }
} }
} }