1
0
Fork 0

Simplified AqlTraverser Setup code by moving shared logic into the TraverserOptions.

This commit is contained in:
Michael Hackstein 2017-04-11 13:47:06 +02:00
parent b09dfaa323
commit 212de2b0d1
3 changed files with 80 additions and 148 deletions

View File

@ -900,7 +900,6 @@ void TraversalNode::prepareOptions() {
_options->_tmpVar = _tmpObjVariable; _options->_tmpVar = _tmpObjVariable;
size_t numEdgeColls = _edgeColls.size(); size_t numEdgeColls = _edgeColls.size();
bool res = false;
TraversalEdgeConditionBuilder globalEdgeConditionBuilder(this); TraversalEdgeConditionBuilder globalEdgeConditionBuilder(this);
for (auto& it : _globalEdgeConditions) { for (auto& it : _globalEdgeConditions) {
@ -908,78 +907,30 @@ void TraversalNode::prepareOptions() {
} }
Ast* ast = _plan->getAst(); Ast* ast = _plan->getAst();
auto trx = ast->query()->trx();
_options->_baseLookupInfos.reserve(numEdgeColls);
// Compute Edge Indexes. First default indexes: // Compute Edge Indexes. First default indexes:
for (size_t i = 0; i < numEdgeColls; ++i) { for (size_t i = 0; i < numEdgeColls; ++i) {
std::string usedField;
auto dir = _directions[i]; auto dir = _directions[i];
// TODO we can optimize here. indexCondition and Expression could be
// made non-overlapping.
traverser::TraverserOptions::LookupInfo info;
switch (dir) { switch (dir) {
case TRI_EDGE_IN: case TRI_EDGE_IN:
usedField = StaticStrings::ToString; _options->addLookupInfo(
info.indexCondition = ast, _edgeColls[i]->getName(), StaticStrings::ToString,
globalEdgeConditionBuilder.getInboundCondition()->clone(ast); globalEdgeConditionBuilder.getInboundCondition()->clone(ast));
break; break;
case TRI_EDGE_OUT: case TRI_EDGE_OUT:
usedField = StaticStrings::FromString; _options->addLookupInfo(
info.indexCondition = ast, _edgeColls[i]->getName(), StaticStrings::FromString,
globalEdgeConditionBuilder.getOutboundCondition()->clone(ast); globalEdgeConditionBuilder.getOutboundCondition()->clone(ast));
break; break;
case TRI_EDGE_ANY: case TRI_EDGE_ANY:
TRI_ASSERT(false); TRI_ASSERT(false);
break; 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) { for (auto& it : _edgeConditions) {
auto ins = _options->_depthLookupInfo.emplace( uint64_t depth = it.first;
it.first, std::vector<traverser::TraverserOptions::LookupInfo>());
// We probably have to adopt minDepth. We cannot fulfill a condition of larger depth anyway // 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; auto& builder = it.second;
for (auto& it : _globalEdgeConditions) { for (auto& it : _globalEdgeConditions) {
@ -987,64 +938,24 @@ void TraversalNode::prepareOptions() {
} }
for (size_t i = 0; i < numEdgeColls; ++i) { for (size_t i = 0; i < numEdgeColls; ++i) {
std::string usedField;
auto dir = _directions[i]; auto dir = _directions[i];
// TODO we can optimize here. indexCondition and Expression could be // TODO we can optimize here. indexCondition and Expression could be
// made non-overlapping. // made non-overlapping.
traverser::TraverserOptions::LookupInfo info;
switch (dir) { switch (dir) {
case TRI_EDGE_IN: case TRI_EDGE_IN:
usedField = StaticStrings::ToString; _options->addDepthLookupInfo(
info.indexCondition = builder->getInboundCondition()->clone(ast); ast, _edgeColls[i]->getName(), StaticStrings::ToString,
builder->getInboundCondition()->clone(ast), depth);
break; break;
case TRI_EDGE_OUT: case TRI_EDGE_OUT:
usedField = StaticStrings::FromString; _options->addDepthLookupInfo(
info.indexCondition = builder->getOutboundCondition()->clone(ast); ast, _edgeColls[i]->getName(), StaticStrings::FromString,
builder->getOutboundCondition()->clone(ast), depth);
break; break;
case TRI_EDGE_ANY: case TRI_EDGE_ANY:
TRI_ASSERT(false); TRI_ASSERT(false);
break; 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));
} }
} }

View File

@ -52,8 +52,8 @@ TraverserOptions::TraverserOptions(transaction::Methods* trx)
uniqueVertices(UniquenessLevel::NONE), uniqueVertices(UniquenessLevel::NONE),
uniqueEdges(UniquenessLevel::PATH) {} uniqueEdges(UniquenessLevel::PATH) {}
TraverserOptions::TraverserOptions( TraverserOptions::TraverserOptions(transaction::Methods* trx,
transaction::Methods* trx, VPackSlice const& slice) VPackSlice const& slice)
: BaseOptions(trx), : BaseOptions(trx),
_baseVertexExpression(nullptr), _baseVertexExpression(nullptr),
_traverser(nullptr), _traverser(nullptr),
@ -89,16 +89,14 @@ TraverserOptions::TraverserOptions(
tmp = VPackHelper::getStringValue(obj, "uniqueEdges", ""); tmp = VPackHelper::getStringValue(obj, "uniqueEdges", "");
if (tmp == "none") { if (tmp == "none") {
uniqueEdges = uniqueEdges = arangodb::traverser::TraverserOptions::UniquenessLevel::NONE;
arangodb::traverser::TraverserOptions::UniquenessLevel::NONE;
} else if (tmp == "global") { } else if (tmp == "global") {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER, THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER,
"uniqueEdges: 'global' is not supported, " "uniqueEdges: 'global' is not supported, "
"due to unpredictable results. Use 'path' " "due to unpredictable results. Use 'path' "
"or 'none' instead"); "or 'none' instead");
} else { } else {
uniqueEdges = uniqueEdges = arangodb::traverser::TraverserOptions::UniquenessLevel::PATH;
arangodb::traverser::TraverserOptions::UniquenessLevel::PATH;
} }
} }
@ -233,8 +231,8 @@ arangodb::traverser::TraverserOptions::TraverserOptions(
d, new aql::Expression(query->ast(), info.value)); d, new aql::Expression(query->ast(), info.value));
TRI_ASSERT(it.second); TRI_ASSERT(it.second);
#else #else
_vertexExpressions.emplace( _vertexExpressions.emplace(d,
d, new aql::Expression(query->ast(), info.value)); new aql::Expression(query->ast(), info.value));
#endif #endif
} }
} }
@ -289,7 +287,8 @@ arangodb::traverser::TraverserOptions::~TraverserOptions() {
delete _baseVertexExpression; delete _baseVertexExpression;
} }
void arangodb::traverser::TraverserOptions::toVelocyPack(VPackBuilder& builder) const { void arangodb::traverser::TraverserOptions::toVelocyPack(
VPackBuilder& builder) const {
VPackObjectBuilder guard(&builder); VPackObjectBuilder guard(&builder);
builder.add("minDepth", VPackValue(minDepth)); 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); VPackObjectBuilder guard(&builder);
// base indexes // base indexes
@ -352,7 +352,8 @@ void arangodb::traverser::TraverserOptions::toVelocyPackIndexes(VPackBuilder& bu
builder.close(); builder.close();
} }
void arangodb::traverser::TraverserOptions::buildEngineInfo(VPackBuilder& result) const { void arangodb::traverser::TraverserOptions::buildEngineInfo(
VPackBuilder& result) const {
result.openObject(); result.openObject();
result.add("minDepth", VPackValue(minDepth)); result.add("minDepth", VPackValue(minDepth));
result.add("maxDepth", VPackValue(maxDepth)); result.add("maxDepth", VPackValue(maxDepth));
@ -386,7 +387,7 @@ void arangodb::traverser::TraverserOptions::buildEngineInfo(VPackBuilder& result
result.add(VPackValue("baseLookupInfos")); result.add(VPackValue("baseLookupInfos"));
result.openArray(); result.openArray();
for (auto const& it: _baseLookupInfos) { for (auto const& it : _baseLookupInfos) {
it.buildEngineInfo(result); it.buildEngineInfo(result);
} }
result.close(); result.close();
@ -432,6 +433,18 @@ void arangodb::traverser::TraverserOptions::buildEngineInfo(VPackBuilder& result
result.close(); 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( bool arangodb::traverser::TraverserOptions::vertexHasFilter(
uint64_t depth) const { uint64_t depth) const {
if (_baseVertexExpression != nullptr) { if (_baseVertexExpression != nullptr) {
@ -441,8 +454,8 @@ bool arangodb::traverser::TraverserOptions::vertexHasFilter(
} }
bool arangodb::traverser::TraverserOptions::evaluateEdgeExpression( bool arangodb::traverser::TraverserOptions::evaluateEdgeExpression(
arangodb::velocypack::Slice edge, StringRef vertexId, arangodb::velocypack::Slice edge, StringRef vertexId, uint64_t depth,
uint64_t depth, size_t cursorId) const { size_t cursorId) const {
if (_isCoordinator) { if (_isCoordinator) {
// The Coordinator never checks conditions. The DBServer is responsible! // The Coordinator never checks conditions. The DBServer is responsible!
return true; return true;
@ -513,10 +526,12 @@ arangodb::traverser::TraverserOptions::nextCursor(ManagedDocumentResult* mmdr,
} }
arangodb::traverser::EdgeCursor* arangodb::traverser::EdgeCursor*
arangodb::traverser::TraverserOptions::nextCursorLocal(ManagedDocumentResult* mmdr, arangodb::traverser::TraverserOptions::nextCursorLocal(
StringRef vid, uint64_t depth, std::vector<LookupInfo>& list) { ManagedDocumentResult* mmdr, StringRef vid, uint64_t depth,
std::vector<LookupInfo>& list) {
TRI_ASSERT(mmdr != nullptr); 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(); auto& opCursors = allCursor->getCursors();
for (auto& info : list) { for (auto& info : list) {
auto& node = info.indexCondition; auto& node = info.indexCondition;
@ -535,8 +550,8 @@ arangodb::traverser::TraverserOptions::nextCursorLocal(ManagedDocumentResult* mm
std::vector<OperationCursor*> csrs; std::vector<OperationCursor*> csrs;
csrs.reserve(info.idxHandles.size()); csrs.reserve(info.idxHandles.size());
for (auto const& it : info.idxHandles) { for (auto const& it : info.idxHandles) {
csrs.emplace_back(_trx->indexScanForCondition( csrs.emplace_back(_trx->indexScanForCondition(it, node, _tmpVar, mmdr,
it, node, _tmpVar, mmdr, UINT64_MAX, 1000, false)); UINT64_MAX, 1000, false));
} }
opCursors.emplace_back(std::move(csrs)); opCursors.emplace_back(std::move(csrs));
} }
@ -544,8 +559,8 @@ arangodb::traverser::TraverserOptions::nextCursorLocal(ManagedDocumentResult* mm
} }
arangodb::traverser::EdgeCursor* arangodb::traverser::EdgeCursor*
arangodb::traverser::TraverserOptions::nextCursorCoordinator( arangodb::traverser::TraverserOptions::nextCursorCoordinator(StringRef vid,
StringRef vid, uint64_t depth) { uint64_t depth) {
TRI_ASSERT(_traverser != nullptr); TRI_ASSERT(_traverser != nullptr);
auto cursor = std::make_unique<ClusterEdgeCursor>(vid, depth, _traverser); auto cursor = std::make_unique<ClusterEdgeCursor>(vid, depth, _traverser);
return cursor.release(); return cursor.release();
@ -556,7 +571,8 @@ void arangodb::traverser::TraverserOptions::linkTraverser(
_traverser = trav; _traverser = trav;
} }
double arangodb::traverser::TraverserOptions::estimateCost(size_t& nrItems) const { double arangodb::traverser::TraverserOptions::estimateCost(
size_t& nrItems) const {
size_t count = 1; size_t count = 1;
double cost = 0; double cost = 0;
size_t baseCreateItems = 0; size_t baseCreateItems = 0;

View File

@ -24,9 +24,9 @@
#ifndef ARANGOD_VOC_BASE_TRAVERSER_OPTIONS_H #ifndef ARANGOD_VOC_BASE_TRAVERSER_OPTIONS_H
#define ARANGOD_VOC_BASE_TRAVERSER_OPTIONS_H 1 #define ARANGOD_VOC_BASE_TRAVERSER_OPTIONS_H 1
#include "Aql/FixedVarExpressionContext.h"
#include "Basics/Common.h" #include "Basics/Common.h"
#include "Basics/StringRef.h" #include "Basics/StringRef.h"
#include "Aql/FixedVarExpressionContext.h"
#include "Graph/BaseOptions.h" #include "Graph/BaseOptions.h"
#include "StorageEngine/TransactionState.h" #include "StorageEngine/TransactionState.h"
#include "Transaction/Methods.h" #include "Transaction/Methods.h"
@ -60,9 +60,13 @@ class EdgeCursor {
EdgeCursor() {} EdgeCursor() {}
virtual ~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 { struct TraverserOptions : public graph::BaseOptions {
@ -111,11 +115,15 @@ struct TraverserOptions : public graph::BaseOptions {
/// for DBServer traverser engines. /// for DBServer traverser engines.
void buildEngineInfo(arangodb::velocypack::Builder&) const; 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 vertexHasFilter(uint64_t) const;
bool evaluateEdgeExpression(arangodb::velocypack::Slice, bool evaluateEdgeExpression(arangodb::velocypack::Slice, StringRef vertexId,
StringRef vertexId, uint64_t, uint64_t, size_t) const;
size_t) const;
bool evaluateVertexExpression(arangodb::velocypack::Slice, uint64_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; double estimateCost(size_t& nrItems) const;
private: private:
EdgeCursor* nextCursorLocal(ManagedDocumentResult*, StringRef vid, uint64_t,
EdgeCursor* nextCursorLocal(ManagedDocumentResult*,
StringRef vid, uint64_t,
std::vector<LookupInfo>&); std::vector<LookupInfo>&);
EdgeCursor* nextCursorCoordinator(StringRef vid, uint64_t); EdgeCursor* nextCursorCoordinator(StringRef vid, uint64_t);
}; };
} }
} }
#endif #endif