1
0
Fork 0

Intermediate State: Moved Traversals to use Slices above Strings to compare. Also Preperation to use different indexes. This state compiles but is not functional.

This commit is contained in:
Michael Hackstein 2016-07-19 10:54:37 +02:00
parent 5b1e1b7496
commit aa1dc2a083
9 changed files with 443 additions and 390 deletions

View File

@ -632,6 +632,7 @@ void TraversalNode::fillTraversalOptions(
EdgeConditionBuilder globalEdgeConditionBuilder(this); EdgeConditionBuilder globalEdgeConditionBuilder(this);
opts._baseIndexHandles.reserve(numEdgeColls); opts._baseIndexHandles.reserve(numEdgeColls);
opts._baseConditions.reserve(numEdgeColls);
// Compute Edge Indexes. First default indexes: // Compute Edge Indexes. First default indexes:
for (size_t i = 0; i < numEdgeColls; ++i) { for (size_t i = 0; i < numEdgeColls; ++i) {
auto dir = _directions[i]; auto dir = _directions[i];
@ -649,6 +650,7 @@ void TraversalNode::fillTraversalOptions(
opts._baseIndexHandles); opts._baseIndexHandles);
TRI_ASSERT(res); // Right now we have an enforced edge index which wil TRI_ASSERT(res); // Right now we have an enforced edge index which wil
// always fit. // always fit.
opts._baseConditions.emplace_back(condition->clone(_ast));
condition = globalEdgeConditionBuilder.getOutboundCondition(); condition = globalEdgeConditionBuilder.getOutboundCondition();
break; break;
} }
@ -657,15 +659,19 @@ void TraversalNode::fillTraversalOptions(
_edgeColls[i], condition, _tmpObjVariable, &sort, 1000, _edgeColls[i], condition, _tmpObjVariable, &sort, 1000,
opts._baseIndexHandles); opts._baseIndexHandles);
TRI_ASSERT(res); // We have an enforced edge index which wil always fit. TRI_ASSERT(res); // We have an enforced edge index which wil always fit.
opts._baseConditions.emplace_back(condition->clone(_ast));
} }
for (std::pair<size_t, EdgeConditionBuilder> it : _edgeConditions) { for (std::pair<size_t, EdgeConditionBuilder> it : _edgeConditions) {
auto ins = opts._depthIndexHandles.emplace( auto ins = opts._depthIndexHandles.emplace(
it.first, std::vector<Transaction::IndexHandle>()); it.first, std::make_pair(std::vector<Transaction::IndexHandle>(),
std::vector<AstNode const*>()));
TRI_ASSERT(ins.second); TRI_ASSERT(ins.second);
auto& idxList = ins.first->second; auto& idxList = ins.first->second.first;
auto& condList = ins.first->second.second;
idxList.reserve(numEdgeColls); idxList.reserve(numEdgeColls);
condList.reserve(numEdgeColls);
// Compute Edge Indexes. First default indexes: // Compute Edge Indexes. First default indexes:
for (size_t i = 0; i < numEdgeColls; ++i) { for (size_t i = 0; i < numEdgeColls; ++i) {
auto dir = _directions[i]; auto dir = _directions[i];
@ -682,6 +688,7 @@ void TraversalNode::fillTraversalOptions(
_edgeColls[i], condition, _tmpObjVariable, &sort, 1000, idxList); _edgeColls[i], condition, _tmpObjVariable, &sort, 1000, idxList);
TRI_ASSERT(res); // Right now we have an enforced edge index which wil TRI_ASSERT(res); // Right now we have an enforced edge index which wil
// always fit. // always fit.
condList.emplace_back(condition);
condition = it.second.getOutboundCondition(); condition = it.second.getOutboundCondition();
break; break;
} }
@ -689,32 +696,10 @@ void TraversalNode::fillTraversalOptions(
res = trx->getBestIndexHandleForFilterCondition( res = trx->getBestIndexHandleForFilterCondition(
_edgeColls[i], condition, _tmpObjVariable, &sort, 1000, idxList); _edgeColls[i], condition, _tmpObjVariable, &sort, 1000, idxList);
TRI_ASSERT(res); // We have an enforced edge index which wil always fit. TRI_ASSERT(res); // We have an enforced edge index which wil always fit.
condList.emplace_back(condition);
} }
} }
VPackBuilder ulf;
ulf.openObject();
ulf.add(VPackValue("base"));
ulf.openArray();
for (auto const& idx : opts._baseIndexHandles) {
ulf.openObject();
idx.toVelocyPack(ulf, false);
ulf.close();
}
ulf.close();
for (auto const& it : opts._depthIndexHandles) {
ulf.add(VPackValue(std::to_string(it.first)));
ulf.openArray();
for (auto const& idx : it.second) {
ulf.openObject();
idx.toVelocyPack(ulf, false);
ulf.close();
}
ulf.close();
}
ulf.close();
LOG(ERR) << ulf.toJson();
opts.useBreadthFirst = _options.useBreadthFirst; opts.useBreadthFirst = _options.useBreadthFirst;
opts.uniqueVertices = _options.uniqueVertices; opts.uniqueVertices = _options.uniqueVertices;
opts.uniqueEdges = _options.uniqueEdges; opts.uniqueEdges = _options.uniqueEdges;

View File

@ -32,68 +32,103 @@ using namespace arangodb;
using ClusterTraverser = arangodb::traverser::ClusterTraverser; using ClusterTraverser = arangodb::traverser::ClusterTraverser;
bool ClusterTraverser::VertexGetter::getVertex(std::string const& edgeId, bool ClusterTraverser::VertexGetter::getVertex(
std::string const& vertexId, VPackSlice edge, std::vector<VPackSlice>& result) {
size_t depth, VPackSlice cmp = result.back();
std::string& result) { VPackSlice from = edge.get(StaticStrings::FromString);
auto it = _traverser->_edges.find(edgeId);
if (it != _traverser->_edges.end()) {
VPackSlice slice(it->second->data());
std::string from = slice.get(StaticStrings::FromString).copyString();
if (from != vertexId) {
result = std::move(from);
} else {
std::string to = slice.get(StaticStrings::ToString).copyString();
result = std::move(to);
}
#warning Here we have to execute VertexFilter #warning Here we have to execute VertexFilter
/// If the vertex is not cached in _traverser->_vertices => incr. _filteredPath return false; /// If the vertex is not cached in _traverser->_vertices => incr. _filteredPath return false;
/// Else check condition if ok => return true, else return false. /// Else check condition if ok => return true, else return false.
/// When returning false set result = "" /// When returning false set result = ""
if (arangodb::basics::VelocyPackHelper::compare(cmp, from, false) != 0) {
result.emplace_back(from);
} else {
result.emplace_back(edge.get(StaticStrings::ToString));
} }
// This should never be reached return true;
result = "";
return false;
} }
bool ClusterTraverser::VertexGetter::getSingleVertex(VPackSlice edge,
VPackSlice cmp,
size_t depth,
VPackSlice& result) {
VPackSlice from = edge.get(StaticStrings::FromString);
#warning Here we have to execute VertexFilter
/// If the vertex is not cached in _traverser->_vertices => incr. _filteredPath return false;
/// Else check condition if ok => return true, else return false.
/// When returning false set result = ""
if (arangodb::basics::VelocyPackHelper::compare(cmp, from, false) != 0) {
result = from;
} else {
result = edge.get(StaticStrings::ToString);
}
return true;
}
void ClusterTraverser::VertexGetter::reset() { void ClusterTraverser::VertexGetter::reset() {
// Nothing to do here. Subclass has to clear list of already returned vertices. // Nothing to do here. Subclass has to clear list of already returned vertices.
} }
bool ClusterTraverser::UniqueVertexGetter::getVertex( bool ClusterTraverser::UniqueVertexGetter::getVertex(
std::string const& edgeId, std::string const& vertexId, size_t depth, VPackSlice edge, std::vector<VPackSlice>& result) {
std::string& result) { VPackSlice toAdd = edge.get(StaticStrings::FromString);
VPackSlice cmp = result.back();
auto it = _traverser->_edges.find(edgeId);
if (it != _traverser->_edges.end()) {
VPackSlice slice(it->second->data());
std::string from = slice.get(StaticStrings::FromString).copyString();
if (from != vertexId) {
result = std::move(from);
} else {
std::string to = slice.get(StaticStrings::ToString).copyString();
result = std::move(to);
}
if (_returnedVertices.find(result) != _returnedVertices.end()) {
// This vertex is not unique.
++_traverser->_filteredPaths;
result = "";
return false;
}
if (arangodb::basics::VelocyPackHelper::compare(toAdd, cmp, false) == 0) {
toAdd = edge.get(StaticStrings::ToString);
}
#warning Here we have to execute VertexFilter #warning Here we have to execute VertexFilter
/// If the vertex is not cached in _traverser->_vertices => incr. _filteredPath return false; /// If the vertex is not cached in _traverser->_vertices => incr. _filteredPath return false;
/// Else check condition if ok => return true, else return false. /// Else check condition if ok => return true, else return false.
/// When returning false set result = "" /// When returning false set result = ""
/// When returning true: _returnedVertices.emplace(result) /// When returning true: _returnedVertices.emplace(result)
if (_returnedVertices.find(toAdd) != _returnedVertices.end()) {
// This vertex is not unique.
++_traverser->_filteredPaths;
return false;
} else {
_returnedVertices.emplace(toAdd);
result.emplace_back(toAdd);
} }
// This should never be reached // This should never be reached
result = "";
return false; return false;
} }
bool ClusterTraverser::UniqueVertexGetter::getSingleVertex(
VPackSlice edge, VPackSlice cmp, size_t depth, VPackSlice& result) {
result = edge.get(StaticStrings::FromString);
if (arangodb::basics::VelocyPackHelper::compare(result, cmp, false) == 0) {
result = edge.get(StaticStrings::ToString);
}
#warning Here we have to execute VertexFilter
/// If the vertex is not cached in _traverser->_vertices => incr. _filteredPath return false;
/// Else check condition if ok => return true, else return false.
/// When returning false set result = ""
/// When returning true: _returnedVertices.emplace(result)
if (_returnedVertices.find(result) != _returnedVertices.end()) {
// This vertex is not unique.
++_traverser->_filteredPaths;
return false;
} else {
_returnedVertices.emplace(result);
return true;
}
// This should never be reached
return false;
}
void ClusterTraverser::UniqueVertexGetter::reset() { void ClusterTraverser::UniqueVertexGetter::reset() {
_returnedVertices.clear(); _returnedVertices.clear();
} }
@ -228,7 +263,7 @@ void ClusterTraverser::ClusterEdgeGetter::getEdge(
} }
void ClusterTraverser::ClusterEdgeGetter::getAllEdges( void ClusterTraverser::ClusterEdgeGetter::getAllEdges(
std::string const& startVertex, std::unordered_set<std::string>& result, VPackSlice startVertex, std::unordered_set<VPackSlice>& result,
size_t depth) { size_t depth) {
std::string collName; std::string collName;
TRI_edge_direction_e dir; TRI_edge_direction_e dir;
@ -300,16 +335,14 @@ void ClusterTraverser::ClusterEdgeGetter::getAllEdges(
void ClusterTraverser::setStartVertex(std::string const& id) { void ClusterTraverser::setStartVertex(std::string const& id) {
_vertexGetter->reset(); _vertexGetter->reset();
if (_opts.useBreadthFirst) {
_enumerator.reset(
new arangodb::traverser::BreadthFirstEnumerator(this, id, &_opts));
_vertexGetter->setStartVertex(id);
} else {
_enumerator.reset(
new arangodb::traverser::DepthFirstEnumerator(this, id, &_opts));
}
_done = false; _done = false;
auto it = _vertices.find(id); #warning Arraaghghh Who is responsible for the Builder and Slice?
VPackBuilder tmp;
tmp.add(VPackValue(id));
VPackSlice idSlice = tmp.slice();
auto it = _vertices.find(idSlice);
if (it == _vertices.end()) { if (it == _vertices.end()) {
size_t firstSlash = id.find("/"); size_t firstSlash = id.find("/");
if (firstSlash == std::string::npos || if (firstSlash == std::string::npos ||
@ -322,7 +355,7 @@ void ClusterTraverser::setStartVertex(std::string const& id) {
std::unordered_set<std::string> vertexToFetch; std::unordered_set<std::string> vertexToFetch;
vertexToFetch.emplace(id); vertexToFetch.emplace(id);
fetchVertices(vertexToFetch, 0); // this inserts the vertex fetchVertices(vertexToFetch, 0); // this inserts the vertex
it = _vertices.find(id); it = _vertices.find(idSlice);
if (it == _vertices.end()) { if (it == _vertices.end()) {
// We can stop here. The start vertex does not match condition. // We can stop here. The start vertex does not match condition.
++_filteredPaths; ++_filteredPaths;
@ -334,6 +367,16 @@ void ClusterTraverser::setStartVertex(std::string const& id) {
if (_opts.evaluateVertexExpression(VPackSlice(it->second->data()), 0)) { if (_opts.evaluateVertexExpression(VPackSlice(it->second->data()), 0)) {
// We can stop here. The start vertex does not match condition // We can stop here. The start vertex does not match condition
_done = true; _done = true;
return;
}
VPackSlice startId(it->second->data());
if (_opts.useBreadthFirst) {
_enumerator.reset(
new arangodb::traverser::BreadthFirstEnumerator(this, startId, &_opts));
_vertexGetter->setStartVertex(startId);
} else {
_enumerator.reset(
new arangodb::traverser::DepthFirstEnumerator(this, startId, &_opts));
} }
} }
@ -344,17 +387,22 @@ void ClusterTraverser::getEdge(std::string const& startVertex,
} }
void ClusterTraverser::getAllEdges( void ClusterTraverser::getAllEdges(
std::string const& startVertex, std::unordered_set<std::string>& result, VPackSlice startVertex, std::unordered_set<VPackSlice>& result,
size_t depth) { size_t depth) {
return _edgeGetter->getAllEdges(startVertex, result, depth); return _edgeGetter->getAllEdges(startVertex, result, depth);
} }
bool ClusterTraverser::getVertex(std::string const& edgeId, bool ClusterTraverser::getVertex(VPackSlice edge,
std::string const& vertexId, size_t depth, std::vector<VPackSlice>& result) {
std::string& result) { return _vertexGetter->getVertex(edge, result);
return _vertexGetter->getVertex(edgeId, vertexId, depth, result);
} }
bool ClusterTraverser::getSingleVertex(VPackSlice edge, VPackSlice comp,
size_t depth, VPackSlice& result) {
return _vertexGetter->getSingleVertex(edge, comp, depth, result);
}
void ClusterTraverser::fetchVertices(std::unordered_set<std::string>& verticesToFetch, size_t depth) { void ClusterTraverser::fetchVertices(std::unordered_set<std::string>& verticesToFetch, size_t depth) {
_readDocuments += verticesToFetch.size(); _readDocuments += verticesToFetch.size();
@ -400,11 +448,6 @@ bool ClusterTraverser::vertexMatchesCondition(
bool ClusterTraverser::next() { bool ClusterTraverser::next() {
TRI_ASSERT(!_done); TRI_ASSERT(!_done);
if (_pruneNext) {
_pruneNext = false;
_enumerator->prune();
}
TRI_ASSERT(!_pruneNext);
return _enumerator->next(); return _enumerator->next();
/* /*
if (_opts.useBreadthFirst && if (_opts.useBreadthFirst &&
@ -430,26 +473,25 @@ bool ClusterTraverser::next() {
*/ */
} }
aql::AqlValue ClusterTraverser::fetchVertexData(std::string const& id) { aql::AqlValue ClusterTraverser::fetchVertexData(VPackSlice idString) {
auto cached = _vertices.find(id); TRI_ASSERT(idString.isString());
auto cached = _vertices.find(idString);
// All vertices are cached!! // All vertices are cached!!
TRI_ASSERT(cached != _vertices.end()); TRI_ASSERT(cached != _vertices.end());
return aql::AqlValue((*cached).second->data()); return aql::AqlValue((*cached).second->data());
} }
aql::AqlValue ClusterTraverser::fetchEdgeData(std::string const& id) { aql::AqlValue ClusterTraverser::fetchEdgeData(VPackSlice edge) {
auto cached = _edges.find(id); return aql::AqlValue(edge);
// All edges are cached!!
TRI_ASSERT(cached != _edges.end());
return aql::AqlValue((*cached).second->data());
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Function to add the real data of a vertex into a velocypack builder /// @brief Function to add the real data of a vertex into a velocypack builder
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void ClusterTraverser::addVertexToVelocyPack(std::string const& id, void ClusterTraverser::addVertexToVelocyPack(VPackSlice id,
arangodb::velocypack::Builder& result) { VPackBuilder& result) {
TRI_ASSERT(id.isString());
auto cached = _vertices.find(id); auto cached = _vertices.find(id);
// All vertices are cached!! // All vertices are cached!!
TRI_ASSERT(cached != _vertices.end()); TRI_ASSERT(cached != _vertices.end());
@ -460,12 +502,9 @@ void ClusterTraverser::addVertexToVelocyPack(std::string const& id,
/// @brief Function to add the real data of an edge into a velocypack builder /// @brief Function to add the real data of an edge into a velocypack builder
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void ClusterTraverser::addEdgeToVelocyPack(std::string const& id, void ClusterTraverser::addEdgeToVelocyPack(arangodb::velocypack::Slice edge,
arangodb::velocypack::Builder& result) { arangodb::velocypack::Builder& result) {
auto cached = _edges.find(id); result.add(edge);
// All edges are cached!!
TRI_ASSERT(cached != _edges.end());
result.add(VPackSlice((*cached).second->data()));
} }
aql::AqlValue ClusterTraverser::lastVertexToAqlValue() { aql::AqlValue ClusterTraverser::lastVertexToAqlValue() {

View File

@ -56,7 +56,7 @@ class ClusterTraverser final : public Traverser {
~ClusterTraverser() { ~ClusterTraverser() {
} }
void setStartVertex(std::string const&) override; void setStartVertex(std::string const& id) override;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Function to load edges for a node /// @brief Function to load edges for a node
@ -69,16 +69,22 @@ class ClusterTraverser final : public Traverser {
/// @brief Function to load all edges for a list of nodes /// @brief Function to load all edges for a list of nodes
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void getAllEdges(std::string const&, std::unordered_set<std::string>&, void getAllEdges(arangodb::velocypack::Slice,
std::unordered_set<arangodb::velocypack::Slice>&,
size_t) override; size_t) override;
//////////////////////////////////////////////////////////////////////////////
/// @brief Function to load the other sides vertex of an edge /// @brief Function to load the other sides vertex of an edge
/// Returns true if the vertex passes filtering conditions /// Returns true if the vertex passes filtering conditions
////////////////////////////////////////////////////////////////////////////// /// Also apppends the _id value of the vertex in the given vector
bool getVertex(std::string const&, std::string const&, size_t, bool getVertex(arangodb::velocypack::Slice,
std::string&) override; std::vector<arangodb::velocypack::Slice>&) override;
/// @brief Function to load the other sides vertex of an edge
/// Returns true if the vertex passes filtering conditions
bool getSingleVertex(arangodb::velocypack::Slice, arangodb::velocypack::Slice,
size_t, arangodb::velocypack::Slice&) override;
bool next() override; bool next() override;
@ -111,26 +117,26 @@ class ClusterTraverser final : public Traverser {
/// @brief Function to fetch the real data of a vertex into an AQLValue /// @brief Function to fetch the real data of a vertex into an AQLValue
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
aql::AqlValue fetchVertexData(std::string const&) override; aql::AqlValue fetchVertexData(arangodb::velocypack::Slice) override;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Function to fetch the real data of an edge into an AQLValue /// @brief Function to fetch the real data of an edge into an AQLValue
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
aql::AqlValue fetchEdgeData(std::string const&) override; aql::AqlValue fetchEdgeData(arangodb::velocypack::Slice) override;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Function to add the real data of a vertex into a velocypack builder /// @brief Function to add the real data of a vertex into a velocypack builder
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void addVertexToVelocyPack(std::string const&, void addVertexToVelocyPack(arangodb::velocypack::Slice,
arangodb::velocypack::Builder&) override; arangodb::velocypack::Builder&) override;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Function to add the real data of an edge into a velocypack builder /// @brief Function to add the real data of an edge into a velocypack builder
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void addEdgeToVelocyPack(std::string const&, void addEdgeToVelocyPack(arangodb::velocypack::Slice,
arangodb::velocypack::Builder&) override; arangodb::velocypack::Builder&) override;
private: private:
@ -147,11 +153,15 @@ class ClusterTraverser final : public Traverser {
virtual ~VertexGetter() = default; virtual ~VertexGetter() = default;
virtual bool getVertex(std::string const&, std::string const&, size_t, virtual bool getVertex(arangodb::velocypack::Slice,
std::string&); std::vector<arangodb::velocypack::Slice>&);
virtual bool getSingleVertex(arangodb::velocypack::Slice,
arangodb::velocypack::Slice, size_t,
arangodb::velocypack::Slice&);
virtual void reset(); virtual void reset();
virtual void setStartVertex(std::string const&) {} virtual void setStartVertex(arangodb::velocypack::Slice) {}
protected: protected:
ClusterTraverser* _traverser; ClusterTraverser* _traverser;
@ -164,17 +174,21 @@ class ClusterTraverser final : public Traverser {
~UniqueVertexGetter() = default; ~UniqueVertexGetter() = default;
bool getVertex(std::string const&, std::string const&, size_t, bool getVertex(arangodb::velocypack::Slice,
std::string&) override; std::vector<arangodb::velocypack::Slice>&) override;
bool getSingleVertex(arangodb::velocypack::Slice,
arangodb::velocypack::Slice, size_t,
arangodb::velocypack::Slice&) override;
void reset() override; void reset() override;
void setStartVertex(std::string const& id) override { void setStartVertex(arangodb::velocypack::Slice id) override {
_returnedVertices.emplace(id); _returnedVertices.emplace(id);
} }
private: private:
std::unordered_set<std::string> _returnedVertices; std::unordered_set<arangodb::velocypack::Slice> _returnedVertices;
}; };
class ClusterEdgeGetter { class ClusterEdgeGetter {
@ -185,7 +199,9 @@ class ClusterTraverser final : public Traverser {
void getEdge(std::string const&, std::vector<std::string>&, size_t*&, void getEdge(std::string const&, std::vector<std::string>&, size_t*&,
size_t&); size_t&);
void getAllEdges(std::string const&, std::unordered_set<std::string>&, size_t depth); void getAllEdges(arangodb::velocypack::Slice,
std::unordered_set<arangodb::velocypack::Slice>&,
size_t depth);
private: private:
ClusterTraverser* _traverser; ClusterTraverser* _traverser;
@ -197,7 +213,7 @@ class ClusterTraverser final : public Traverser {
std::shared_ptr<arangodb::velocypack::Buffer<uint8_t>>> std::shared_ptr<arangodb::velocypack::Buffer<uint8_t>>>
_edges; _edges;
std::unordered_map<std::string, std::unordered_map<arangodb::velocypack::Slice,
std::shared_ptr<arangodb::velocypack::Buffer<uint8_t>>> std::shared_ptr<arangodb::velocypack::Buffer<uint8_t>>>
_vertices; _vertices;

View File

@ -32,78 +32,53 @@ using TraverserOptions = arangodb::traverser::TraverserOptions;
bool DepthFirstEnumerator::next() { bool DepthFirstEnumerator::next() {
if (_isFirst) { if (_isFirst) {
_isFirst = false; _isFirst = false;
// Initialze the first cursor
_opts->nextCursor(_enumeratedPath.vertices.back(), 0);
if (_opts->minDepth == 0) { if (_opts->minDepth == 0) {
return true; return true;
} }
} }
if (_enumeratedPath.edges.size() == _opts->maxDepth) { if (_enumeratedPath.vertices.empty()) {
// we have reached the maximal search depth. // We are done;
// We can prune this path and go to the next. return false;
prune(); }
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(_enumeratedPath.vertices.back(),
_enumeratedPath.vertices.size());
if (cursor != nullptr) {
_edgeCursors.emplace(cursor);
}
} else {
// This path is at the end. cut the last step
_enumeratedPath.vertices.pop_back();
_enumeratedPath.edges.pop_back();
} }
// Avoid tail recursion. May crash on high search depth while (!_edgeCursors.empty()) {
while (true) { auto cursor = _edgeCursors.top();
if (_lastEdges.empty()) { if (cursor->next(_enumeratedPath.edges)) {
_enumeratedPath.edges.clear(); #warning not yet finished
_enumeratedPath.vertices.clear(); // TODO UNIQUE_PATH
return false; // We have to check if edge and vertex is valid
} if (_traverser->getVertex(_enumeratedPath.edges.back(),
_traverser->getEdge(_enumeratedPath.vertices.back(), _enumeratedPath.edges, _enumeratedPath.vertices)) {
_lastEdges.top(), _lastEdgesIdx.top()); // case both are valid.
if (_lastEdges.top() != nullptr) { // TODO UNIQUE_PATH
// Could continue the path in the next depth.
_lastEdges.push(nullptr);
_lastEdgesIdx.push(0);
std::string v;
bool isValid = _traverser->getVertex(_enumeratedPath.edges.back(),
_enumeratedPath.vertices.back(),
_enumeratedPath.vertices.size(), v);
_enumeratedPath.vertices.push_back(v);
TRI_ASSERT(_enumeratedPath.vertices.size() ==
_enumeratedPath.edges.size() + 1);
if (isValid) {
if (_enumeratedPath.edges.size() < _opts->minDepth) {
// The path is ok as a prefix. But to short to be returned.
continue;
}
if (_opts->uniqueVertices == TraverserOptions::UniquenessLevel::PATH) {
// it is sufficient to check if any of the vertices on the path is equal to the end.
// Then we prune and any intermediate equality cannot happen.
auto& last = _enumeratedPath.vertices.back();
auto found = std::find(_enumeratedPath.vertices.begin(), _enumeratedPath.vertices.end(), last);
TRI_ASSERT(found != _enumeratedPath.vertices.end()); // We have to find it once, it is at least the last!
if ((++found) != _enumeratedPath.vertices.end()) {
// Test if we found the last element. That is ok.
prune();
continue;
}
}
return true; return true;
} }
} else { // Vertex Invalid. Revoke edge
if (_enumeratedPath.edges.empty()) {
// We are done with enumerating paths
_enumeratedPath.edges.clear();
_enumeratedPath.vertices.clear();
return false;
}
}
// This either modifies the stack or _lastEdges is empty.
// This will return in next depth
prune();
}
}
void DepthFirstEnumerator::prune() {
if (!_lastEdges.empty()) {
_lastEdges.pop();
_lastEdgesIdx.pop();
if (!_enumeratedPath.edges.empty()) {
_enumeratedPath.edges.pop_back(); _enumeratedPath.edges.pop_back();
_enumeratedPath.vertices.pop_back(); } else {
// cursor is empty.
_edgeCursors.pop();
} }
} }
// If we get here all cursors are exhausted.
_enumeratedPath.edges.clear();
_enumeratedPath.vertices.clear();
return false;
} }
arangodb::aql::AqlValue DepthFirstEnumerator::lastVertexToAqlValue() { arangodb::aql::AqlValue DepthFirstEnumerator::lastVertexToAqlValue() {
@ -137,7 +112,7 @@ arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(arangodb::velocypac
} }
BreadthFirstEnumerator::BreadthFirstEnumerator(Traverser* traverser, BreadthFirstEnumerator::BreadthFirstEnumerator(Traverser* traverser,
std::string const& startVertex, VPackSlice startVertex,
TraverserOptions const* opts) TraverserOptions const* opts)
: PathEnumerator(traverser, startVertex, opts), : PathEnumerator(traverser, startVertex, opts),
_schreierIndex(1), _schreierIndex(1),
@ -213,10 +188,10 @@ bool BreadthFirstEnumerator::next() {
bool shouldReturnPath = _currentDepth + 1 >= _opts->minDepth; bool shouldReturnPath = _currentDepth + 1 >= _opts->minDepth;
if (!_tmpEdges.empty()) { if (!_tmpEdges.empty()) {
bool didInsert = false; bool didInsert = false;
std::string v; VPackSlice v;
for (auto const& e : _tmpEdges) { for (auto const& e : _tmpEdges) {
bool valid = bool valid =
_traverser->getVertex(e, nextVertex, _currentDepth, v); _traverser->getSingleVertex(e, nextVertex, _currentDepth, v);
if (valid) { if (valid) {
auto step = std::make_unique<PathStep>(nextIdx, e, v); auto step = std::make_unique<PathStep>(nextIdx, e, v);
_schreier.emplace_back(step.get()); _schreier.emplace_back(step.get());
@ -251,12 +226,6 @@ bool BreadthFirstEnumerator::next() {
return true; return true;
} }
void BreadthFirstEnumerator::prune() {
if (!_nextDepth.empty()) {
_nextDepth.pop_back();
}
}
// TODO Optimize this. Remove enumeratedPath // TODO Optimize this. Remove enumeratedPath
// All can be read from schreier vector directly // All can be read from schreier vector directly
arangodb::aql::AqlValue BreadthFirstEnumerator::lastVertexToAqlValue() { arangodb::aql::AqlValue BreadthFirstEnumerator::lastVertexToAqlValue() {

View File

@ -25,6 +25,7 @@
#define ARANGODB_VOCBASE_PATHENUMERATOR_H 1 #define ARANGODB_VOCBASE_PATHENUMERATOR_H 1
#include "Basics/Common.h" #include "Basics/Common.h"
#include <velocypack/Slice.h>
#include <stack> #include <stack>
namespace arangodb { namespace arangodb {
@ -37,12 +38,13 @@ class Builder;
} }
namespace traverser { namespace traverser {
class EdgeCursor;
class Traverser; class Traverser;
struct TraverserOptions; struct TraverserOptions;
struct EnumeratedPath { struct EnumeratedPath {
std::vector<std::string> edges; std::vector<arangodb::velocypack::Slice> edges;
std::vector<std::string> vertices; std::vector<arangodb::velocypack::Slice> vertices;
EnumeratedPath() {} EnumeratedPath() {}
}; };
@ -79,7 +81,7 @@ class PathEnumerator {
EnumeratedPath _enumeratedPath; EnumeratedPath _enumeratedPath;
public: public:
PathEnumerator(Traverser* traverser, std::string const& startVertex, PathEnumerator(Traverser* traverser, arangodb::velocypack::Slice startVertex,
TraverserOptions const* opts) TraverserOptions const* opts)
: _traverser(traverser), _isFirst(true), _opts(opts) { : _traverser(traverser), _isFirst(true), _opts(opts) {
_enumeratedPath.vertices.push_back(startVertex); _enumeratedPath.vertices.push_back(startVertex);
@ -96,13 +98,6 @@ class PathEnumerator {
virtual bool next() = 0; virtual bool next() = 0;
//////////////////////////////////////////////////////////////////////////////
/// @brief Prunes the current path prefix, the next function should not return
/// any path having this prefix anymore.
//////////////////////////////////////////////////////////////////////////////
virtual void prune() = 0;
virtual aql::AqlValue lastVertexToAqlValue() = 0; virtual aql::AqlValue lastVertexToAqlValue() = 0;
virtual aql::AqlValue lastEdgeToAqlValue() = 0; virtual aql::AqlValue lastEdgeToAqlValue() = 0;
virtual aql::AqlValue pathToAqlValue(arangodb::velocypack::Builder&) = 0; virtual aql::AqlValue pathToAqlValue(arangodb::velocypack::Builder&) = 0;
@ -111,30 +106,20 @@ class PathEnumerator {
class DepthFirstEnumerator final : public PathEnumerator { class DepthFirstEnumerator final : public PathEnumerator {
private: private:
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief The pointers returned for edge indexes on this path. Used to /// @brief The stack of EdgeCursors to walk through.
/// continue
/// the search on respective levels.
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
std::stack<size_t*> _lastEdges; std::stack<EdgeCursor*> _edgeCursors;
//////////////////////////////////////////////////////////////////////////////
/// @brief An internal index for the edge collection used at each depth level
//////////////////////////////////////////////////////////////////////////////
std::stack<size_t> _lastEdgesIdx;
public: public:
DepthFirstEnumerator( DepthFirstEnumerator(Traverser* traverser,
Traverser* traverser, arangodb::velocypack::Slice startVertex,
std::string const& startVertex, TraverserOptions const* opts) TraverserOptions const* opts)
: PathEnumerator(traverser, startVertex, opts) { : PathEnumerator(traverser, startVertex, opts) {}
_lastEdges.push(nullptr);
_lastEdgesIdx.push(0);
TRI_ASSERT(_lastEdges.size() == 1);
}
~DepthFirstEnumerator() {} ~DepthFirstEnumerator() {
#warning Who is responsible for the cursors? Traverser or this class? Maybe they are just leased.
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Get the next Path element from the traversal. /// @brief Get the next Path element from the traversal.
@ -147,8 +132,6 @@ class DepthFirstEnumerator final : public PathEnumerator {
/// any path having this prefix anymore. /// any path having this prefix anymore.
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void prune() override;
aql::AqlValue lastVertexToAqlValue() override; aql::AqlValue lastVertexToAqlValue() override;
aql::AqlValue lastEdgeToAqlValue() override; aql::AqlValue lastEdgeToAqlValue() override;
@ -166,17 +149,17 @@ class BreadthFirstEnumerator final : public PathEnumerator {
struct PathStep { struct PathStep {
size_t sourceIdx; size_t sourceIdx;
std::string edge; arangodb::velocypack::Slice edge;
std::string vertex; arangodb::velocypack::Slice vertex;
private: private:
PathStep() {} PathStep() {}
public: public:
explicit PathStep(std::string const& vertex) : sourceIdx(0), vertex(vertex) {} explicit PathStep(arangodb::velocypack::Slice vertex) : sourceIdx(0), vertex(vertex) {}
PathStep(size_t sourceIdx, std::string const& edge, PathStep(size_t sourceIdx, arangodb::velocypack::Slice edge,
std::string const& vertex) arangodb::velocypack::Slice vertex)
: sourceIdx(sourceIdx), edge(edge), vertex(vertex) {} : sourceIdx(sourceIdx), edge(edge), vertex(vertex) {}
}; };
@ -230,7 +213,7 @@ class BreadthFirstEnumerator final : public PathEnumerator {
/// @brief Vector storing the position at current search depth /// @brief Vector storing the position at current search depth
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
std::unordered_set<std::string> _tmpEdges; std::unordered_set<arangodb::velocypack::Slice> _tmpEdges;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Marker for the search depth. Used to abort searching. /// @brief Marker for the search depth. Used to abort searching.
@ -247,7 +230,8 @@ class BreadthFirstEnumerator final : public PathEnumerator {
public: public:
BreadthFirstEnumerator(Traverser* traverser, BreadthFirstEnumerator(Traverser* traverser,
std::string const& startVertex, TraverserOptions const* opts); arangodb::velocypack::Slice startVertex,
TraverserOptions const* opts);
~BreadthFirstEnumerator() { ~BreadthFirstEnumerator() {
for (auto& it : _schreier) { for (auto& it : _schreier) {
@ -266,8 +250,6 @@ class BreadthFirstEnumerator final : public PathEnumerator {
/// any path having this prefix anymore. /// any path having this prefix anymore.
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void prune() override;
aql::AqlValue lastVertexToAqlValue() override; aql::AqlValue lastVertexToAqlValue() override;
aql::AqlValue lastEdgeToAqlValue() override; aql::AqlValue lastEdgeToAqlValue() override;

View File

@ -56,6 +56,15 @@ static int FetchDocumentById(arangodb::Transaction* trx,
return res; return res;
} }
SingleServerEdgeCursor::SingleServerEdgeCursor() {
#warning TODO Implement
};
bool SingleServerEdgeCursor::next(std::vector<VPackSlice>& result) {
#warning TODO Implement
return false;
}
SingleServerTraverser::SingleServerTraverser(TraverserOptions& opts, SingleServerTraverser::SingleServerTraverser(TraverserOptions& opts,
arangodb::Transaction* trx) arangodb::Transaction* trx)
: Traverser(opts), _trx(trx) { : Traverser(opts), _trx(trx) {
@ -77,8 +86,9 @@ bool SingleServerTraverser::edgeMatchesConditions(VPackSlice e, size_t depth) {
return true; return true;
} }
bool SingleServerTraverser::vertexMatchesConditions(std::string const& v, bool SingleServerTraverser::vertexMatchesConditions(VPackSlice v,
size_t depth) { size_t depth) {
TRI_ASSERT(v.isString());
#warning it is possible to not fetch the vertex if no check is required. #warning it is possible to not fetch the vertex if no check is required.
aql::AqlValue vertex = fetchVertexData(v); aql::AqlValue vertex = fetchVertexData(v);
if (!_opts.evaluateVertexExpression(vertex.slice(), depth)) { if (!_opts.evaluateVertexExpression(vertex.slice(), depth)) {
@ -88,12 +98,14 @@ bool SingleServerTraverser::vertexMatchesConditions(std::string const& v,
return true; return true;
} }
aql::AqlValue SingleServerTraverser::fetchVertexData(std::string const& id) { aql::AqlValue SingleServerTraverser::fetchVertexData(VPackSlice id) {
TRI_ASSERT(id.isString());
auto it = _vertices.find(id); auto it = _vertices.find(id);
if (it == _vertices.end()) { if (it == _vertices.end()) {
TRI_doc_mptr_t mptr; TRI_doc_mptr_t mptr;
int res = FetchDocumentById(_trx, id, &mptr); #warning Do we need the copy here
int res = FetchDocumentById(_trx, id.copyString(), &mptr);
++_readDocuments; ++_readDocuments;
if (res != TRI_ERROR_NO_ERROR) { if (res != TRI_ERROR_NO_ERROR) {
return aql::AqlValue(basics::VelocyPackHelper::NullValue()); return aql::AqlValue(basics::VelocyPackHelper::NullValue());
@ -107,20 +119,26 @@ aql::AqlValue SingleServerTraverser::fetchVertexData(std::string const& id) {
return aql::AqlValue((*it).second, aql::AqlValueFromMasterPointer()); return aql::AqlValue((*it).second, aql::AqlValueFromMasterPointer());
} }
aql::AqlValue SingleServerTraverser::fetchEdgeData(std::string const& id) { aql::AqlValue SingleServerTraverser::fetchEdgeData(VPackSlice edge) {
#warning Is this enough?
return aql::AqlValue(edge);
/*
auto it = _edges.find(id); auto it = _edges.find(id);
TRI_ASSERT(it != _edges.end()); TRI_ASSERT(it != _edges.end());
return aql::AqlValue((*it).second, aql::AqlValueFromMasterPointer()); return aql::AqlValue((*it).second, aql::AqlValueFromMasterPointer());
*/
} }
void SingleServerTraverser::addVertexToVelocyPack(std::string const& id, void SingleServerTraverser::addVertexToVelocyPack(VPackSlice id,
arangodb::velocypack::Builder& result) { VPackBuilder& result) {
TRI_ASSERT(id.isString());
auto it = _vertices.find(id); auto it = _vertices.find(id);
if (it == _vertices.end()) { if (it == _vertices.end()) {
TRI_doc_mptr_t mptr; TRI_doc_mptr_t mptr;
int res = FetchDocumentById(_trx, id, &mptr); #warning Do we need the copy here?
int res = FetchDocumentById(_trx, id.copyString(), &mptr);
++_readDocuments; ++_readDocuments;
if (res != TRI_ERROR_NO_ERROR) { if (res != TRI_ERROR_NO_ERROR) {
result.add(basics::VelocyPackHelper::NullValue()); result.add(basics::VelocyPackHelper::NullValue());
@ -134,62 +152,106 @@ void SingleServerTraverser::addVertexToVelocyPack(std::string const& id,
} }
} }
void SingleServerTraverser::addEdgeToVelocyPack(std::string const& id, void SingleServerTraverser::addEdgeToVelocyPack(VPackSlice edge,
arangodb::velocypack::Builder& result) { VPackBuilder& result) {
auto it = _edges.find(id); result.addExternal(edge.begin());
TRI_ASSERT(it != _edges.end());
result.addExternal((*it).second);
} }
bool SingleServerTraverser::VertexGetter::getVertex(std::string const& edge, bool SingleServerTraverser::VertexGetter::getVertex(
std::string const& vertex, VPackSlice edge, std::vector<VPackSlice>& result) {
size_t depth, VPackSlice cmp = result.back();
std::string& result) { VPackSlice from = Transaction::extractFromFromDocument(edge);
auto it = _traverser->_edges.find(edge); #warning Here we have to execute VertexFilter
TRI_ASSERT(it != _traverser->_edges.end()); /// If the vertex is not cached in _traverser->_vertices => incr. _filteredPath return false;
VPackSlice v((*it).second); /// Else check condition if ok => return true, else return false.
// NOTE: We assume that we only have valid edges. /// When returning false set result = ""
VPackSlice from = Transaction::extractFromFromDocument(v); if (arangodb::basics::VelocyPackHelper::compare(cmp, from, false) != 0) {
if (from.isEqualString(vertex)) { result.emplace_back(from);
result = Transaction::extractToFromDocument(v).copyString();
} else { } else {
result = from.copyString(); result.emplace_back(Transaction::extractToFromDocument(edge));
}
if (!_traverser->vertexMatchesConditions(result, depth)) {
return false;
} }
return true; return true;
} }
void SingleServerTraverser::VertexGetter::reset(std::string const&) { bool SingleServerTraverser::VertexGetter::getSingleVertex(VPackSlice edge,
VPackSlice cmp,
size_t depth,
VPackSlice& result) {
VPackSlice from = Transaction::extractFromFromDocument(edge);
#warning Here we have to execute VertexFilter
/// If the vertex is not cached in _traverser->_vertices => incr. _filteredPath return false;
/// Else check condition if ok => return true, else return false.
/// When returning false set result = ""
if (arangodb::basics::VelocyPackHelper::compare(cmp, from, false) != 0) {
result = from;
} else {
result = Transaction::extractToFromDocument(edge);
}
return true;
}
void SingleServerTraverser::VertexGetter::reset(arangodb::velocypack::Slice) {
} }
bool SingleServerTraverser::UniqueVertexGetter::getVertex( bool SingleServerTraverser::UniqueVertexGetter::getVertex(
std::string const& edge, std::string const& vertex, size_t depth, VPackSlice edge, std::vector<VPackSlice>& result) {
std::string& result) { VPackSlice toAdd = Transaction::extractFromFromDocument(edge);
VPackSlice cmp = result.back();
if (arangodb::basics::VelocyPackHelper::compare(toAdd, cmp, false) == 0) {
toAdd = Transaction::extractToFromDocument(edge);
}
auto it = _traverser->_edges.find(edge); #warning Here we have to execute VertexFilter
TRI_ASSERT(it != _traverser->_edges.end()); /// If the vertex is not cached in _traverser->_vertices => incr. _filteredPath return false;
VPackSlice v((*it).second); /// Else check condition if ok => return true, else return false.
// NOTE: We assume that we only have valid edges. /// When returning false set result = ""
VPackSlice from = Transaction::extractFromFromDocument(v); /// When returning true: _returnedVertices.emplace(result)
if (from.isEqualString(vertex)) {
result = Transaction::extractToFromDocument(v).copyString(); if (_returnedVertices.find(toAdd) != _returnedVertices.end()) {
// This vertex is not unique.
++_traverser->_filteredPaths;
return false;
} else { } else {
result = from.copyString(); _returnedVertices.emplace(toAdd);
result.emplace_back(toAdd);
return true;
} }
if (_returnedVertices.find(result) != _returnedVertices.end()) {
return false; // This should never be reached
} return false;
if (!_traverser->vertexMatchesConditions(result, depth)) {
return false;
}
_returnedVertices.emplace(result);
return true;
} }
void SingleServerTraverser::UniqueVertexGetter::reset(std::string const& startVertex) { bool SingleServerTraverser::UniqueVertexGetter::getSingleVertex(
VPackSlice edge, VPackSlice cmp, size_t depth, VPackSlice& result) {
result = Transaction::extractFromFromDocument(edge);
if (arangodb::basics::VelocyPackHelper::compare(result, cmp, false) == 0) {
result = Transaction::extractToFromDocument(edge);
}
#warning Here we have to execute VertexFilter
/// If the vertex is not cached in _traverser->_vertices => incr. _filteredPath return false;
/// Else check condition if ok => return true, else return false.
/// When returning false set result = ""
/// When returning true: _returnedVertices.emplace(result)
if (_returnedVertices.find(result) != _returnedVertices.end()) {
// This vertex is not unique.
++_traverser->_filteredPaths;
return false;
} else {
_returnedVertices.emplace(result);
return true;
}
// This should never be reached
return false;
}
void SingleServerTraverser::UniqueVertexGetter::reset(VPackSlice startVertex) {
_returnedVertices.clear(); _returnedVertices.clear();
// The startVertex always counts as visited! // The startVertex always counts as visited!
_returnedVertices.emplace(startVertex); _returnedVertices.emplace(startVertex);
@ -198,6 +260,11 @@ void SingleServerTraverser::UniqueVertexGetter::reset(std::string const& startVe
void SingleServerTraverser::setStartVertex(std::string const& v) { void SingleServerTraverser::setStartVertex(std::string const& v) {
_pruneNext = false; _pruneNext = false;
#warning Who is responsible for this builder?!
VPackBuilder tmp;
tmp.add(VPackValue(v));
VPackSlice idSlice = tmp.slice();
TRI_doc_mptr_t vertex; TRI_doc_mptr_t vertex;
int result = FetchDocumentById(_trx, v, &vertex); int result = FetchDocumentById(_trx, v, &vertex);
++_readDocuments; ++_readDocuments;
@ -207,19 +274,19 @@ void SingleServerTraverser::setStartVertex(std::string const& v) {
_done = true; _done = true;
return; return;
} }
VPackSlice vertexSlice(vertex.vpack());
_vertices.emplace(v, vertex.vpack()); if (!_opts.evaluateVertexExpression(vertexSlice, 0)) {
if (!_opts.evaluateVertexExpression(VPackSlice(vertex.vpack()), 0)) {
// Start vertex invalid // Start vertex invalid
++_filteredPaths; ++_filteredPaths;
_done = true; _done = true;
return; return;
} }
_vertexGetter->reset(v); _vertexGetter->reset(idSlice);
if (_opts.useBreadthFirst) { if (_opts.useBreadthFirst) {
_enumerator.reset(new BreadthFirstEnumerator(this, v, &_opts)); _enumerator.reset(new BreadthFirstEnumerator(this, vertexSlice, &_opts));
} else { } else {
_enumerator.reset(new DepthFirstEnumerator(this, v, &_opts)); _enumerator.reset(new DepthFirstEnumerator(this, vertexSlice, &_opts));
} }
_done = false; _done = false;
} }
@ -229,26 +296,25 @@ void SingleServerTraverser::getEdge(std::string const& startVertex,
size_t*& last, size_t& eColIdx) { size_t*& last, size_t& eColIdx) {
return _edgeGetter->getEdge(startVertex, edges, last, eColIdx); return _edgeGetter->getEdge(startVertex, edges, last, eColIdx);
} }
void SingleServerTraverser::getAllEdges( void SingleServerTraverser::getAllEdges(
std::string const& startVertex, std::unordered_set<std::string>& edges, arangodb::velocypack::Slice startVertex,
size_t depth) { std::unordered_set<arangodb::velocypack::Slice>& edges, size_t depth) {
return _edgeGetter->getAllEdges(startVertex, edges, depth); return _edgeGetter->getAllEdges(startVertex, edges, depth);
} }
bool SingleServerTraverser::getVertex(std::string const& edge, bool SingleServerTraverser::getVertex(VPackSlice edge,
std::string const& vertex, size_t depth, std::vector<VPackSlice>& result) {
std::string& result) { return _vertexGetter->getVertex(edge, result);
return _vertexGetter->getVertex(edge, vertex, depth, result); }
bool SingleServerTraverser::getSingleVertex(VPackSlice edge, VPackSlice vertex,
size_t depth, VPackSlice& result) {
return _vertexGetter->getSingleVertex(edge, vertex, depth, result);
} }
bool SingleServerTraverser::next() { bool SingleServerTraverser::next() {
TRI_ASSERT(!_done); TRI_ASSERT(!_done);
if (_pruneNext) {
_pruneNext = false;
_enumerator->prune();
}
TRI_ASSERT(!_pruneNext);
bool res = _enumerator->next(); bool res = _enumerator->next();
if (!res) { if (!res) {
_done = true; _done = true;
@ -425,9 +491,8 @@ void SingleServerTraverser::EdgeGetter::getEdge(std::string const& startVertex,
} }
void SingleServerTraverser::EdgeGetter::getAllEdges( void SingleServerTraverser::EdgeGetter::getAllEdges(
std::string const& startVertex, std::unordered_set<std::string>& edges, VPackSlice startVertex, std::unordered_set<VPackSlice>& edges,
size_t depth) { size_t depth) {
#warning reimplement #warning reimplement
/* /*
size_t idxId = 0; size_t idxId = 0;

View File

@ -37,8 +37,20 @@ namespace traverser {
class PathEnumerator; class PathEnumerator;
class SingleServerTraverser final : public Traverser { class SingleServerEdgeCursor : public EdgeCursor {
private:
std::vector<OperationCursor> _cursors;
size_t _currentCursor;
public:
SingleServerEdgeCursor();
~SingleServerEdgeCursor() {}
bool next(std::vector<arangodb::velocypack::Slice>&);
};
class SingleServerTraverser final : public Traverser {
private: private:
class VertexGetter { class VertexGetter {
@ -48,9 +60,14 @@ class SingleServerTraverser final : public Traverser {
virtual ~VertexGetter() = default; virtual ~VertexGetter() = default;
virtual bool getVertex(std::string const&, std::string const&, size_t, virtual bool getVertex(arangodb::velocypack::Slice,
std::string&); std::vector<arangodb::velocypack::Slice>&);
virtual void reset(std::string const&);
virtual bool getSingleVertex(arangodb::velocypack::Slice,
arangodb::velocypack::Slice, size_t,
arangodb::velocypack::Slice&);
virtual void reset(arangodb::velocypack::Slice);
protected: protected:
SingleServerTraverser* _traverser; SingleServerTraverser* _traverser;
@ -63,13 +80,17 @@ class SingleServerTraverser final : public Traverser {
~UniqueVertexGetter() = default; ~UniqueVertexGetter() = default;
bool getVertex(std::string const&, std::string const&, size_t, bool getVertex(arangodb::velocypack::Slice,
std::string&) override; std::vector<arangodb::velocypack::Slice>&) override;
void reset(std::string const&) override; bool getSingleVertex(arangodb::velocypack::Slice,
arangodb::velocypack::Slice, size_t,
arangodb::velocypack::Slice&) override;
void reset(arangodb::velocypack::Slice) override;
private: private:
std::unordered_set<std::string> _returnedVertices; std::unordered_set<arangodb::velocypack::Slice> _returnedVertices;
}; };
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -91,7 +112,8 @@ class SingleServerTraverser final : public Traverser {
void getEdge(std::string const&, std::vector<std::string>&, void getEdge(std::string const&, std::vector<std::string>&,
size_t*&, size_t&); size_t*&, size_t&);
void getAllEdges(std::string const&, std::unordered_set<std::string>&, size_t); void getAllEdges(arangodb::velocypack::Slice,
std::unordered_set<arangodb::velocypack::Slice>&, size_t);
private: private:
@ -193,16 +215,22 @@ public:
/// @brief Function to load all edges for a list of nodes /// @brief Function to load all edges for a list of nodes
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void getAllEdges(std::string const&, std::unordered_set<std::string>&, void getAllEdges(arangodb::velocypack::Slice,
std::unordered_set<arangodb::velocypack::Slice>&,
size_t) override; size_t) override;
//////////////////////////////////////////////////////////////////////////////
/// @brief Function to load the other sides vertex of an edge /// @brief Function to load the other sides vertex of an edge
/// Returns true if the vertex passes filtering conditions /// Returns true if the vertex passes filtering conditions
////////////////////////////////////////////////////////////////////////////// /// Adds the _id of the vertex into the given vector
bool getVertex(std::string const&, std::string const&, size_t, bool getVertex(arangodb::velocypack::Slice,
std::string&) override; std::vector<arangodb::velocypack::Slice>&) override;
/// @brief Function to load the other sides vertex of an edge
/// Returns true if the vertex passes filtering conditions
bool getSingleVertex(arangodb::velocypack::Slice, arangodb::velocypack::Slice,
size_t depth, arangodb::velocypack::Slice&) override;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Get the next possible path in the graph. /// @brief Get the next possible path in the graph.
@ -239,32 +267,32 @@ public:
/// @brief Function to fetch the real data of a vertex into an AQLValue /// @brief Function to fetch the real data of a vertex into an AQLValue
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
aql::AqlValue fetchVertexData(std::string const&) override; aql::AqlValue fetchVertexData(arangodb::velocypack::Slice) override;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Function to fetch the real data of an edge into an AQLValue /// @brief Function to fetch the real data of an edge into an AQLValue
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
aql::AqlValue fetchEdgeData(std::string const&) override; aql::AqlValue fetchEdgeData(arangodb::velocypack::Slice) override;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Function to add the real data of a vertex into a velocypack builder /// @brief Function to add the real data of a vertex into a velocypack builder
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void addVertexToVelocyPack(std::string const&, void addVertexToVelocyPack(arangodb::velocypack::Slice,
arangodb::velocypack::Builder&) override; arangodb::velocypack::Builder&) override;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Function to add the real data of an edge into a velocypack builder /// @brief Function to add the real data of an edge into a velocypack builder
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void addEdgeToVelocyPack(std::string const&, void addEdgeToVelocyPack(arangodb::velocypack::Slice,
arangodb::velocypack::Builder&) override; arangodb::velocypack::Builder&) override;
private: private:
bool edgeMatchesConditions(arangodb::velocypack::Slice, size_t); bool edgeMatchesConditions(arangodb::velocypack::Slice, size_t);
bool vertexMatchesConditions(std::string const&, size_t); bool vertexMatchesConditions(arangodb::velocypack::Slice, size_t);
std::vector<TRI_document_collection_t*> _edgeCols; std::vector<TRI_document_collection_t*> _edgeCols;
@ -279,7 +307,7 @@ public:
/// document VPack value (in datafiles) /// document VPack value (in datafiles)
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
std::unordered_map<std::string, uint8_t const*> _vertices; std::unordered_map<arangodb::velocypack::Slice, uint8_t const*> _vertices;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Cache for edge documents, points from _id to start of edge /// @brief Cache for edge documents, points from _id to start of edge

View File

@ -71,55 +71,6 @@ void arangodb::traverser::ShortestPath::vertexToVelocyPack(Transaction* trx, siz
} }
} }
#warning TODO remove
/*
size_t arangodb::traverser::TraverserOptions::collectionCount () const {
return _collections.size();
}
bool arangodb::traverser::TraverserOptions::getCollection(
size_t index, std::string& name, TRI_edge_direction_e& dir) const {
if (index >= _collections.size()) {
// No more collections stop now
return false;
}
if (_directions.size() == 1) {
dir = _directions.at(0);
} else {
dir = _directions.at(index);
}
name = _collections.at(index);
return true;
}
bool arangodb::traverser::TraverserOptions::getCollectionAndSearchValue(
size_t index, std::string const& vertexId, std::string& name,
Transaction::IndexHandle& indexHandle, VPackBuilder& builder) const {
if (index >= _collections.size()) {
// No more collections stop now
return false;
}
TRI_edge_direction_e dir;
TRI_ASSERT(!_directions.empty());
if (_directions.size() == 1) {
dir = _directions.at(0);
} else {
dir = _directions.at(index);
}
TRI_ASSERT(!_collections.empty());
name = _collections.at(index);
TRI_ASSERT(!_indexHandles.empty());
indexHandle = _indexHandles.at(index);
builder.clear();
arangodb::EdgeIndex::buildSearchValue(dir, vertexId, builder);
return true;
}
*/
bool arangodb::traverser::TraverserOptions::evaluateEdgeExpression(arangodb::velocypack::Slice edge, size_t depth) const { bool arangodb::traverser::TraverserOptions::evaluateEdgeExpression(arangodb::velocypack::Slice edge, size_t depth) const {
#warning This has to be implemented. #warning This has to be implemented.
return true; return true;
@ -130,6 +81,11 @@ bool arangodb::traverser::TraverserOptions::evaluateVertexExpression(arangodb::v
return true; return true;
} }
arangodb::traverser::EdgeCursor* arangodb::traverser::TraverserOptions::nextCursor(VPackSlice vertex, size_t depth) const {
#warning This has to be implemented.
return nullptr;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief Creates an expression from a VelocyPackSlice /// @brief Creates an expression from a VelocyPackSlice
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -41,10 +41,24 @@ class Slice;
} }
namespace aql { namespace aql {
struct AstNode;
class TraversalNode; class TraversalNode;
} }
namespace traverser { namespace traverser {
/// @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::vector<arangodb::velocypack::Slice>&) = 0;
};
#warning Deprecated
class TraverserExpression { class TraverserExpression {
public: public:
bool isEdgeAccess; bool isEdgeAccess;
@ -207,11 +221,11 @@ struct TraverserOptions {
private: private:
arangodb::Transaction* _trx; arangodb::Transaction* _trx;
std::vector<std::string> _collections;
std::vector<TRI_edge_direction_e> _directions;
std::vector<arangodb::Transaction::IndexHandle> _baseIndexHandles; std::vector<arangodb::Transaction::IndexHandle> _baseIndexHandles;
std::unordered_map<size_t, std::vector<arangodb::Transaction::IndexHandle>> std::vector<aql::AstNode const*> _baseConditions;
_depthIndexHandles; std::unordered_map<size_t,
std::pair<std::vector<arangodb::Transaction::IndexHandle>,
std::vector<aql::AstNode const*>>> _depthIndexHandles;
public: public:
uint64_t minDepth; uint64_t minDepth;
@ -235,19 +249,11 @@ struct TraverserOptions {
uniqueEdges(UniquenessLevel::PATH) { uniqueEdges(UniquenessLevel::PATH) {
} }
/*
size_t collectionCount() const;
bool getCollection(size_t, std::string&, TRI_edge_direction_e&) const;
bool getCollectionAndSearchValue(size_t, std::string const&, std::string&,
arangodb::Transaction::IndexHandle&,
arangodb::velocypack::Builder&) const;
*/
bool evaluateEdgeExpression(arangodb::velocypack::Slice, size_t) const; bool evaluateEdgeExpression(arangodb::velocypack::Slice, size_t) const;
bool evaluateVertexExpression(arangodb::velocypack::Slice, size_t) const; bool evaluateVertexExpression(arangodb::velocypack::Slice, size_t) const;
EdgeCursor* nextCursor(arangodb::velocypack::Slice, size_t) const;
}; };
class Traverser { class Traverser {
@ -313,17 +319,24 @@ class Traverser {
/// @brief Function to load all edges for a list of nodes /// @brief Function to load all edges for a list of nodes
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
virtual void getAllEdges(std::string const&, std::unordered_set<std::string>&, virtual void getAllEdges(arangodb::velocypack::Slice,
std::unordered_set<arangodb::velocypack::Slice>&,
size_t) = 0; size_t) = 0;
//////////////////////////////////////////////////////////////////////////////
/// @brief Function to load the other sides vertex of an edge /// @brief Function to load the other sides vertex of an edge
/// Returns true if the vertex passes filtering conditions /// Returns true if the vertex passes filtering conditions
////////////////////////////////////////////////////////////////////////////// /// Also apppends the _id value of the vertex in the given vector
virtual bool getVertex(std::string const&, std::string const&, size_t, virtual bool getVertex(arangodb::velocypack::Slice,
std::string&) = 0; std::vector<arangodb::velocypack::Slice>&) = 0;
/// @brief Function to load the other sides vertex of an edge
/// Returns true if the vertex passes filtering conditions
virtual bool getSingleVertex(arangodb::velocypack::Slice,
arangodb::velocypack::Slice, size_t,
arangodb::velocypack::Slice&) = 0;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Builds only the last vertex as AQLValue /// @brief Builds only the last vertex as AQLValue
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -419,26 +432,26 @@ class Traverser {
/// @brief Function to fetch the real data of a vertex into an AQLValue /// @brief Function to fetch the real data of a vertex into an AQLValue
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
virtual aql::AqlValue fetchVertexData(std::string const&) = 0; virtual aql::AqlValue fetchVertexData(arangodb::velocypack::Slice) = 0;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Function to fetch the real data of an edge into an AQLValue /// @brief Function to fetch the real data of an edge into an AQLValue
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
virtual aql::AqlValue fetchEdgeData(std::string const&) = 0; virtual aql::AqlValue fetchEdgeData(arangodb::velocypack::Slice) = 0;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Function to add the real data of a vertex into a velocypack builder /// @brief Function to add the real data of a vertex into a velocypack builder
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
virtual void addVertexToVelocyPack(std::string const&, virtual void addVertexToVelocyPack(arangodb::velocypack::Slice,
arangodb::velocypack::Builder&) = 0; arangodb::velocypack::Builder&) = 0;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief Function to add the real data of an edge into a velocypack builder /// @brief Function to add the real data of an edge into a velocypack builder
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
virtual void addEdgeToVelocyPack(std::string const&, virtual void addEdgeToVelocyPack(arangodb::velocypack::Slice,
arangodb::velocypack::Builder&) = 0; arangodb::velocypack::Builder&) = 0;
}; };
} // traverser } // traverser