1
0
Fork 0

Moved some Edge Lookup logic around and moved the EdgeCursor to it's own class. This is still ongoing work. Expect shortest-path to fail.

This commit is contained in:
Michael Hackstein 2017-04-11 18:03:56 +02:00
parent 3cb9f0b805
commit c2be40b4ab
14 changed files with 172 additions and 63 deletions

View File

@ -24,6 +24,7 @@
#ifndef ARANGOD_CLUSTER_CLUSTER_EDGE_CURSOR_H
#define ARANGOD_CLUSTER_CLUSTER_EDGE_CURSOR_H 1
#include "Graph/EdgeCursor.h"
#include "VocBase/TraverserOptions.h"
namespace arangodb {
@ -32,7 +33,7 @@ namespace traverser {
class Traverser;
class ClusterEdgeCursor : public EdgeCursor {
class ClusterEdgeCursor : public graph::EdgeCursor {
public:
ClusterEdgeCursor(StringRef vid, uint64_t, ClusterTraverser*);

View File

@ -26,6 +26,7 @@
#include "Aql/AqlTransaction.h"
#include "Aql/Ast.h"
#include "Aql/Query.h"
#include "Graph/EdgeCursor.h"
#include "Utils/CollectionNameResolver.h"
#include "Transaction/Context.h"
#include "VocBase/ManagedDocumentResult.h"
@ -160,7 +161,7 @@ void BaseTraverserEngine::getEdges(VPackSlice vertex, size_t depth, VPackBuilder
// Result now contains all valid edges, probably multiples.
}
} else if (vertex.isString()) {
std::unique_ptr<arangodb::traverser::EdgeCursor> edgeCursor(_opts->nextCursor(&mmdr, StringRef(vertex), depth));
std::unique_ptr<arangodb::graph::EdgeCursor> edgeCursor(_opts->nextCursor(&mmdr, StringRef(vertex), depth));
edgeCursor->readAll([&] (StringRef const& documentId, VPackSlice edge, size_t cursorId) {
if (!_opts->evaluateEdgeExpression(edge, StringRef(vertex), depth, cursorId)) {
filtered++;

View File

@ -48,6 +48,8 @@ class Slice;
namespace graph {
class EdgeCursor;
struct BaseOptions {
protected:
struct LookupInfo {

View File

@ -23,6 +23,7 @@
#include "BreadthFirstEnumerator.h"
#include "Graph/EdgeCursor.h"
#include "VocBase/Traverser.h"
#include "VocBase/TraverserCache.h"
#include "VocBase/TraverserOptions.h"
@ -116,7 +117,7 @@ bool BreadthFirstEnumerator::next() {
auto const nextVertex = _schreier[nextIdx].vertex;
StringRef vId;
std::unique_ptr<arangodb::traverser::EdgeCursor> cursor(_opts->nextCursor(_traverser->mmdr(), nextVertex, _currentDepth));
std::unique_ptr<arangodb::graph::EdgeCursor> cursor(_opts->nextCursor(_traverser->mmdr(), nextVertex, _currentDepth));
if (cursor != nullptr) {
bool shouldReturnPath = _currentDepth + 1 >= _opts->minDepth;
bool didInsert = false;

View File

@ -0,0 +1,59 @@
////////////////////////////////////////////////////////////////////////////////
/// 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_GRAPH_EDGECURSOR_H
#define ARANGOD_GRAPH_EDGECURSOR_H 1
#include "Basics/Common.h"
namespace arangodb {
class StringRef;
namespace velocypack {
class Slice;
}
namespace graph {
/// @brief Abstract class used in the traversals
/// to abstract away access to indexes / DBServers.
/// Returns edges as VelocyPack.
class EdgeCursor {
public:
EdgeCursor() {}
virtual ~EdgeCursor() {}
virtual bool next(std::function<void(arangodb::StringRef const&,
arangodb::velocypack::Slice, size_t)>
callback) = 0;
virtual void readAll(
std::function<void(arangodb::StringRef const&,
arangodb::velocypack::Slice, size_t&)>) = 0;
};
} // namespace graph
} // namespace arangodb
#endif

View File

@ -24,6 +24,7 @@
#include "NeighborsEnumerator.h"
#include "Basics/VelocyPackHelper.h"
#include "Graph/EdgeCursor.h"
#include "VocBase/Traverser.h"
#include "VocBase/TraverserCache.h"
@ -73,7 +74,7 @@ bool NeighborsEnumerator::next() {
}
}
};
std::unique_ptr<arangodb::traverser::EdgeCursor> cursor(
std::unique_ptr<arangodb::graph::EdgeCursor> cursor(
_opts->nextCursor(_traverser->mmdr(), nextVertex, _searchDepth));
cursor->readAll(callback);
}

View File

@ -32,7 +32,6 @@ using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::graph;
ShortestPathOptions::ShortestPathOptions(transaction::Methods* trx)
: BaseOptions(trx),
direction("outbound"),
@ -100,3 +99,35 @@ double ShortestPathOptions::estimateCost(size_t& nrItems) const {
// TODO Implement me
return 0;
}
void ShortestPathOptions::addReverseLookupInfo(
aql::Ast* ast, std::string const& collectionName,
std::string const& attributeName, aql::AstNode* condition) {
injectLookupInfoInList(_reverseLookupInfos, ast, collectionName,
attributeName, condition);
}
EdgeCursor* ShortestPathOptions::nextCursor(ManagedDocumentResult* mmdr,
StringRef vid, uint64_t depth) {
if (_isCoordinator) {
return nextCursorCoordinator(vid, depth);
}
TRI_ASSERT(mmdr != nullptr);
return nextCursorLocal(mmdr, vid, depth, _baseLookupInfos);
}
EdgeCursor* ShortestPathOptions::nextCursorLocal(ManagedDocumentResult* mmdr,
StringRef vid, uint64_t depth,
std::vector<LookupInfo>&) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
EdgeCursor* ShortestPathOptions::nextCursorCoordinator(StringRef vid,
uint64_t depth) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
EdgeCursor* ShortestPathOptions::nextReverseCursorCoordinator(StringRef vid,
uint64_t depth) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}

View File

@ -84,8 +84,18 @@ struct ShortestPathOptions : public BaseOptions {
std::string const& attributeName,
aql::AstNode* condition);
private:
EdgeCursor* nextCursor(ManagedDocumentResult*, StringRef vid, uint64_t);
EdgeCursor* nextReverseCursor(ManagedDocumentResult*, StringRef vid, uint64_t);
private:
EdgeCursor* nextCursorLocal(ManagedDocumentResult*, StringRef vid, uint64_t,
std::vector<LookupInfo>&);
EdgeCursor* nextCursorCoordinator(StringRef vid, uint64_t);
EdgeCursor* nextReverseCursorCoordinator(StringRef vid, uint64_t);
private:
/// @brief Lookup info to find all reverse edges.
std::vector<LookupInfo> _reverseLookupInfos;
};

View File

@ -23,6 +23,7 @@
#include "PathEnumerator.h"
#include "Basics/VelocyPackHelper.h"
#include "Graph/EdgeCursor.h"
#include "VocBase/Traverser.h"
#include "VocBase/TraverserCache.h"
@ -31,7 +32,8 @@ using DepthFirstEnumerator = arangodb::traverser::DepthFirstEnumerator;
using Traverser = arangodb::traverser::Traverser;
using TraverserOptions = arangodb::traverser::TraverserOptions;
PathEnumerator::PathEnumerator(Traverser* traverser, std::string const& startVertex,
PathEnumerator::PathEnumerator(Traverser* traverser,
std::string const& startVertex,
TraverserOptions* opts)
: _traverser(traverser), _isFirst(true), _opts(opts) {
StringRef svId = _opts->cache()->persistString(StringRef(startVertex));
@ -40,6 +42,13 @@ PathEnumerator::PathEnumerator(Traverser* traverser, std::string const& startVer
TRI_ASSERT(_enumeratedPath.vertices.size() == 1);
}
DepthFirstEnumerator::DepthFirstEnumerator(Traverser* traverser,
std::string const& startVertex,
TraverserOptions* opts)
: PathEnumerator(traverser, startVertex, opts) {}
DepthFirstEnumerator::~DepthFirstEnumerator() {}
bool DepthFirstEnumerator::next() {
if (_isFirst) {
_isFirst = false;
@ -56,8 +65,9 @@ bool DepthFirstEnumerator::next() {
if (_enumeratedPath.edges.size() < _opts->maxDepth) {
// We are not done with this path, so
// we reserve the cursor for next depth
auto cursor = _opts->nextCursor(_traverser->mmdr(), StringRef(_enumeratedPath.vertices.back()),
_enumeratedPath.edges.size());
auto cursor = _opts->nextCursor(
_traverser->mmdr(), StringRef(_enumeratedPath.vertices.back()),
_enumeratedPath.edges.size());
if (cursor != nullptr) {
_edgeCursors.emplace(cursor);
}
@ -72,14 +82,16 @@ bool DepthFirstEnumerator::next() {
while (!_edgeCursors.empty()) {
TRI_ASSERT(_edgeCursors.size() == _enumeratedPath.edges.size() + 1);
auto& cursor = _edgeCursors.top();
bool foundPath = false;
bool exitInnerLoop = false;
auto callback = [&] (StringRef const& eid, VPackSlice const& edge, size_t cursorId) {
auto callback = [&](StringRef const& eid, VPackSlice const& edge,
size_t cursorId) {
++_traverser->_readDocuments;
_enumeratedPath.edges.push_back(eid);
_opts->cache()->insertDocument(StringRef(eid), edge); // TODO handle in cursor directly?
_opts->cache()->insertDocument(
StringRef(eid), edge); // TODO handle in cursor directly?
if (_opts->uniqueEdges == TraverserOptions::UniquenessLevel::GLOBAL) {
if (_returnedEdges.find(eid) == _returnedEdges.end()) {
// Edge not yet visited. Mark and continue.
@ -91,22 +103,22 @@ bool DepthFirstEnumerator::next() {
return;
}
}
if (!_traverser->edgeMatchesConditions(edge,
StringRef(_enumeratedPath.vertices.back()),
_enumeratedPath.edges.size() - 1,
cursorId)) {
if (!_traverser->edgeMatchesConditions(
edge, StringRef(_enumeratedPath.vertices.back()),
_enumeratedPath.edges.size() - 1, cursorId)) {
// This edge does not pass the filtering
TRI_ASSERT(!_enumeratedPath.edges.empty());
_enumeratedPath.edges.pop_back();
return;
}
if (_opts->uniqueEdges == TraverserOptions::UniquenessLevel::PATH) {
StringRef const& e = _enumeratedPath.edges.back();
bool foundOnce = false;
for (StringRef const& it : _enumeratedPath.edges) {
if (foundOnce) {
foundOnce = false; // if we leave with foundOnce == false we found the edge earlier
foundOnce = false; // if we leave with foundOnce == false we
// found the edge earlier
break;
}
if (it == e) {
@ -121,11 +133,12 @@ bool DepthFirstEnumerator::next() {
return;
}
}
// We have to check if edge and vertex is valid
if (_traverser->getVertex(edge, _enumeratedPath.vertices)) {
// case both are valid.
if (_opts->uniqueVertices == TraverserOptions::UniquenessLevel::PATH) {
if (_opts->uniqueVertices ==
TraverserOptions::UniquenessLevel::PATH) {
auto& e = _enumeratedPath.vertices.back();
bool foundOnce = false;
for (auto const& it : _enumeratedPath.vertices) {
@ -152,7 +165,7 @@ bool DepthFirstEnumerator::next() {
exitInnerLoop = true;
return;
}
foundPath = true;
return;
}
@ -163,7 +176,7 @@ bool DepthFirstEnumerator::next() {
if (cursor->next(callback)) {
if (foundPath) {
return true;
} else if(exitInnerLoop) {
} else if (exitInnerLoop) {
break;
}
} else {
@ -174,28 +187,31 @@ bool DepthFirstEnumerator::next() {
_enumeratedPath.vertices.pop_back();
}
}
}// while (!_edgeCursors.empty())
} // while (!_edgeCursors.empty())
if (_edgeCursors.empty()) {
// If we get here all cursors are exhausted.
_enumeratedPath.edges.clear();
_enumeratedPath.vertices.clear();
return false;
}
}// while (true)
} // while (true)
}
arangodb::aql::AqlValue DepthFirstEnumerator::lastVertexToAqlValue() {
return _traverser->fetchVertexData(StringRef(_enumeratedPath.vertices.back()));
return _traverser->fetchVertexData(
StringRef(_enumeratedPath.vertices.back()));
}
arangodb::aql::AqlValue DepthFirstEnumerator::lastEdgeToAqlValue() {
if (_enumeratedPath.edges.empty()) {
return arangodb::aql::AqlValue(arangodb::basics::VelocyPackHelper::NullValue());
return arangodb::aql::AqlValue(
arangodb::basics::VelocyPackHelper::NullValue());
}
return _traverser->fetchEdgeData(StringRef(_enumeratedPath.edges.back()));
}
arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(arangodb::velocypack::Builder& result) {
arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(
arangodb::velocypack::Builder& result) {
result.clear();
result.openObject();
result.add(VPackValue("edges"));

View File

@ -39,6 +39,10 @@ namespace velocypack {
class Builder;
}
namespace graph {
class EdgeCursor;
}
namespace traverser {
class Traverser;
struct TraverserOptions;
@ -49,7 +53,6 @@ struct EnumeratedPath {
EnumeratedPath() {}
};
class PathEnumerator {
protected:
@ -109,16 +112,14 @@ class DepthFirstEnumerator final : public PathEnumerator {
/// @brief The stack of EdgeCursors to walk through.
//////////////////////////////////////////////////////////////////////////////
std::stack<std::unique_ptr<EdgeCursor>> _edgeCursors;
std::stack<std::unique_ptr<graph::EdgeCursor>> _edgeCursors;
public:
DepthFirstEnumerator(Traverser* traverser,
std::string const& startVertex,
TraverserOptions* opts)
: PathEnumerator(traverser, startVertex, opts) {}
TraverserOptions* opts);
~DepthFirstEnumerator() {
}
~DepthFirstEnumerator();
//////////////////////////////////////////////////////////////////////////////
/// @brief Get the next Path element from the traversal.

View File

@ -44,7 +44,7 @@ using namespace arangodb::graph;
////////////////////////////////////////////////////////////////////////////////
SingleServerEdgeCursor::SingleServerEdgeCursor(ManagedDocumentResult* mmdr,
TraverserOptions* opts,
BaseOptions* opts,
size_t nrCursors, std::vector<size_t> const* mapping)
: _opts(opts),
_trx(opts->trx()),

View File

@ -25,9 +25,9 @@
#define ARANGOD_SINGLE_SERVER_TRAVERSER_H 1
#include "Aql/AqlValue.h"
#include "Graph/EdgeCursor.h"
#include "Utils/OperationCursor.h"
#include "VocBase/Traverser.h"
#include "VocBase/TraverserOptions.h"
#include "VocBase/voc-types.h"
namespace arangodb {
@ -35,13 +35,17 @@ namespace arangodb {
class LogicalCollection;
class ManagedDocumentResult;
namespace graph {
class BaseOptions;
}
namespace traverser {
class PathEnumerator;
class SingleServerEdgeCursor : public EdgeCursor {
class SingleServerEdgeCursor : public graph::EdgeCursor {
private:
TraverserOptions* _opts;
graph::BaseOptions* _opts;
transaction::Methods* _trx;
ManagedDocumentResult* _mmdr;
std::vector<std::vector<OperationCursor*>> _cursors;
@ -52,7 +56,7 @@ class SingleServerEdgeCursor : public EdgeCursor {
std::vector<size_t> const* _internalCursorMapping;
public:
SingleServerEdgeCursor(ManagedDocumentResult* mmdr, TraverserOptions* options, size_t, std::vector<size_t> const* mapping = nullptr);
SingleServerEdgeCursor(ManagedDocumentResult* mmdr, graph::BaseOptions* options, size_t, std::vector<size_t> const* mapping = nullptr);
~SingleServerEdgeCursor() {
for (auto& it : _cursors) {

View File

@ -507,7 +507,7 @@ bool arangodb::traverser::TraverserOptions::evaluateVertexExpression(
return evaluateExpression(expression, vertex);
}
arangodb::traverser::EdgeCursor*
EdgeCursor*
arangodb::traverser::TraverserOptions::nextCursor(ManagedDocumentResult* mmdr,
StringRef vid,
uint64_t depth) {
@ -525,7 +525,7 @@ arangodb::traverser::TraverserOptions::nextCursor(ManagedDocumentResult* mmdr,
return nextCursorLocal(mmdr, vid, depth, list);
}
arangodb::traverser::EdgeCursor*
EdgeCursor*
arangodb::traverser::TraverserOptions::nextCursorLocal(
ManagedDocumentResult* mmdr, StringRef vid, uint64_t depth,
std::vector<LookupInfo>& list) {
@ -558,7 +558,7 @@ arangodb::traverser::TraverserOptions::nextCursorLocal(
return allCursor.release();
}
arangodb::traverser::EdgeCursor*
EdgeCursor*
arangodb::traverser::TraverserOptions::nextCursorCoordinator(StringRef vid,
uint64_t depth) {
TRI_ASSERT(_traverser != nullptr);

View File

@ -51,24 +51,6 @@ namespace traverser {
class ClusterTraverser;
class TraverserCache;
/// @brief Abstract class used in the traversals
/// to abstract away access to indexes / DBServers.
/// Returns edges as VelocyPack.
class EdgeCursor {
public:
EdgeCursor() {}
virtual ~EdgeCursor() {}
virtual bool next(
std::function<void(arangodb::StringRef const&, VPackSlice, size_t)>
callback) = 0;
virtual void readAll(
std::function<void(arangodb::StringRef const&,
arangodb::velocypack::Slice, size_t&)>) = 0;
};
struct TraverserOptions : public graph::BaseOptions {
friend class arangodb::aql::TraversalNode;
@ -127,17 +109,17 @@ struct TraverserOptions : public graph::BaseOptions {
bool evaluateVertexExpression(arangodb::velocypack::Slice, uint64_t) const;
EdgeCursor* nextCursor(ManagedDocumentResult*, StringRef vid, uint64_t);
graph::EdgeCursor* nextCursor(ManagedDocumentResult*, StringRef vid, uint64_t);
void linkTraverser(arangodb::traverser::ClusterTraverser*);
double estimateCost(size_t& nrItems) const;
private:
EdgeCursor* nextCursorLocal(ManagedDocumentResult*, StringRef vid, uint64_t,
graph::EdgeCursor* nextCursorLocal(ManagedDocumentResult*, StringRef vid, uint64_t,
std::vector<LookupInfo>&);
EdgeCursor* nextCursorCoordinator(StringRef vid, uint64_t);
graph::EdgeCursor* nextCursorCoordinator(StringRef vid, uint64_t);
};
}
}