mirror of https://gitee.com/bigwinds/arangodb
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:
parent
5b1e1b7496
commit
aa1dc2a083
|
@ -632,6 +632,7 @@ void TraversalNode::fillTraversalOptions(
|
|||
EdgeConditionBuilder globalEdgeConditionBuilder(this);
|
||||
|
||||
opts._baseIndexHandles.reserve(numEdgeColls);
|
||||
opts._baseConditions.reserve(numEdgeColls);
|
||||
// Compute Edge Indexes. First default indexes:
|
||||
for (size_t i = 0; i < numEdgeColls; ++i) {
|
||||
auto dir = _directions[i];
|
||||
|
@ -649,6 +650,7 @@ void TraversalNode::fillTraversalOptions(
|
|||
opts._baseIndexHandles);
|
||||
TRI_ASSERT(res); // Right now we have an enforced edge index which wil
|
||||
// always fit.
|
||||
opts._baseConditions.emplace_back(condition->clone(_ast));
|
||||
condition = globalEdgeConditionBuilder.getOutboundCondition();
|
||||
break;
|
||||
}
|
||||
|
@ -657,15 +659,19 @@ void TraversalNode::fillTraversalOptions(
|
|||
_edgeColls[i], condition, _tmpObjVariable, &sort, 1000,
|
||||
opts._baseIndexHandles);
|
||||
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) {
|
||||
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);
|
||||
|
||||
auto& idxList = ins.first->second;
|
||||
auto& idxList = ins.first->second.first;
|
||||
auto& condList = ins.first->second.second;
|
||||
idxList.reserve(numEdgeColls);
|
||||
condList.reserve(numEdgeColls);
|
||||
// Compute Edge Indexes. First default indexes:
|
||||
for (size_t i = 0; i < numEdgeColls; ++i) {
|
||||
auto dir = _directions[i];
|
||||
|
@ -682,6 +688,7 @@ void TraversalNode::fillTraversalOptions(
|
|||
_edgeColls[i], condition, _tmpObjVariable, &sort, 1000, idxList);
|
||||
TRI_ASSERT(res); // Right now we have an enforced edge index which wil
|
||||
// always fit.
|
||||
condList.emplace_back(condition);
|
||||
condition = it.second.getOutboundCondition();
|
||||
break;
|
||||
}
|
||||
|
@ -689,32 +696,10 @@ void TraversalNode::fillTraversalOptions(
|
|||
res = trx->getBestIndexHandleForFilterCondition(
|
||||
_edgeColls[i], condition, _tmpObjVariable, &sort, 1000, idxList);
|
||||
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.uniqueVertices = _options.uniqueVertices;
|
||||
opts.uniqueEdges = _options.uniqueEdges;
|
||||
|
|
|
@ -32,68 +32,103 @@ using namespace arangodb;
|
|||
|
||||
using ClusterTraverser = arangodb::traverser::ClusterTraverser;
|
||||
|
||||
bool ClusterTraverser::VertexGetter::getVertex(std::string const& edgeId,
|
||||
std::string const& vertexId,
|
||||
size_t depth,
|
||||
std::string& result) {
|
||||
|
||||
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);
|
||||
}
|
||||
bool ClusterTraverser::VertexGetter::getVertex(
|
||||
VPackSlice edge, std::vector<VPackSlice>& result) {
|
||||
VPackSlice cmp = result.back();
|
||||
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 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.emplace_back(from);
|
||||
} else {
|
||||
result.emplace_back(edge.get(StaticStrings::ToString));
|
||||
}
|
||||
// This should never be reached
|
||||
result = "";
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
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() {
|
||||
// Nothing to do here. Subclass has to clear list of already returned vertices.
|
||||
}
|
||||
|
||||
bool ClusterTraverser::UniqueVertexGetter::getVertex(
|
||||
std::string const& edgeId, std::string const& vertexId, size_t depth,
|
||||
std::string& result) {
|
||||
|
||||
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;
|
||||
}
|
||||
VPackSlice edge, std::vector<VPackSlice>& result) {
|
||||
VPackSlice toAdd = edge.get(StaticStrings::FromString);
|
||||
VPackSlice cmp = result.back();
|
||||
|
||||
if (arangodb::basics::VelocyPackHelper::compare(toAdd, cmp, false) == 0) {
|
||||
toAdd = 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(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
|
||||
result = "";
|
||||
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() {
|
||||
_returnedVertices.clear();
|
||||
}
|
||||
|
@ -228,7 +263,7 @@ void ClusterTraverser::ClusterEdgeGetter::getEdge(
|
|||
}
|
||||
|
||||
void ClusterTraverser::ClusterEdgeGetter::getAllEdges(
|
||||
std::string const& startVertex, std::unordered_set<std::string>& result,
|
||||
VPackSlice startVertex, std::unordered_set<VPackSlice>& result,
|
||||
size_t depth) {
|
||||
std::string collName;
|
||||
TRI_edge_direction_e dir;
|
||||
|
@ -300,16 +335,14 @@ void ClusterTraverser::ClusterEdgeGetter::getAllEdges(
|
|||
|
||||
void ClusterTraverser::setStartVertex(std::string const& id) {
|
||||
_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;
|
||||
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()) {
|
||||
size_t firstSlash = id.find("/");
|
||||
if (firstSlash == std::string::npos ||
|
||||
|
@ -322,7 +355,7 @@ void ClusterTraverser::setStartVertex(std::string const& id) {
|
|||
std::unordered_set<std::string> vertexToFetch;
|
||||
vertexToFetch.emplace(id);
|
||||
fetchVertices(vertexToFetch, 0); // this inserts the vertex
|
||||
it = _vertices.find(id);
|
||||
it = _vertices.find(idSlice);
|
||||
if (it == _vertices.end()) {
|
||||
// We can stop here. The start vertex does not match condition.
|
||||
++_filteredPaths;
|
||||
|
@ -334,6 +367,16 @@ void ClusterTraverser::setStartVertex(std::string const& id) {
|
|||
if (_opts.evaluateVertexExpression(VPackSlice(it->second->data()), 0)) {
|
||||
// We can stop here. The start vertex does not match condition
|
||||
_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(
|
||||
std::string const& startVertex, std::unordered_set<std::string>& result,
|
||||
VPackSlice startVertex, std::unordered_set<VPackSlice>& result,
|
||||
size_t depth) {
|
||||
return _edgeGetter->getAllEdges(startVertex, result, depth);
|
||||
}
|
||||
|
||||
bool ClusterTraverser::getVertex(std::string const& edgeId,
|
||||
std::string const& vertexId, size_t depth,
|
||||
std::string& result) {
|
||||
return _vertexGetter->getVertex(edgeId, vertexId, depth, result);
|
||||
bool ClusterTraverser::getVertex(VPackSlice edge,
|
||||
std::vector<VPackSlice>& result) {
|
||||
return _vertexGetter->getVertex(edge, 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) {
|
||||
_readDocuments += verticesToFetch.size();
|
||||
|
||||
|
@ -400,11 +448,6 @@ bool ClusterTraverser::vertexMatchesCondition(
|
|||
|
||||
bool ClusterTraverser::next() {
|
||||
TRI_ASSERT(!_done);
|
||||
if (_pruneNext) {
|
||||
_pruneNext = false;
|
||||
_enumerator->prune();
|
||||
}
|
||||
TRI_ASSERT(!_pruneNext);
|
||||
return _enumerator->next();
|
||||
/*
|
||||
if (_opts.useBreadthFirst &&
|
||||
|
@ -430,26 +473,25 @@ bool ClusterTraverser::next() {
|
|||
*/
|
||||
}
|
||||
|
||||
aql::AqlValue ClusterTraverser::fetchVertexData(std::string const& id) {
|
||||
auto cached = _vertices.find(id);
|
||||
aql::AqlValue ClusterTraverser::fetchVertexData(VPackSlice idString) {
|
||||
TRI_ASSERT(idString.isString());
|
||||
auto cached = _vertices.find(idString);
|
||||
// All vertices are cached!!
|
||||
TRI_ASSERT(cached != _vertices.end());
|
||||
return aql::AqlValue((*cached).second->data());
|
||||
}
|
||||
|
||||
aql::AqlValue ClusterTraverser::fetchEdgeData(std::string const& id) {
|
||||
auto cached = _edges.find(id);
|
||||
// All edges are cached!!
|
||||
TRI_ASSERT(cached != _edges.end());
|
||||
return aql::AqlValue((*cached).second->data());
|
||||
aql::AqlValue ClusterTraverser::fetchEdgeData(VPackSlice edge) {
|
||||
return aql::AqlValue(edge);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Function to add the real data of a vertex into a velocypack builder
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ClusterTraverser::addVertexToVelocyPack(std::string const& id,
|
||||
arangodb::velocypack::Builder& result) {
|
||||
void ClusterTraverser::addVertexToVelocyPack(VPackSlice id,
|
||||
VPackBuilder& result) {
|
||||
TRI_ASSERT(id.isString());
|
||||
auto cached = _vertices.find(id);
|
||||
// All vertices are cached!!
|
||||
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
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ClusterTraverser::addEdgeToVelocyPack(std::string const& id,
|
||||
void ClusterTraverser::addEdgeToVelocyPack(arangodb::velocypack::Slice edge,
|
||||
arangodb::velocypack::Builder& result) {
|
||||
auto cached = _edges.find(id);
|
||||
// All edges are cached!!
|
||||
TRI_ASSERT(cached != _edges.end());
|
||||
result.add(VPackSlice((*cached).second->data()));
|
||||
result.add(edge);
|
||||
}
|
||||
|
||||
aql::AqlValue ClusterTraverser::lastVertexToAqlValue() {
|
||||
|
|
|
@ -56,7 +56,7 @@ class ClusterTraverser final : public Traverser {
|
|||
~ClusterTraverser() {
|
||||
}
|
||||
|
||||
void setStartVertex(std::string const&) override;
|
||||
void setStartVertex(std::string const& id) override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @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
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void getAllEdges(std::string const&, std::unordered_set<std::string>&,
|
||||
void getAllEdges(arangodb::velocypack::Slice,
|
||||
std::unordered_set<arangodb::velocypack::Slice>&,
|
||||
size_t) override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Function to load the other sides vertex of an edge
|
||||
/// 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,
|
||||
std::string&) override;
|
||||
bool getVertex(arangodb::velocypack::Slice,
|
||||
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;
|
||||
|
||||
|
@ -111,26 +117,26 @@ class ClusterTraverser final : public Traverser {
|
|||
/// @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
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void addVertexToVelocyPack(std::string const&,
|
||||
void addVertexToVelocyPack(arangodb::velocypack::Slice,
|
||||
arangodb::velocypack::Builder&) override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @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;
|
||||
|
||||
private:
|
||||
|
@ -147,11 +153,15 @@ class ClusterTraverser final : public Traverser {
|
|||
|
||||
virtual ~VertexGetter() = default;
|
||||
|
||||
virtual bool getVertex(std::string const&, std::string const&, size_t,
|
||||
std::string&);
|
||||
virtual bool getVertex(arangodb::velocypack::Slice,
|
||||
std::vector<arangodb::velocypack::Slice>&);
|
||||
|
||||
virtual bool getSingleVertex(arangodb::velocypack::Slice,
|
||||
arangodb::velocypack::Slice, size_t,
|
||||
arangodb::velocypack::Slice&);
|
||||
virtual void reset();
|
||||
|
||||
virtual void setStartVertex(std::string const&) {}
|
||||
virtual void setStartVertex(arangodb::velocypack::Slice) {}
|
||||
|
||||
protected:
|
||||
ClusterTraverser* _traverser;
|
||||
|
@ -164,17 +174,21 @@ class ClusterTraverser final : public Traverser {
|
|||
|
||||
~UniqueVertexGetter() = default;
|
||||
|
||||
bool getVertex(std::string const&, std::string const&, size_t,
|
||||
std::string&) override;
|
||||
bool getVertex(arangodb::velocypack::Slice,
|
||||
std::vector<arangodb::velocypack::Slice>&) override;
|
||||
|
||||
bool getSingleVertex(arangodb::velocypack::Slice,
|
||||
arangodb::velocypack::Slice, size_t,
|
||||
arangodb::velocypack::Slice&) override;
|
||||
|
||||
void reset() override;
|
||||
|
||||
void setStartVertex(std::string const& id) override {
|
||||
void setStartVertex(arangodb::velocypack::Slice id) override {
|
||||
_returnedVertices.emplace(id);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_set<std::string> _returnedVertices;
|
||||
std::unordered_set<arangodb::velocypack::Slice> _returnedVertices;
|
||||
};
|
||||
|
||||
class ClusterEdgeGetter {
|
||||
|
@ -185,7 +199,9 @@ class ClusterTraverser final : public Traverser {
|
|||
void getEdge(std::string const&, std::vector<std::string>&, 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:
|
||||
ClusterTraverser* _traverser;
|
||||
|
@ -197,7 +213,7 @@ class ClusterTraverser final : public Traverser {
|
|||
std::shared_ptr<arangodb::velocypack::Buffer<uint8_t>>>
|
||||
_edges;
|
||||
|
||||
std::unordered_map<std::string,
|
||||
std::unordered_map<arangodb::velocypack::Slice,
|
||||
std::shared_ptr<arangodb::velocypack::Buffer<uint8_t>>>
|
||||
_vertices;
|
||||
|
||||
|
|
|
@ -32,78 +32,53 @@ using TraverserOptions = arangodb::traverser::TraverserOptions;
|
|||
bool DepthFirstEnumerator::next() {
|
||||
if (_isFirst) {
|
||||
_isFirst = false;
|
||||
// Initialze the first cursor
|
||||
_opts->nextCursor(_enumeratedPath.vertices.back(), 0);
|
||||
if (_opts->minDepth == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (_enumeratedPath.edges.size() == _opts->maxDepth) {
|
||||
// we have reached the maximal search depth.
|
||||
// We can prune this path and go to the next.
|
||||
prune();
|
||||
if (_enumeratedPath.vertices.empty()) {
|
||||
// We are done;
|
||||
return false;
|
||||
}
|
||||
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 (true) {
|
||||
if (_lastEdges.empty()) {
|
||||
_enumeratedPath.edges.clear();
|
||||
_enumeratedPath.vertices.clear();
|
||||
return false;
|
||||
}
|
||||
_traverser->getEdge(_enumeratedPath.vertices.back(), _enumeratedPath.edges,
|
||||
_lastEdges.top(), _lastEdgesIdx.top());
|
||||
if (_lastEdges.top() != nullptr) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
while (!_edgeCursors.empty()) {
|
||||
auto cursor = _edgeCursors.top();
|
||||
if (cursor->next(_enumeratedPath.edges)) {
|
||||
#warning not yet finished
|
||||
// TODO UNIQUE_PATH
|
||||
// We have to check if edge and vertex is valid
|
||||
if (_traverser->getVertex(_enumeratedPath.edges.back(),
|
||||
_enumeratedPath.vertices)) {
|
||||
// case both are valid.
|
||||
// TODO UNIQUE_PATH
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
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()) {
|
||||
// Vertex Invalid. Revoke edge
|
||||
_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() {
|
||||
|
@ -137,7 +112,7 @@ arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(arangodb::velocypac
|
|||
}
|
||||
|
||||
BreadthFirstEnumerator::BreadthFirstEnumerator(Traverser* traverser,
|
||||
std::string const& startVertex,
|
||||
VPackSlice startVertex,
|
||||
TraverserOptions const* opts)
|
||||
: PathEnumerator(traverser, startVertex, opts),
|
||||
_schreierIndex(1),
|
||||
|
@ -213,10 +188,10 @@ bool BreadthFirstEnumerator::next() {
|
|||
bool shouldReturnPath = _currentDepth + 1 >= _opts->minDepth;
|
||||
if (!_tmpEdges.empty()) {
|
||||
bool didInsert = false;
|
||||
std::string v;
|
||||
VPackSlice v;
|
||||
for (auto const& e : _tmpEdges) {
|
||||
bool valid =
|
||||
_traverser->getVertex(e, nextVertex, _currentDepth, v);
|
||||
_traverser->getSingleVertex(e, nextVertex, _currentDepth, v);
|
||||
if (valid) {
|
||||
auto step = std::make_unique<PathStep>(nextIdx, e, v);
|
||||
_schreier.emplace_back(step.get());
|
||||
|
@ -251,12 +226,6 @@ bool BreadthFirstEnumerator::next() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void BreadthFirstEnumerator::prune() {
|
||||
if (!_nextDepth.empty()) {
|
||||
_nextDepth.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Optimize this. Remove enumeratedPath
|
||||
// All can be read from schreier vector directly
|
||||
arangodb::aql::AqlValue BreadthFirstEnumerator::lastVertexToAqlValue() {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#define ARANGODB_VOCBASE_PATHENUMERATOR_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include <velocypack/Slice.h>
|
||||
#include <stack>
|
||||
|
||||
namespace arangodb {
|
||||
|
@ -37,12 +38,13 @@ class Builder;
|
|||
}
|
||||
|
||||
namespace traverser {
|
||||
class EdgeCursor;
|
||||
class Traverser;
|
||||
struct TraverserOptions;
|
||||
|
||||
struct EnumeratedPath {
|
||||
std::vector<std::string> edges;
|
||||
std::vector<std::string> vertices;
|
||||
std::vector<arangodb::velocypack::Slice> edges;
|
||||
std::vector<arangodb::velocypack::Slice> vertices;
|
||||
EnumeratedPath() {}
|
||||
};
|
||||
|
||||
|
@ -79,7 +81,7 @@ class PathEnumerator {
|
|||
EnumeratedPath _enumeratedPath;
|
||||
|
||||
public:
|
||||
PathEnumerator(Traverser* traverser, std::string const& startVertex,
|
||||
PathEnumerator(Traverser* traverser, arangodb::velocypack::Slice startVertex,
|
||||
TraverserOptions const* opts)
|
||||
: _traverser(traverser), _isFirst(true), _opts(opts) {
|
||||
_enumeratedPath.vertices.push_back(startVertex);
|
||||
|
@ -96,13 +98,6 @@ class PathEnumerator {
|
|||
|
||||
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 lastEdgeToAqlValue() = 0;
|
||||
virtual aql::AqlValue pathToAqlValue(arangodb::velocypack::Builder&) = 0;
|
||||
|
@ -111,30 +106,20 @@ class PathEnumerator {
|
|||
class DepthFirstEnumerator final : public PathEnumerator {
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief The pointers returned for edge indexes on this path. Used to
|
||||
/// continue
|
||||
/// the search on respective levels.
|
||||
/// @brief The stack of EdgeCursors to walk through.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::stack<size_t*> _lastEdges;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief An internal index for the edge collection used at each depth level
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::stack<size_t> _lastEdgesIdx;
|
||||
std::stack<EdgeCursor*> _edgeCursors;
|
||||
|
||||
public:
|
||||
DepthFirstEnumerator(
|
||||
Traverser* traverser,
|
||||
std::string const& startVertex, TraverserOptions const* opts)
|
||||
: PathEnumerator(traverser, startVertex, opts) {
|
||||
_lastEdges.push(nullptr);
|
||||
_lastEdgesIdx.push(0);
|
||||
TRI_ASSERT(_lastEdges.size() == 1);
|
||||
}
|
||||
DepthFirstEnumerator(Traverser* traverser,
|
||||
arangodb::velocypack::Slice startVertex,
|
||||
TraverserOptions const* opts)
|
||||
: PathEnumerator(traverser, startVertex, opts) {}
|
||||
|
||||
~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.
|
||||
|
@ -147,8 +132,6 @@ class DepthFirstEnumerator final : public PathEnumerator {
|
|||
/// any path having this prefix anymore.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void prune() override;
|
||||
|
||||
aql::AqlValue lastVertexToAqlValue() override;
|
||||
|
||||
aql::AqlValue lastEdgeToAqlValue() override;
|
||||
|
@ -166,17 +149,17 @@ class BreadthFirstEnumerator final : public PathEnumerator {
|
|||
|
||||
struct PathStep {
|
||||
size_t sourceIdx;
|
||||
std::string edge;
|
||||
std::string vertex;
|
||||
arangodb::velocypack::Slice edge;
|
||||
arangodb::velocypack::Slice vertex;
|
||||
|
||||
private:
|
||||
PathStep() {}
|
||||
|
||||
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,
|
||||
std::string const& vertex)
|
||||
PathStep(size_t sourceIdx, arangodb::velocypack::Slice edge,
|
||||
arangodb::velocypack::Slice 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
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unordered_set<std::string> _tmpEdges;
|
||||
std::unordered_set<arangodb::velocypack::Slice> _tmpEdges;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Marker for the search depth. Used to abort searching.
|
||||
|
@ -247,7 +230,8 @@ class BreadthFirstEnumerator final : public PathEnumerator {
|
|||
|
||||
public:
|
||||
BreadthFirstEnumerator(Traverser* traverser,
|
||||
std::string const& startVertex, TraverserOptions const* opts);
|
||||
arangodb::velocypack::Slice startVertex,
|
||||
TraverserOptions const* opts);
|
||||
|
||||
~BreadthFirstEnumerator() {
|
||||
for (auto& it : _schreier) {
|
||||
|
@ -266,8 +250,6 @@ class BreadthFirstEnumerator final : public PathEnumerator {
|
|||
/// any path having this prefix anymore.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void prune() override;
|
||||
|
||||
aql::AqlValue lastVertexToAqlValue() override;
|
||||
|
||||
aql::AqlValue lastEdgeToAqlValue() override;
|
||||
|
|
|
@ -56,6 +56,15 @@ static int FetchDocumentById(arangodb::Transaction* trx,
|
|||
return res;
|
||||
}
|
||||
|
||||
SingleServerEdgeCursor::SingleServerEdgeCursor() {
|
||||
#warning TODO Implement
|
||||
};
|
||||
|
||||
bool SingleServerEdgeCursor::next(std::vector<VPackSlice>& result) {
|
||||
#warning TODO Implement
|
||||
return false;
|
||||
}
|
||||
|
||||
SingleServerTraverser::SingleServerTraverser(TraverserOptions& opts,
|
||||
arangodb::Transaction* trx)
|
||||
: Traverser(opts), _trx(trx) {
|
||||
|
@ -77,8 +86,9 @@ bool SingleServerTraverser::edgeMatchesConditions(VPackSlice e, size_t depth) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SingleServerTraverser::vertexMatchesConditions(std::string const& v,
|
||||
bool SingleServerTraverser::vertexMatchesConditions(VPackSlice v,
|
||||
size_t depth) {
|
||||
TRI_ASSERT(v.isString());
|
||||
#warning it is possible to not fetch the vertex if no check is required.
|
||||
aql::AqlValue vertex = fetchVertexData(v);
|
||||
if (!_opts.evaluateVertexExpression(vertex.slice(), depth)) {
|
||||
|
@ -88,12 +98,14 @@ bool SingleServerTraverser::vertexMatchesConditions(std::string const& v,
|
|||
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);
|
||||
|
||||
if (it == _vertices.end()) {
|
||||
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;
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
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());
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
TRI_ASSERT(it != _edges.end());
|
||||
return aql::AqlValue((*it).second, aql::AqlValueFromMasterPointer());
|
||||
*/
|
||||
}
|
||||
|
||||
void SingleServerTraverser::addVertexToVelocyPack(std::string const& id,
|
||||
arangodb::velocypack::Builder& result) {
|
||||
void SingleServerTraverser::addVertexToVelocyPack(VPackSlice id,
|
||||
VPackBuilder& result) {
|
||||
TRI_ASSERT(id.isString());
|
||||
auto it = _vertices.find(id);
|
||||
|
||||
if (it == _vertices.end()) {
|
||||
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;
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
result.add(basics::VelocyPackHelper::NullValue());
|
||||
|
@ -134,62 +152,106 @@ void SingleServerTraverser::addVertexToVelocyPack(std::string const& id,
|
|||
}
|
||||
}
|
||||
|
||||
void SingleServerTraverser::addEdgeToVelocyPack(std::string const& id,
|
||||
arangodb::velocypack::Builder& result) {
|
||||
auto it = _edges.find(id);
|
||||
|
||||
TRI_ASSERT(it != _edges.end());
|
||||
result.addExternal((*it).second);
|
||||
void SingleServerTraverser::addEdgeToVelocyPack(VPackSlice edge,
|
||||
VPackBuilder& result) {
|
||||
result.addExternal(edge.begin());
|
||||
}
|
||||
|
||||
bool SingleServerTraverser::VertexGetter::getVertex(std::string const& edge,
|
||||
std::string const& vertex,
|
||||
size_t depth,
|
||||
std::string& result) {
|
||||
auto it = _traverser->_edges.find(edge);
|
||||
TRI_ASSERT(it != _traverser->_edges.end());
|
||||
VPackSlice v((*it).second);
|
||||
// NOTE: We assume that we only have valid edges.
|
||||
VPackSlice from = Transaction::extractFromFromDocument(v);
|
||||
if (from.isEqualString(vertex)) {
|
||||
result = Transaction::extractToFromDocument(v).copyString();
|
||||
bool SingleServerTraverser::VertexGetter::getVertex(
|
||||
VPackSlice edge, std::vector<VPackSlice>& result) {
|
||||
VPackSlice cmp = result.back();
|
||||
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.emplace_back(from);
|
||||
} else {
|
||||
result = from.copyString();
|
||||
}
|
||||
if (!_traverser->vertexMatchesConditions(result, depth)) {
|
||||
return false;
|
||||
result.emplace_back(Transaction::extractToFromDocument(edge));
|
||||
}
|
||||
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(
|
||||
std::string const& edge, std::string const& vertex, size_t depth,
|
||||
std::string& result) {
|
||||
VPackSlice edge, std::vector<VPackSlice>& 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);
|
||||
TRI_ASSERT(it != _traverser->_edges.end());
|
||||
VPackSlice v((*it).second);
|
||||
// NOTE: We assume that we only have valid edges.
|
||||
VPackSlice from = Transaction::extractFromFromDocument(v);
|
||||
if (from.isEqualString(vertex)) {
|
||||
result = Transaction::extractToFromDocument(v).copyString();
|
||||
#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(toAdd) != _returnedVertices.end()) {
|
||||
// This vertex is not unique.
|
||||
++_traverser->_filteredPaths;
|
||||
return false;
|
||||
} else {
|
||||
result = from.copyString();
|
||||
_returnedVertices.emplace(toAdd);
|
||||
result.emplace_back(toAdd);
|
||||
return true;
|
||||
}
|
||||
if (_returnedVertices.find(result) != _returnedVertices.end()) {
|
||||
return false;
|
||||
}
|
||||
if (!_traverser->vertexMatchesConditions(result, depth)) {
|
||||
return false;
|
||||
}
|
||||
_returnedVertices.emplace(result);
|
||||
return true;
|
||||
|
||||
// This should never be reached
|
||||
return false;
|
||||
}
|
||||
|
||||
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();
|
||||
// The startVertex always counts as visited!
|
||||
_returnedVertices.emplace(startVertex);
|
||||
|
@ -198,6 +260,11 @@ void SingleServerTraverser::UniqueVertexGetter::reset(std::string const& startVe
|
|||
void SingleServerTraverser::setStartVertex(std::string const& v) {
|
||||
_pruneNext = false;
|
||||
|
||||
#warning Who is responsible for this builder?!
|
||||
VPackBuilder tmp;
|
||||
tmp.add(VPackValue(v));
|
||||
VPackSlice idSlice = tmp.slice();
|
||||
|
||||
TRI_doc_mptr_t vertex;
|
||||
int result = FetchDocumentById(_trx, v, &vertex);
|
||||
++_readDocuments;
|
||||
|
@ -207,19 +274,19 @@ void SingleServerTraverser::setStartVertex(std::string const& v) {
|
|||
_done = true;
|
||||
return;
|
||||
}
|
||||
VPackSlice vertexSlice(vertex.vpack());
|
||||
|
||||
_vertices.emplace(v, vertex.vpack());
|
||||
if (!_opts.evaluateVertexExpression(VPackSlice(vertex.vpack()), 0)) {
|
||||
if (!_opts.evaluateVertexExpression(vertexSlice, 0)) {
|
||||
// Start vertex invalid
|
||||
++_filteredPaths;
|
||||
_done = true;
|
||||
return;
|
||||
}
|
||||
_vertexGetter->reset(v);
|
||||
_vertexGetter->reset(idSlice);
|
||||
if (_opts.useBreadthFirst) {
|
||||
_enumerator.reset(new BreadthFirstEnumerator(this, v, &_opts));
|
||||
_enumerator.reset(new BreadthFirstEnumerator(this, vertexSlice, &_opts));
|
||||
} else {
|
||||
_enumerator.reset(new DepthFirstEnumerator(this, v, &_opts));
|
||||
_enumerator.reset(new DepthFirstEnumerator(this, vertexSlice, &_opts));
|
||||
}
|
||||
_done = false;
|
||||
}
|
||||
|
@ -229,26 +296,25 @@ void SingleServerTraverser::getEdge(std::string const& startVertex,
|
|||
size_t*& last, size_t& eColIdx) {
|
||||
return _edgeGetter->getEdge(startVertex, edges, last, eColIdx);
|
||||
}
|
||||
|
||||
|
||||
void SingleServerTraverser::getAllEdges(
|
||||
std::string const& startVertex, std::unordered_set<std::string>& edges,
|
||||
size_t depth) {
|
||||
arangodb::velocypack::Slice startVertex,
|
||||
std::unordered_set<arangodb::velocypack::Slice>& edges, size_t depth) {
|
||||
return _edgeGetter->getAllEdges(startVertex, edges, depth);
|
||||
}
|
||||
|
||||
bool SingleServerTraverser::getVertex(std::string const& edge,
|
||||
std::string const& vertex, size_t depth,
|
||||
std::string& result) {
|
||||
return _vertexGetter->getVertex(edge, vertex, depth, result);
|
||||
bool SingleServerTraverser::getVertex(VPackSlice edge,
|
||||
std::vector<VPackSlice>& result) {
|
||||
return _vertexGetter->getVertex(edge, result);
|
||||
}
|
||||
|
||||
bool SingleServerTraverser::getSingleVertex(VPackSlice edge, VPackSlice vertex,
|
||||
size_t depth, VPackSlice& result) {
|
||||
return _vertexGetter->getSingleVertex(edge, vertex, depth, result);
|
||||
}
|
||||
|
||||
bool SingleServerTraverser::next() {
|
||||
TRI_ASSERT(!_done);
|
||||
if (_pruneNext) {
|
||||
_pruneNext = false;
|
||||
_enumerator->prune();
|
||||
}
|
||||
TRI_ASSERT(!_pruneNext);
|
||||
bool res = _enumerator->next();
|
||||
if (!res) {
|
||||
_done = true;
|
||||
|
@ -425,9 +491,8 @@ void SingleServerTraverser::EdgeGetter::getEdge(std::string const& startVertex,
|
|||
}
|
||||
|
||||
void SingleServerTraverser::EdgeGetter::getAllEdges(
|
||||
std::string const& startVertex, std::unordered_set<std::string>& edges,
|
||||
VPackSlice startVertex, std::unordered_set<VPackSlice>& edges,
|
||||
size_t depth) {
|
||||
|
||||
#warning reimplement
|
||||
/*
|
||||
size_t idxId = 0;
|
||||
|
|
|
@ -37,8 +37,20 @@ namespace traverser {
|
|||
|
||||
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:
|
||||
|
||||
class VertexGetter {
|
||||
|
@ -48,9 +60,14 @@ class SingleServerTraverser final : public Traverser {
|
|||
|
||||
virtual ~VertexGetter() = default;
|
||||
|
||||
virtual bool getVertex(std::string const&, std::string const&, size_t,
|
||||
std::string&);
|
||||
virtual void reset(std::string const&);
|
||||
virtual bool getVertex(arangodb::velocypack::Slice,
|
||||
std::vector<arangodb::velocypack::Slice>&);
|
||||
|
||||
virtual bool getSingleVertex(arangodb::velocypack::Slice,
|
||||
arangodb::velocypack::Slice, size_t,
|
||||
arangodb::velocypack::Slice&);
|
||||
|
||||
virtual void reset(arangodb::velocypack::Slice);
|
||||
|
||||
protected:
|
||||
SingleServerTraverser* _traverser;
|
||||
|
@ -63,13 +80,17 @@ class SingleServerTraverser final : public Traverser {
|
|||
|
||||
~UniqueVertexGetter() = default;
|
||||
|
||||
bool getVertex(std::string const&, std::string const&, size_t,
|
||||
std::string&) override;
|
||||
bool getVertex(arangodb::velocypack::Slice,
|
||||
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:
|
||||
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>&,
|
||||
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:
|
||||
|
||||
|
@ -193,16 +215,22 @@ public:
|
|||
/// @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;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Function to load the other sides vertex of an edge
|
||||
/// 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,
|
||||
std::string&) override;
|
||||
bool getVertex(arangodb::velocypack::Slice,
|
||||
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.
|
||||
|
@ -239,32 +267,32 @@ public:
|
|||
/// @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
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void addVertexToVelocyPack(std::string const&,
|
||||
void addVertexToVelocyPack(arangodb::velocypack::Slice,
|
||||
arangodb::velocypack::Builder&) override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @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;
|
||||
|
||||
private:
|
||||
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;
|
||||
|
||||
|
@ -279,7 +307,7 @@ public:
|
|||
/// 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
|
||||
|
|
|
@ -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 {
|
||||
#warning This has to be implemented.
|
||||
return true;
|
||||
|
@ -130,6 +81,11 @@ bool arangodb::traverser::TraverserOptions::evaluateVertexExpression(arangodb::v
|
|||
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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -41,10 +41,24 @@ class Slice;
|
|||
}
|
||||
|
||||
namespace aql {
|
||||
struct AstNode;
|
||||
class TraversalNode;
|
||||
}
|
||||
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 {
|
||||
public:
|
||||
bool isEdgeAccess;
|
||||
|
@ -207,11 +221,11 @@ struct TraverserOptions {
|
|||
|
||||
private:
|
||||
arangodb::Transaction* _trx;
|
||||
std::vector<std::string> _collections;
|
||||
std::vector<TRI_edge_direction_e> _directions;
|
||||
std::vector<arangodb::Transaction::IndexHandle> _baseIndexHandles;
|
||||
std::unordered_map<size_t, std::vector<arangodb::Transaction::IndexHandle>>
|
||||
_depthIndexHandles;
|
||||
std::vector<aql::AstNode const*> _baseConditions;
|
||||
std::unordered_map<size_t,
|
||||
std::pair<std::vector<arangodb::Transaction::IndexHandle>,
|
||||
std::vector<aql::AstNode const*>>> _depthIndexHandles;
|
||||
|
||||
public:
|
||||
uint64_t minDepth;
|
||||
|
@ -235,19 +249,11 @@ struct TraverserOptions {
|
|||
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 evaluateVertexExpression(arangodb::velocypack::Slice, size_t) const;
|
||||
|
||||
EdgeCursor* nextCursor(arangodb::velocypack::Slice, size_t) const;
|
||||
};
|
||||
|
||||
class Traverser {
|
||||
|
@ -313,17 +319,24 @@ class Traverser {
|
|||
/// @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;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Function to load the other sides vertex of an edge
|
||||
/// 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,
|
||||
std::string&) = 0;
|
||||
virtual bool getVertex(arangodb::velocypack::Slice,
|
||||
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
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -419,26 +432,26 @@ class Traverser {
|
|||
/// @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
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void addVertexToVelocyPack(std::string const&,
|
||||
virtual void addVertexToVelocyPack(arangodb::velocypack::Slice,
|
||||
arangodb::velocypack::Builder&) = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @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;
|
||||
};
|
||||
} // traverser
|
||||
|
|
Loading…
Reference in New Issue