diff --git a/arangod/Cluster/TraverserEngine.cpp b/arangod/Cluster/TraverserEngine.cpp index ecfce46aaf..369780f64f 100644 --- a/arangod/Cluster/TraverserEngine.cpp +++ b/arangod/Cluster/TraverserEngine.cpp @@ -232,7 +232,10 @@ void BaseTraverserEngine::getEdges(VPackSlice vertex, size_t depth, _opts->nextCursor(&mmdr, vertexId, depth)); edgeCursor->readAll( - [&](std::unique_ptr&&, VPackSlice edge, size_t cursorId) { + [&](std::unique_ptr&& eid, VPackSlice edge, size_t cursorId) { + if (edge.isString()) { + edge = _opts->cache()->lookupToken(eid.get()); + } if (_opts->evaluateEdgeExpression(edge, StringRef(v), depth, cursorId)) { builder.add(edge); @@ -244,7 +247,10 @@ void BaseTraverserEngine::getEdges(VPackSlice vertex, size_t depth, std::unique_ptr edgeCursor( _opts->nextCursor(&mmdr, StringRef(vertex), depth)); edgeCursor->readAll( - [&](std::unique_ptr&&, VPackSlice edge, size_t cursorId) { + [&](std::unique_ptr&& eid, VPackSlice edge, size_t cursorId) { + if (edge.isString()) { + edge = _opts->cache()->lookupToken(eid.get()); + } if (_opts->evaluateEdgeExpression(edge, StringRef(vertex), depth, cursorId)) { builder.add(edge); @@ -374,8 +380,13 @@ void ShortestPathEngine::getEdges(VPackSlice vertex, bool backward, edgeCursor.reset(_opts->nextCursor(&mmdr, vertexId)); } - edgeCursor->readAll([&](std::unique_ptr&&, VPackSlice edge, - size_t cursorId) { builder.add(edge); }); + edgeCursor->readAll([&](std::unique_ptr&& eid, VPackSlice edge, + size_t cursorId) { + if (edge.isString()) { + edge = _opts->cache()->lookupToken(eid.get()); + } + builder.add(edge); + }); // Result now contains all valid edges, probably multiples. } } else if (vertex.isString()) { @@ -385,8 +396,13 @@ void ShortestPathEngine::getEdges(VPackSlice vertex, bool backward, } else { edgeCursor.reset(_opts->nextCursor(&mmdr, vertexId)); } - edgeCursor->readAll([&](std::unique_ptr&&, VPackSlice edge, - size_t cursorId) { builder.add(edge); }); + edgeCursor->readAll([&](std::unique_ptr&& eid, VPackSlice edge, + size_t cursorId) { + if (edge.isString()) { + edge = _opts->cache()->lookupToken(eid.get()); + } + builder.add(edge); + }); // Result now contains all valid edges, probably multiples. } else { THROW_ARANGO_EXCEPTION(TRI_ERROR_BAD_PARAMETER); diff --git a/arangod/Graph/AttributeWeightShortestPathFinder.cpp b/arangod/Graph/AttributeWeightShortestPathFinder.cpp index b6ce7dc7de..f7ff625b8a 100644 --- a/arangod/Graph/AttributeWeightShortestPathFinder.cpp +++ b/arangod/Graph/AttributeWeightShortestPathFinder.cpp @@ -288,15 +288,22 @@ void AttributeWeightShortestPathFinder::expandVertex( std::unordered_map candidates; auto callback = [&](std::unique_ptr&& eid, VPackSlice edge, size_t cursorIdx) -> void { - StringRef fromTmp(transaction::helpers::extractFromFromDocument(edge)); - StringRef toTmp(transaction::helpers::extractToFromDocument(edge)); - StringRef from = _options->cache()->persistString(fromTmp); - StringRef to = _options->cache()->persistString(toTmp); double currentWeight = _options->weightEdge(edge); - if (from == vertex) { - inserter(candidates, result, from, to, currentWeight, std::move(eid)); + if (edge.isString()) { + StringRef other = _options->cache()->persistString(StringRef(edge)); + TRI_ASSERT(other.compare(vertex) == 0); + inserter(candidates, result, vertex, other, currentWeight, std::move(eid)); } else { - inserter(candidates, result, to, from, currentWeight, std::move(eid)); + StringRef fromTmp(transaction::helpers::extractFromFromDocument(edge)); + StringRef toTmp(transaction::helpers::extractToFromDocument(edge)); + StringRef from = _options->cache()->persistString(fromTmp); + StringRef to = _options->cache()->persistString(toTmp); + double currentWeight = _options->weightEdge(edge); + if (from == vertex) { + inserter(candidates, result, from, to, currentWeight, std::move(eid)); + } else { + inserter(candidates, result, to, from, currentWeight, std::move(eid)); + } } }; diff --git a/arangod/Graph/BreadthFirstEnumerator.cpp b/arangod/Graph/BreadthFirstEnumerator.cpp index f91be9fbbe..d1bd8d1397 100644 --- a/arangod/Graph/BreadthFirstEnumerator.cpp +++ b/arangod/Graph/BreadthFirstEnumerator.cpp @@ -130,10 +130,16 @@ bool BreadthFirstEnumerator::next() { auto callback = [&](std::unique_ptr&& eid, VPackSlice e, size_t cursorIdx) -> void { - - if (!_traverser->edgeMatchesConditions(e, nextVertex, _currentDepth, - cursorIdx)) { - return; + + if (_opts->hasEdgeFilter(_currentDepth, cursorIdx)) { + VPackSlice edge = e; + if (edge.isString()) { + edge = _opts->cache()->lookupToken(eid.get()); + } + if (!_traverser->edgeMatchesConditions(edge, nextVertex, _currentDepth, + cursorIdx)) { + return; + } } if (_traverser->getSingleVertex(e, nextVertex, _currentDepth, vId)) { diff --git a/arangod/Graph/ClusterTraverserCache.cpp b/arangod/Graph/ClusterTraverserCache.cpp index 36869d006c..b793b91b74 100644 --- a/arangod/Graph/ClusterTraverserCache.cpp +++ b/arangod/Graph/ClusterTraverserCache.cpp @@ -44,6 +44,10 @@ ClusterTraverserCache::ClusterTraverserCache( ClusterTraverserCache::~ClusterTraverserCache() {} +arangodb::velocypack::Slice ClusterTraverserCache::lookupToken(EdgeDocumentToken const* token) { + return lookupInCollection(static_cast(token)->id()); +} + aql::AqlValue ClusterTraverserCache::fetchAqlResult(EdgeDocumentToken const* idToken) { // This cast is save because the Coordinator can only create those tokens auto tkn = static_cast(idToken); diff --git a/arangod/Graph/ClusterTraverserCache.h b/arangod/Graph/ClusterTraverserCache.h index f1971482a5..81aef01d86 100644 --- a/arangod/Graph/ClusterTraverserCache.h +++ b/arangod/Graph/ClusterTraverserCache.h @@ -85,6 +85,8 @@ class ClusterTraverserCache : public TraverserCache { size_t& insertedDocuments(); size_t& filteredDocuments(); + + arangodb::velocypack::Slice lookupToken(EdgeDocumentToken const* token) override; private: std::unordered_map _edges; diff --git a/arangod/Graph/ConstantWeightShortestPathFinder.cpp b/arangod/Graph/ConstantWeightShortestPathFinder.cpp index 36a313b763..c497802029 100644 --- a/arangod/Graph/ConstantWeightShortestPathFinder.cpp +++ b/arangod/Graph/ConstantWeightShortestPathFinder.cpp @@ -178,14 +178,22 @@ void ConstantWeightShortestPathFinder::expandVertex(bool backward, auto callback = [&](std::unique_ptr&& eid, VPackSlice edge, size_t cursorIdx) -> void { - StringRef other(transaction::helpers::extractFromFromDocument(edge)); - if (other == vertex) { - other = StringRef(transaction::helpers::extractToFromDocument(edge)); - } - if (other != vertex) { - StringRef id = _options->cache()->persistString(other); - _edges.emplace_back(std::move(eid)); - _neighbors.emplace_back(id); + if (edge.isString()) { + if (edge.compareString(vertex.data(), vertex.length()) != 0) { + StringRef id = _options->cache()->persistString(StringRef(edge)); + _edges.emplace_back(std::move(eid)); + _neighbors.emplace_back(id); + } + } else { + StringRef other(transaction::helpers::extractFromFromDocument(edge)); + if (other == vertex) { + other = StringRef(transaction::helpers::extractToFromDocument(edge)); + } + if (other != vertex) { + StringRef id = _options->cache()->persistString(other); + _edges.emplace_back(std::move(eid)); + _neighbors.emplace_back(id); + } } }; edgeCursor->readAll(callback); diff --git a/arangod/Graph/NeighborsEnumerator.cpp b/arangod/Graph/NeighborsEnumerator.cpp index ffde87f377..a685650cee 100644 --- a/arangod/Graph/NeighborsEnumerator.cpp +++ b/arangod/Graph/NeighborsEnumerator.cpp @@ -61,15 +61,15 @@ bool NeighborsEnumerator::next() { _lastDepth.swap(_currentDepth); _currentDepth.clear(); - StringRef v; for (auto const& nextVertex : _lastDepth) { - auto callback = [&](std::unique_ptr&&, VPackSlice e, size_t cursorId) { + auto callback = [&](std::unique_ptr&&, + VPackSlice other, size_t cursorId) { // Counting should be done in readAll - if (_traverser->getSingleVertex(e, nextVertex, _searchDepth, v)) { - StringRef otherId = _traverser->traverserCache()->persistString(v); - if (_allFound.find(otherId) == _allFound.end()) { - _currentDepth.emplace(otherId); - _allFound.emplace(otherId); + StringRef v; + if (_traverser->getSingleVertex(other, nextVertex, _searchDepth, v)) { + if (_allFound.find(v) == _allFound.end()) { + _currentDepth.emplace(v); + _allFound.emplace(v); } } }; diff --git a/arangod/Graph/SingleServerEdgeCursor.cpp b/arangod/Graph/SingleServerEdgeCursor.cpp index 3d223f4cfc..7a0b19874f 100644 --- a/arangod/Graph/SingleServerEdgeCursor.cpp +++ b/arangod/Graph/SingleServerEdgeCursor.cpp @@ -169,9 +169,9 @@ void SingleServerEdgeCursor::readAll( LogicalCollection* collection = cursor->collection(); auto cid = collection->cid(); if (cursor->hasExtra()) { - auto cb = [&](DocumentIdentifierToken const& token, VPackSlice doc) { + auto cb = [&](DocumentIdentifierToken const& token, VPackSlice edge) { _opts->cache()->increaseCounter(); - callback(std::make_unique(cid, token), doc, cursorId); + callback(std::make_unique(cid, token), edge, cursorId); }; cursor->allWithExtra(cb); } else { @@ -187,3 +187,4 @@ void SingleServerEdgeCursor::readAll( } } } + diff --git a/arangod/Graph/TraverserCache.cpp b/arangod/Graph/TraverserCache.cpp index 0f34ba9c74..3a2b02a887 100644 --- a/arangod/Graph/TraverserCache.cpp +++ b/arangod/Graph/TraverserCache.cpp @@ -50,6 +50,11 @@ TraverserCache::TraverserCache(transaction::Methods* trx) TraverserCache::~TraverserCache() {} +arangodb::velocypack::Slice TraverserCache::lookupToken(EdgeDocumentToken const* token) { + return lookupInCollection(static_cast(token)); +} + + VPackSlice TraverserCache::lookupInCollection(StringRef id) { size_t pos = id.find('/'); if (pos == std::string::npos) { diff --git a/arangod/Graph/TraverserCache.h b/arangod/Graph/TraverserCache.h index 111edb8e2f..7223e16d7a 100644 --- a/arangod/Graph/TraverserCache.h +++ b/arangod/Graph/TraverserCache.h @@ -122,6 +122,9 @@ class TraverserCache { void increaseCounter() { _insertedDocuments++; } + + /// Only valid until the next call to this class + virtual arangodb::velocypack::Slice lookupToken(EdgeDocumentToken const* token); protected: diff --git a/arangod/RocksDBEngine/RocksDBEdgeIndex.cpp b/arangod/RocksDBEngine/RocksDBEdgeIndex.cpp index 38e2e90e51..975e896ba7 100644 --- a/arangod/RocksDBEngine/RocksDBEdgeIndex.cpp +++ b/arangod/RocksDBEngine/RocksDBEdgeIndex.cpp @@ -242,7 +242,7 @@ bool RocksDBEdgeIndexIterator::nextExtra(ExtraCallback const& cb, _builderIterator.next(); TRI_ASSERT(_builderIterator.valid()); // For now we store complete edges. - TRI_ASSERT(_builderIterator.value().isObject()); + TRI_ASSERT(_builderIterator.value().isString()); cb(tkn, _builderIterator.value()); @@ -287,7 +287,7 @@ bool RocksDBEdgeIndexIterator::nextExtra(ExtraCallback const& cb, _builderIterator.value().getNumericValue()}; _builderIterator.next(); TRI_ASSERT(_builderIterator.valid()); - TRI_ASSERT(_builderIterator.value().isObject()); + TRI_ASSERT(_builderIterator.value().isString()); cb(tkn, _builderIterator.value()); @@ -324,7 +324,6 @@ void RocksDBEdgeIndexIterator::lookupInRocksDB(StringRef fromTo) { _bounds = RocksDBKeyBounds::EdgeIndexVertex(_index->_objectId, fromTo); _iterator->Seek(_bounds.start()); resetInplaceMemory(); - RocksDBCollection* rocksColl = toRocksDBCollection(_collection); rocksdb::Comparator const* cmp = _index->comparator(); _builder.openArray(); @@ -332,8 +331,13 @@ void RocksDBEdgeIndexIterator::lookupInRocksDB(StringRef fromTo) { while (_iterator->Valid() && (cmp->Compare(_iterator->key(), end) < 0)) { TRI_voc_rid_t revisionId = RocksDBKey::revisionId(_iterator->key()); RocksDBToken token(revisionId); - - ManagedDocumentResult mmdr; + + // adding revision ID and _from or _to value + _builder.add(VPackValue(token.revisionId())); + StringRef vertexId = RocksDBValue::vertexId(_iterator->value()); + _builder.add(VPackValuePair(vertexId.data(), vertexId.size(), VPackValueType::String)); + + /*ManagedDocumentResult mmdr; if (rocksColl->readDocument(_trx, token, mmdr)) { _builder.add(VPackValue(token.revisionId())); VPackSlice doc(mmdr.vpack()); @@ -343,7 +347,7 @@ void RocksDBEdgeIndexIterator::lookupInRocksDB(StringRef fromTo) { // Data Inconsistency. // We have a revision id without a document... TRI_ASSERT(false); - } + }*/ _iterator->Next(); } _builder.close(); @@ -451,7 +455,7 @@ int RocksDBEdgeIndex::insert(transaction::Methods* trx, TRI_ASSERT(fromTo.isString()); auto fromToRef = StringRef(fromTo); RocksDBKey key = RocksDBKey::EdgeIndexValue(_objectId, fromToRef, revisionId); - VPackSlice toFrom = _isFromIndex ? doc.get(StaticStrings::ToString) : doc.get(StaticStrings::FromString); + VPackSlice toFrom = _isFromIndex ? transaction::helpers::extractToFromDocument(doc) : transaction::helpers::extractFromFromDocument(doc); TRI_ASSERT(toFrom.isString()); RocksDBValue value = RocksDBValue::EdgeIndexValue(StringRef(toFrom)); @@ -485,7 +489,7 @@ int RocksDBEdgeIndex::remove(transaction::Methods* trx, auto fromToRef = StringRef(fromTo); TRI_ASSERT(fromTo.isString()); RocksDBKey key = RocksDBKey::EdgeIndexValue(_objectId, fromToRef, revisionId); - VPackSlice toFrom = _isFromIndex ? doc.get(StaticStrings::ToString) : doc.get(StaticStrings::FromString); + VPackSlice toFrom = _isFromIndex ? transaction::helpers::extractToFromDocument(doc) : transaction::helpers::extractFromFromDocument(doc); TRI_ASSERT(toFrom.isString()); RocksDBValue value = RocksDBValue::EdgeIndexValue(StringRef(toFrom)); diff --git a/arangod/VocBase/Traverser.cpp b/arangod/VocBase/Traverser.cpp index bb10fb3c8e..0af77a7644 100644 --- a/arangod/VocBase/Traverser.cpp +++ b/arangod/VocBase/Traverser.cpp @@ -38,9 +38,13 @@ using namespace arangodb::traverser; using namespace arangodb::graph; bool Traverser::VertexGetter::getVertex(VPackSlice edge, std::vector& result) { - VPackSlice res = transaction::helpers::extractFromFromDocument(edge); - if (result.back() == StringRef(res)) { - res = transaction::helpers::extractToFromDocument(edge); + VPackSlice res = edge; + if (!res.isString()) { + res = transaction::helpers::extractFromFromDocument(edge); + if (result.back() == StringRef(res)) { + res = transaction::helpers::extractToFromDocument(edge); + } + TRI_ASSERT(res.isString()); } if (!_traverser->vertexMatchesConditions(res, result.size())) { @@ -52,12 +56,15 @@ bool Traverser::VertexGetter::getVertex(VPackSlice edge, std::vector& bool Traverser::VertexGetter::getSingleVertex(arangodb::velocypack::Slice edge, StringRef cmp, uint64_t depth, StringRef& result) { - VPackSlice resSlice; - VPackSlice from = transaction::helpers::extractFromFromDocument(edge); - if (from.compareString(cmp.data(), cmp.length()) != 0) { - resSlice = from; - } else { - resSlice = transaction::helpers::extractToFromDocument(edge); + VPackSlice resSlice = edge; + if (!resSlice.isString()) { + VPackSlice from = transaction::helpers::extractFromFromDocument(edge); + if (from.compareString(cmp.data(), cmp.length()) != 0) { + resSlice = from; + } else { + resSlice = transaction::helpers::extractToFromDocument(edge); + } + TRI_ASSERT(resSlice.isString()); } result = _traverser->traverserCache()->persistString(StringRef(resSlice)); return _traverser->vertexMatchesConditions(resSlice, depth); @@ -67,12 +74,17 @@ void Traverser::VertexGetter::reset(StringRef const&) { } bool Traverser::UniqueVertexGetter::getVertex(VPackSlice edge, std::vector& result) { - VPackSlice toAdd = transaction::helpers::extractFromFromDocument(edge); - StringRef const& cmp = result.back(); - TRI_ASSERT(toAdd.isString()); - if (cmp == StringRef(toAdd)) { - toAdd = transaction::helpers::extractToFromDocument(edge); + VPackSlice toAdd = edge; + if (!toAdd.isString()) { + toAdd = transaction::helpers::extractFromFromDocument(edge); + StringRef const& cmp = result.back(); + TRI_ASSERT(toAdd.isString()); + if (cmp == StringRef(toAdd)) { + toAdd = transaction::helpers::extractToFromDocument(edge); + } + TRI_ASSERT(toAdd.isString()); } + StringRef toAddStr = _traverser->traverserCache()->persistString(StringRef(toAdd)); // First check if we visited it. If not, then mark if (_returnedVertices.find(toAddStr) != _returnedVertices.end()) { @@ -93,12 +105,14 @@ bool Traverser::UniqueVertexGetter::getVertex(VPackSlice edge, std::vectortraverserCache()->persistString(StringRef(resSlice)); // First check if we visited it. If not, then mark diff --git a/arangod/VocBase/TraverserOptions.cpp b/arangod/VocBase/TraverserOptions.cpp index f0fd8744a0..75f7fc4293 100644 --- a/arangod/VocBase/TraverserOptions.cpp +++ b/arangod/VocBase/TraverserOptions.cpp @@ -414,6 +414,26 @@ bool TraverserOptions::vertexHasFilter(uint64_t depth) const { return _vertexExpressions.find(depth) != _vertexExpressions.end(); } +bool TraverserOptions::hasEdgeFilter(int64_t depth, size_t cursorId) const { + if (_isCoordinator) { + // The Coordinator never checks conditions. The DBServer is responsible! + return false; + } + arangodb::aql::Expression* expression = nullptr; + + auto specific = _depthLookupInfo.find(depth); + + if (specific != _depthLookupInfo.end()) { + TRI_ASSERT(!specific->second.empty()); + TRI_ASSERT(specific->second.size() > cursorId); + expression = specific->second[cursorId].expression; + } else { + expression = getEdgeExpression(cursorId); + } + return expression != nullptr; +} + + bool TraverserOptions::evaluateEdgeExpression(arangodb::velocypack::Slice edge, StringRef vertexId, uint64_t depth, diff --git a/arangod/VocBase/TraverserOptions.h b/arangod/VocBase/TraverserOptions.h index dff942d416..db21338d55 100644 --- a/arangod/VocBase/TraverserOptions.h +++ b/arangod/VocBase/TraverserOptions.h @@ -112,6 +112,8 @@ struct TraverserOptions : public graph::BaseOptions { bool vertexHasFilter(uint64_t) const; + bool hasEdgeFilter(int64_t, size_t) const; + bool evaluateEdgeExpression(arangodb::velocypack::Slice, StringRef vertexId, uint64_t, size_t) const;