mirror of https://gitee.com/bigwinds/arangodb
Simplified AqlTraverser Setup code by moving shared logic into the TraverserOptions.
This commit is contained in:
parent
b09dfaa323
commit
212de2b0d1
|
@ -900,7 +900,6 @@ void TraversalNode::prepareOptions() {
|
|||
_options->_tmpVar = _tmpObjVariable;
|
||||
|
||||
size_t numEdgeColls = _edgeColls.size();
|
||||
bool res = false;
|
||||
TraversalEdgeConditionBuilder globalEdgeConditionBuilder(this);
|
||||
|
||||
for (auto& it : _globalEdgeConditions) {
|
||||
|
@ -908,78 +907,30 @@ void TraversalNode::prepareOptions() {
|
|||
}
|
||||
|
||||
Ast* ast = _plan->getAst();
|
||||
auto trx = ast->query()->trx();
|
||||
|
||||
_options->_baseLookupInfos.reserve(numEdgeColls);
|
||||
// Compute Edge Indexes. First default indexes:
|
||||
for (size_t i = 0; i < numEdgeColls; ++i) {
|
||||
std::string usedField;
|
||||
auto dir = _directions[i];
|
||||
// TODO we can optimize here. indexCondition and Expression could be
|
||||
// made non-overlapping.
|
||||
traverser::TraverserOptions::LookupInfo info;
|
||||
switch (dir) {
|
||||
case TRI_EDGE_IN:
|
||||
usedField = StaticStrings::ToString;
|
||||
info.indexCondition =
|
||||
globalEdgeConditionBuilder.getInboundCondition()->clone(ast);
|
||||
_options->addLookupInfo(
|
||||
ast, _edgeColls[i]->getName(), StaticStrings::ToString,
|
||||
globalEdgeConditionBuilder.getInboundCondition()->clone(ast));
|
||||
break;
|
||||
case TRI_EDGE_OUT:
|
||||
usedField = StaticStrings::FromString;
|
||||
info.indexCondition =
|
||||
globalEdgeConditionBuilder.getOutboundCondition()->clone(ast);
|
||||
_options->addLookupInfo(
|
||||
ast, _edgeColls[i]->getName(), StaticStrings::FromString,
|
||||
globalEdgeConditionBuilder.getOutboundCondition()->clone(ast));
|
||||
break;
|
||||
case TRI_EDGE_ANY:
|
||||
TRI_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
info.expression = new Expression(ast, info.indexCondition->clone(ast));
|
||||
res = trx->getBestIndexHandleForFilterCondition(
|
||||
_edgeColls[i]->getName(), info.indexCondition, _tmpObjVariable, 1000,
|
||||
info.idxHandles[0]);
|
||||
TRI_ASSERT(res); // Right now we have an enforced edge index which will
|
||||
// always fit.
|
||||
if (!res) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "expected edge index not found");
|
||||
}
|
||||
|
||||
// We now have to check if we need _from / _to inside the index lookup and which position
|
||||
// it is used in. Such that the traverser can update the respective string value
|
||||
// in-place
|
||||
std::pair<Variable const*, std::vector<basics::AttributeName>> pathCmp;
|
||||
for (size_t i = 0; i < info.indexCondition->numMembers(); ++i) {
|
||||
// We search through the nary-and and look for EQ - _from/_to
|
||||
auto eq = info.indexCondition->getMemberUnchecked(i);
|
||||
if (eq->type != NODE_TYPE_OPERATOR_BINARY_EQ) {
|
||||
// No equality. Skip
|
||||
continue;
|
||||
}
|
||||
TRI_ASSERT(eq->numMembers() == 2);
|
||||
// It is sufficient to only check member one.
|
||||
// We build the condition this way.
|
||||
auto mem = eq->getMemberUnchecked(0);
|
||||
if (mem->isAttributeAccessForVariable(pathCmp)) {
|
||||
if (pathCmp.first != _tmpObjVariable) {
|
||||
continue;
|
||||
}
|
||||
if (pathCmp.second.size() == 1 && pathCmp.second[0].name == usedField) {
|
||||
info.conditionNeedUpdate = true;
|
||||
info.conditionMemberToUpdate = i;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_options->_baseLookupInfos.emplace_back(std::move(info));
|
||||
}
|
||||
|
||||
for (auto& it : _edgeConditions) {
|
||||
auto ins = _options->_depthLookupInfo.emplace(
|
||||
it.first, std::vector<traverser::TraverserOptions::LookupInfo>());
|
||||
uint64_t depth = it.first;
|
||||
// We probably have to adopt minDepth. We cannot fulfill a condition of larger depth anyway
|
||||
TRI_ASSERT(ins.second);
|
||||
auto& infos = ins.first->second;
|
||||
infos.reserve(numEdgeColls);
|
||||
auto& builder = it.second;
|
||||
|
||||
for (auto& it : _globalEdgeConditions) {
|
||||
|
@ -987,64 +938,24 @@ void TraversalNode::prepareOptions() {
|
|||
}
|
||||
|
||||
for (size_t i = 0; i < numEdgeColls; ++i) {
|
||||
std::string usedField;
|
||||
auto dir = _directions[i];
|
||||
// TODO we can optimize here. indexCondition and Expression could be
|
||||
// made non-overlapping.
|
||||
traverser::TraverserOptions::LookupInfo info;
|
||||
switch (dir) {
|
||||
case TRI_EDGE_IN:
|
||||
usedField = StaticStrings::ToString;
|
||||
info.indexCondition = builder->getInboundCondition()->clone(ast);
|
||||
_options->addDepthLookupInfo(
|
||||
ast, _edgeColls[i]->getName(), StaticStrings::ToString,
|
||||
builder->getInboundCondition()->clone(ast), depth);
|
||||
break;
|
||||
case TRI_EDGE_OUT:
|
||||
usedField = StaticStrings::FromString;
|
||||
info.indexCondition = builder->getOutboundCondition()->clone(ast);
|
||||
_options->addDepthLookupInfo(
|
||||
ast, _edgeColls[i]->getName(), StaticStrings::FromString,
|
||||
builder->getOutboundCondition()->clone(ast), depth);
|
||||
break;
|
||||
case TRI_EDGE_ANY:
|
||||
TRI_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
info.expression = new Expression(ast, info.indexCondition->clone(ast));
|
||||
res = trx->getBestIndexHandleForFilterCondition(
|
||||
_edgeColls[i]->getName(), info.indexCondition, _tmpObjVariable, 1000,
|
||||
info.idxHandles[0]);
|
||||
TRI_ASSERT(res); // Right now we have an enforced edge index which will
|
||||
// always fit.
|
||||
if (!res) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "expected edge index not found");
|
||||
}
|
||||
|
||||
// We now have to check if we need _from / _to inside the index lookup and which position
|
||||
// it is used in. Such that the traverser can update the respective string value
|
||||
// in-place
|
||||
|
||||
std::pair<Variable const*, std::vector<basics::AttributeName>> pathCmp;
|
||||
for (size_t i = 0; i < info.indexCondition->numMembers(); ++i) {
|
||||
// We search through the nary-and and look for EQ - _from/_to
|
||||
auto eq = info.indexCondition->getMemberUnchecked(i);
|
||||
if (eq->type != NODE_TYPE_OPERATOR_BINARY_EQ) {
|
||||
// No equality. Skip
|
||||
continue;
|
||||
}
|
||||
TRI_ASSERT(eq->numMembers() == 2);
|
||||
// It is sufficient to only check member one.
|
||||
// We build the condition this way.
|
||||
auto mem = eq->getMemberUnchecked(0);
|
||||
if (mem->isAttributeAccessForVariable(pathCmp)) {
|
||||
if (pathCmp.first != _tmpObjVariable) {
|
||||
continue;
|
||||
}
|
||||
if (pathCmp.second.size() == 1 && pathCmp.second[0].name == usedField) {
|
||||
info.conditionNeedUpdate = true;
|
||||
info.conditionMemberToUpdate = i;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
infos.emplace_back(std::move(info));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,8 +52,8 @@ TraverserOptions::TraverserOptions(transaction::Methods* trx)
|
|||
uniqueVertices(UniquenessLevel::NONE),
|
||||
uniqueEdges(UniquenessLevel::PATH) {}
|
||||
|
||||
TraverserOptions::TraverserOptions(
|
||||
transaction::Methods* trx, VPackSlice const& slice)
|
||||
TraverserOptions::TraverserOptions(transaction::Methods* trx,
|
||||
VPackSlice const& slice)
|
||||
: BaseOptions(trx),
|
||||
_baseVertexExpression(nullptr),
|
||||
_traverser(nullptr),
|
||||
|
@ -89,16 +89,14 @@ TraverserOptions::TraverserOptions(
|
|||
|
||||
tmp = VPackHelper::getStringValue(obj, "uniqueEdges", "");
|
||||
if (tmp == "none") {
|
||||
uniqueEdges =
|
||||
arangodb::traverser::TraverserOptions::UniquenessLevel::NONE;
|
||||
uniqueEdges = arangodb::traverser::TraverserOptions::UniquenessLevel::NONE;
|
||||
} else if (tmp == "global") {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER,
|
||||
"uniqueEdges: 'global' is not supported, "
|
||||
"due to unpredictable results. Use 'path' "
|
||||
"or 'none' instead");
|
||||
} else {
|
||||
uniqueEdges =
|
||||
arangodb::traverser::TraverserOptions::UniquenessLevel::PATH;
|
||||
uniqueEdges = arangodb::traverser::TraverserOptions::UniquenessLevel::PATH;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,8 +231,8 @@ arangodb::traverser::TraverserOptions::TraverserOptions(
|
|||
d, new aql::Expression(query->ast(), info.value));
|
||||
TRI_ASSERT(it.second);
|
||||
#else
|
||||
_vertexExpressions.emplace(
|
||||
d, new aql::Expression(query->ast(), info.value));
|
||||
_vertexExpressions.emplace(d,
|
||||
new aql::Expression(query->ast(), info.value));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -289,7 +287,8 @@ arangodb::traverser::TraverserOptions::~TraverserOptions() {
|
|||
delete _baseVertexExpression;
|
||||
}
|
||||
|
||||
void arangodb::traverser::TraverserOptions::toVelocyPack(VPackBuilder& builder) const {
|
||||
void arangodb::traverser::TraverserOptions::toVelocyPack(
|
||||
VPackBuilder& builder) const {
|
||||
VPackObjectBuilder guard(&builder);
|
||||
|
||||
builder.add("minDepth", VPackValue(minDepth));
|
||||
|
@ -321,7 +320,8 @@ void arangodb::traverser::TraverserOptions::toVelocyPack(VPackBuilder& builder)
|
|||
}
|
||||
}
|
||||
|
||||
void arangodb::traverser::TraverserOptions::toVelocyPackIndexes(VPackBuilder& builder) const {
|
||||
void arangodb::traverser::TraverserOptions::toVelocyPackIndexes(
|
||||
VPackBuilder& builder) const {
|
||||
VPackObjectBuilder guard(&builder);
|
||||
|
||||
// base indexes
|
||||
|
@ -352,7 +352,8 @@ void arangodb::traverser::TraverserOptions::toVelocyPackIndexes(VPackBuilder& bu
|
|||
builder.close();
|
||||
}
|
||||
|
||||
void arangodb::traverser::TraverserOptions::buildEngineInfo(VPackBuilder& result) const {
|
||||
void arangodb::traverser::TraverserOptions::buildEngineInfo(
|
||||
VPackBuilder& result) const {
|
||||
result.openObject();
|
||||
result.add("minDepth", VPackValue(minDepth));
|
||||
result.add("maxDepth", VPackValue(maxDepth));
|
||||
|
@ -386,7 +387,7 @@ void arangodb::traverser::TraverserOptions::buildEngineInfo(VPackBuilder& result
|
|||
|
||||
result.add(VPackValue("baseLookupInfos"));
|
||||
result.openArray();
|
||||
for (auto const& it: _baseLookupInfos) {
|
||||
for (auto const& it : _baseLookupInfos) {
|
||||
it.buildEngineInfo(result);
|
||||
}
|
||||
result.close();
|
||||
|
@ -432,6 +433,18 @@ void arangodb::traverser::TraverserOptions::buildEngineInfo(VPackBuilder& result
|
|||
result.close();
|
||||
}
|
||||
|
||||
void TraverserOptions::addDepthLookupInfo(aql::Ast* ast,
|
||||
std::string const& collectionName,
|
||||
std::string const& attributeName,
|
||||
aql::AstNode* condition,
|
||||
uint64_t depth) {
|
||||
TRI_ASSERT(_depthLookupInfo.find(depth) == _depthLookupInfo.end());
|
||||
auto ins = _depthLookupInfo.emplace(depth, std::vector<LookupInfo>());
|
||||
TRI_ASSERT(ins.second); // The insert should always work
|
||||
injectLookupInfoInList(ins.first->second, ast, collectionName,
|
||||
attributeName, condition);
|
||||
}
|
||||
|
||||
bool arangodb::traverser::TraverserOptions::vertexHasFilter(
|
||||
uint64_t depth) const {
|
||||
if (_baseVertexExpression != nullptr) {
|
||||
|
@ -441,8 +454,8 @@ bool arangodb::traverser::TraverserOptions::vertexHasFilter(
|
|||
}
|
||||
|
||||
bool arangodb::traverser::TraverserOptions::evaluateEdgeExpression(
|
||||
arangodb::velocypack::Slice edge, StringRef vertexId,
|
||||
uint64_t depth, size_t cursorId) const {
|
||||
arangodb::velocypack::Slice edge, StringRef vertexId, uint64_t depth,
|
||||
size_t cursorId) const {
|
||||
if (_isCoordinator) {
|
||||
// The Coordinator never checks conditions. The DBServer is responsible!
|
||||
return true;
|
||||
|
@ -513,10 +526,12 @@ arangodb::traverser::TraverserOptions::nextCursor(ManagedDocumentResult* mmdr,
|
|||
}
|
||||
|
||||
arangodb::traverser::EdgeCursor*
|
||||
arangodb::traverser::TraverserOptions::nextCursorLocal(ManagedDocumentResult* mmdr,
|
||||
StringRef vid, uint64_t depth, std::vector<LookupInfo>& list) {
|
||||
arangodb::traverser::TraverserOptions::nextCursorLocal(
|
||||
ManagedDocumentResult* mmdr, StringRef vid, uint64_t depth,
|
||||
std::vector<LookupInfo>& list) {
|
||||
TRI_ASSERT(mmdr != nullptr);
|
||||
auto allCursor = std::make_unique<SingleServerEdgeCursor>(mmdr, this, list.size());
|
||||
auto allCursor =
|
||||
std::make_unique<SingleServerEdgeCursor>(mmdr, this, list.size());
|
||||
auto& opCursors = allCursor->getCursors();
|
||||
for (auto& info : list) {
|
||||
auto& node = info.indexCondition;
|
||||
|
@ -535,8 +550,8 @@ arangodb::traverser::TraverserOptions::nextCursorLocal(ManagedDocumentResult* mm
|
|||
std::vector<OperationCursor*> csrs;
|
||||
csrs.reserve(info.idxHandles.size());
|
||||
for (auto const& it : info.idxHandles) {
|
||||
csrs.emplace_back(_trx->indexScanForCondition(
|
||||
it, node, _tmpVar, mmdr, UINT64_MAX, 1000, false));
|
||||
csrs.emplace_back(_trx->indexScanForCondition(it, node, _tmpVar, mmdr,
|
||||
UINT64_MAX, 1000, false));
|
||||
}
|
||||
opCursors.emplace_back(std::move(csrs));
|
||||
}
|
||||
|
@ -544,8 +559,8 @@ arangodb::traverser::TraverserOptions::nextCursorLocal(ManagedDocumentResult* mm
|
|||
}
|
||||
|
||||
arangodb::traverser::EdgeCursor*
|
||||
arangodb::traverser::TraverserOptions::nextCursorCoordinator(
|
||||
StringRef vid, uint64_t depth) {
|
||||
arangodb::traverser::TraverserOptions::nextCursorCoordinator(StringRef vid,
|
||||
uint64_t depth) {
|
||||
TRI_ASSERT(_traverser != nullptr);
|
||||
auto cursor = std::make_unique<ClusterEdgeCursor>(vid, depth, _traverser);
|
||||
return cursor.release();
|
||||
|
@ -556,7 +571,8 @@ void arangodb::traverser::TraverserOptions::linkTraverser(
|
|||
_traverser = trav;
|
||||
}
|
||||
|
||||
double arangodb::traverser::TraverserOptions::estimateCost(size_t& nrItems) const {
|
||||
double arangodb::traverser::TraverserOptions::estimateCost(
|
||||
size_t& nrItems) const {
|
||||
size_t count = 1;
|
||||
double cost = 0;
|
||||
size_t baseCreateItems = 0;
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
#ifndef ARANGOD_VOC_BASE_TRAVERSER_OPTIONS_H
|
||||
#define ARANGOD_VOC_BASE_TRAVERSER_OPTIONS_H 1
|
||||
|
||||
#include "Aql/FixedVarExpressionContext.h"
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/StringRef.h"
|
||||
#include "Aql/FixedVarExpressionContext.h"
|
||||
#include "Graph/BaseOptions.h"
|
||||
#include "StorageEngine/TransactionState.h"
|
||||
#include "Transaction/Methods.h"
|
||||
|
@ -60,9 +60,13 @@ class EdgeCursor {
|
|||
EdgeCursor() {}
|
||||
virtual ~EdgeCursor() {}
|
||||
|
||||
virtual bool next(std::function<void(arangodb::StringRef const&, VPackSlice, size_t)> callback) = 0;
|
||||
virtual bool next(
|
||||
std::function<void(arangodb::StringRef const&, VPackSlice, size_t)>
|
||||
callback) = 0;
|
||||
|
||||
virtual void readAll(std::function<void(arangodb::StringRef const&, arangodb::velocypack::Slice, size_t&)>) = 0;
|
||||
virtual void readAll(
|
||||
std::function<void(arangodb::StringRef const&,
|
||||
arangodb::velocypack::Slice, size_t&)>) = 0;
|
||||
};
|
||||
|
||||
struct TraverserOptions : public graph::BaseOptions {
|
||||
|
@ -111,11 +115,15 @@ struct TraverserOptions : public graph::BaseOptions {
|
|||
/// for DBServer traverser engines.
|
||||
void buildEngineInfo(arangodb::velocypack::Builder&) const;
|
||||
|
||||
/// @brief Add a lookup info for specific depth
|
||||
void addDepthLookupInfo(aql::Ast* ast, std::string const& collectionName,
|
||||
std::string const& attributeName,
|
||||
aql::AstNode* condition, uint64_t depth);
|
||||
|
||||
bool vertexHasFilter(uint64_t) const;
|
||||
|
||||
bool evaluateEdgeExpression(arangodb::velocypack::Slice,
|
||||
StringRef vertexId, uint64_t,
|
||||
size_t) const;
|
||||
bool evaluateEdgeExpression(arangodb::velocypack::Slice, StringRef vertexId,
|
||||
uint64_t, size_t) const;
|
||||
|
||||
bool evaluateVertexExpression(arangodb::velocypack::Slice, uint64_t) const;
|
||||
|
||||
|
@ -126,14 +134,11 @@ struct TraverserOptions : public graph::BaseOptions {
|
|||
double estimateCost(size_t& nrItems) const;
|
||||
|
||||
private:
|
||||
|
||||
EdgeCursor* nextCursorLocal(ManagedDocumentResult*,
|
||||
StringRef vid, uint64_t,
|
||||
EdgeCursor* nextCursorLocal(ManagedDocumentResult*, StringRef vid, uint64_t,
|
||||
std::vector<LookupInfo>&);
|
||||
|
||||
EdgeCursor* nextCursorCoordinator(StringRef vid, uint64_t);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue