mirror of https://gitee.com/bigwinds/arangodb
Fixed responsibility for Traversal Options. Now the TraversalNode is always responsible for all options and has to free them. All others just use these. In Cluster case each DBServer get's it's own TraverserEngine which is initialized with a copy of the Options.
This commit is contained in:
parent
207d978afc
commit
5ee93a8d6c
|
@ -206,6 +206,10 @@ struct Instanciator final : public WalkerWorker<ExecutionNode> {
|
||||||
virtual void after(ExecutionNode* en) override final {
|
virtual void after(ExecutionNode* en) override final {
|
||||||
ExecutionBlock* block = nullptr;
|
ExecutionBlock* block = nullptr;
|
||||||
{
|
{
|
||||||
|
if (en->getType() == ExecutionNode::TRAVERSAL) {
|
||||||
|
// We have to prepare the options before we build the block
|
||||||
|
static_cast<TraversalNode*>(en)->prepareOptions();
|
||||||
|
}
|
||||||
std::unique_ptr<ExecutionBlock> eb(CreateBlock(engine, en, cache));
|
std::unique_ptr<ExecutionBlock> eb(CreateBlock(engine, en, cache));
|
||||||
|
|
||||||
if (eb == nullptr) {
|
if (eb == nullptr) {
|
||||||
|
|
|
@ -70,10 +70,10 @@ static uint64_t checkTraversalDepthValue(AstNode const* node) {
|
||||||
return static_cast<uint64_t>(v);
|
return static_cast<uint64_t>(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static traverser::TraverserOptions CreateTraversalOptions(
|
static std::unique_ptr<traverser::TraverserOptions> CreateTraversalOptions(
|
||||||
Transaction* trx, AstNode const* direction, AstNode const* optionsNode) {
|
Transaction* trx, AstNode const* direction, AstNode const* optionsNode) {
|
||||||
|
|
||||||
traverser::TraverserOptions options(trx);
|
auto options = std::make_unique<traverser::TraverserOptions>(trx);
|
||||||
|
|
||||||
TRI_ASSERT(direction != nullptr);
|
TRI_ASSERT(direction != nullptr);
|
||||||
TRI_ASSERT(direction->type == NODE_TYPE_DIRECTION);
|
TRI_ASSERT(direction->type == NODE_TYPE_DIRECTION);
|
||||||
|
@ -83,14 +83,14 @@ static traverser::TraverserOptions CreateTraversalOptions(
|
||||||
|
|
||||||
if (steps->isNumericValue()) {
|
if (steps->isNumericValue()) {
|
||||||
// Check if a double value is integer
|
// Check if a double value is integer
|
||||||
options.minDepth = checkTraversalDepthValue(steps);
|
options->minDepth = checkTraversalDepthValue(steps);
|
||||||
options.maxDepth = options.minDepth;
|
options->maxDepth = options->minDepth;
|
||||||
} else if (steps->type == NODE_TYPE_RANGE) {
|
} else if (steps->type == NODE_TYPE_RANGE) {
|
||||||
// Range depth
|
// Range depth
|
||||||
options.minDepth = checkTraversalDepthValue(steps->getMember(0));
|
options->minDepth = checkTraversalDepthValue(steps->getMember(0));
|
||||||
options.maxDepth = checkTraversalDepthValue(steps->getMember(1));
|
options->maxDepth = checkTraversalDepthValue(steps->getMember(1));
|
||||||
|
|
||||||
if (options.maxDepth < options.minDepth) {
|
if (options->maxDepth < options->minDepth) {
|
||||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_PARSE,
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_PARSE,
|
||||||
"invalid traversal depth");
|
"invalid traversal depth");
|
||||||
}
|
}
|
||||||
|
@ -112,29 +112,27 @@ static traverser::TraverserOptions CreateTraversalOptions(
|
||||||
TRI_ASSERT(value->isConstant());
|
TRI_ASSERT(value->isConstant());
|
||||||
|
|
||||||
if (name == "bfs") {
|
if (name == "bfs") {
|
||||||
options.useBreadthFirst = value->isTrue();
|
options->useBreadthFirst = value->isTrue();
|
||||||
} else if (name == "uniqueVertices" && value->isStringValue()) {
|
} else if (name == "uniqueVertices" && value->isStringValue()) {
|
||||||
if (value->stringEquals("path", true)) {
|
if (value->stringEquals("path", true)) {
|
||||||
options.uniqueVertices =
|
options->uniqueVertices =
|
||||||
arangodb::traverser::TraverserOptions::UniquenessLevel::PATH;
|
arangodb::traverser::TraverserOptions::UniquenessLevel::PATH;
|
||||||
} else if (value->stringEquals("global", true)) {
|
} else if (value->stringEquals("global", true)) {
|
||||||
options.uniqueVertices =
|
options->uniqueVertices =
|
||||||
arangodb::traverser::TraverserOptions::UniquenessLevel::GLOBAL;
|
arangodb::traverser::TraverserOptions::UniquenessLevel::GLOBAL;
|
||||||
}
|
}
|
||||||
} else if (name == "uniqueEdges" && value->isStringValue()) {
|
} else if (name == "uniqueEdges" && value->isStringValue()) {
|
||||||
if (value->stringEquals("none", true)) {
|
if (value->stringEquals("none", true)) {
|
||||||
options.uniqueEdges =
|
options->uniqueEdges =
|
||||||
arangodb::traverser::TraverserOptions::UniquenessLevel::NONE;
|
arangodb::traverser::TraverserOptions::UniquenessLevel::NONE;
|
||||||
} else if (value->stringEquals("global", true)) {
|
} else if (value->stringEquals("global", true)) {
|
||||||
options.uniqueEdges =
|
options->uniqueEdges =
|
||||||
arangodb::traverser::TraverserOptions::UniquenessLevel::GLOBAL;
|
arangodb::traverser::TraverserOptions::UniquenessLevel::GLOBAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -755,8 +753,8 @@ ExecutionNode* ExecutionPlan::fromNodeTraversal(ExecutionNode* previous,
|
||||||
previous = calc;
|
previous = calc;
|
||||||
}
|
}
|
||||||
|
|
||||||
traverser::TraverserOptions options = CreateTraversalOptions(
|
auto options = CreateTraversalOptions(getAst()->query()->trx(), direction,
|
||||||
getAst()->query()->trx(), direction, node->getMember(3));
|
node->getMember(3));
|
||||||
|
|
||||||
// First create the node
|
// First create the node
|
||||||
auto travNode = new TraversalNode(this, nextId(), _ast->query()->vocbase(),
|
auto travNode = new TraversalNode(this, nextId(), _ast->query()->vocbase(),
|
||||||
|
|
|
@ -42,7 +42,7 @@ using namespace arangodb::aql;
|
||||||
TraversalBlock::TraversalBlock(ExecutionEngine* engine, TraversalNode const* ep)
|
TraversalBlock::TraversalBlock(ExecutionEngine* engine, TraversalNode const* ep)
|
||||||
: ExecutionBlock(engine, ep),
|
: ExecutionBlock(engine, ep),
|
||||||
_posInPaths(0),
|
_posInPaths(0),
|
||||||
_opts(new traverser::TraverserOptions(_trx)),
|
_opts(nullptr),
|
||||||
_traverser(nullptr),
|
_traverser(nullptr),
|
||||||
_useRegister(false),
|
_useRegister(false),
|
||||||
_usedConstant(false),
|
_usedConstant(false),
|
||||||
|
@ -60,16 +60,16 @@ TraversalBlock::TraversalBlock(ExecutionEngine* engine, TraversalNode const* ep)
|
||||||
_inRegs.emplace_back(it->second.registerId);
|
_inRegs.emplace_back(it->second.registerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
ep->fillTraversalOptions(_opts.get(), _trx);
|
_opts = ep->options();
|
||||||
|
|
||||||
if (arangodb::ServerState::instance()->isCoordinator()) {
|
if (arangodb::ServerState::instance()->isCoordinator()) {
|
||||||
_traverser.reset(new arangodb::traverser::ClusterTraverser(
|
_traverser.reset(new arangodb::traverser::ClusterTraverser(
|
||||||
ep->edgeColls(), _opts.get(),
|
ep->edgeColls(), _opts,
|
||||||
std::string(_trx->vocbase()->_name, strlen(_trx->vocbase()->_name)),
|
std::string(_trx->vocbase()->_name, strlen(_trx->vocbase()->_name)),
|
||||||
_trx));
|
_trx));
|
||||||
} else {
|
} else {
|
||||||
_traverser.reset(
|
_traverser.reset(
|
||||||
new arangodb::traverser::SingleServerTraverser(_opts.get(), _trx));
|
new arangodb::traverser::SingleServerTraverser(_opts, _trx));
|
||||||
}
|
}
|
||||||
if (!ep->usesInVariable()) {
|
if (!ep->usesInVariable()) {
|
||||||
_vertexId = ep->getStartVertex();
|
_vertexId = ep->getStartVertex();
|
||||||
|
|
|
@ -73,7 +73,7 @@ class TraversalBlock : public ExecutionBlock {
|
||||||
size_t _posInPaths;
|
size_t _posInPaths;
|
||||||
|
|
||||||
/// @brief Options for the travereser
|
/// @brief Options for the travereser
|
||||||
std::unique_ptr<arangodb::traverser::TraverserOptions> _opts;
|
arangodb::traverser::TraverserOptions* _opts;
|
||||||
|
|
||||||
/// @brief Traverser object
|
/// @brief Traverser object
|
||||||
std::unique_ptr<arangodb::traverser::Traverser> _traverser;
|
std::unique_ptr<arangodb::traverser::Traverser> _traverser;
|
||||||
|
|
|
@ -114,7 +114,7 @@ static TRI_edge_direction_e parseDirection (AstNode const* node) {
|
||||||
TraversalNode::TraversalNode(ExecutionPlan* plan, size_t id,
|
TraversalNode::TraversalNode(ExecutionPlan* plan, size_t id,
|
||||||
TRI_vocbase_t* vocbase, AstNode const* direction,
|
TRI_vocbase_t* vocbase, AstNode const* direction,
|
||||||
AstNode const* start, AstNode const* graph,
|
AstNode const* start, AstNode const* graph,
|
||||||
traverser::TraverserOptions const& options)
|
std::unique_ptr<traverser::TraverserOptions>& options)
|
||||||
: ExecutionNode(plan, id),
|
: ExecutionNode(plan, id),
|
||||||
_vocbase(vocbase),
|
_vocbase(vocbase),
|
||||||
_vertexOutVariable(nullptr),
|
_vertexOutVariable(nullptr),
|
||||||
|
@ -123,7 +123,6 @@ TraversalNode::TraversalNode(ExecutionPlan* plan, size_t id,
|
||||||
_inVariable(nullptr),
|
_inVariable(nullptr),
|
||||||
_graphObj(nullptr),
|
_graphObj(nullptr),
|
||||||
_condition(nullptr),
|
_condition(nullptr),
|
||||||
_options(options),
|
|
||||||
_specializedNeighborsSearch(false),
|
_specializedNeighborsSearch(false),
|
||||||
_tmpObjVariable(_plan->getAst()->variables()->createTemporaryVariable()),
|
_tmpObjVariable(_plan->getAst()->variables()->createTemporaryVariable()),
|
||||||
_tmpObjVarNode(_plan->getAst()->createNodeReference(_tmpObjVariable)),
|
_tmpObjVarNode(_plan->getAst()->createNodeReference(_tmpObjVariable)),
|
||||||
|
@ -131,11 +130,13 @@ TraversalNode::TraversalNode(ExecutionPlan* plan, size_t id,
|
||||||
_fromCondition(nullptr),
|
_fromCondition(nullptr),
|
||||||
_toCondition(nullptr),
|
_toCondition(nullptr),
|
||||||
_globalEdgeCondition(nullptr),
|
_globalEdgeCondition(nullptr),
|
||||||
_globalVertexCondition(nullptr) {
|
_globalVertexCondition(nullptr),
|
||||||
|
_optionsBuild(false) {
|
||||||
TRI_ASSERT(_vocbase != nullptr);
|
TRI_ASSERT(_vocbase != nullptr);
|
||||||
TRI_ASSERT(direction != nullptr);
|
TRI_ASSERT(direction != nullptr);
|
||||||
TRI_ASSERT(start != nullptr);
|
TRI_ASSERT(start != nullptr);
|
||||||
TRI_ASSERT(graph != nullptr);
|
TRI_ASSERT(graph != nullptr);
|
||||||
|
_options.reset(options.release());
|
||||||
|
|
||||||
auto ast = _plan->getAst();
|
auto ast = _plan->getAst();
|
||||||
// Let us build the conditions on _from and _to. Just in case we need them.
|
// Let us build the conditions on _from and _to. Just in case we need them.
|
||||||
|
@ -280,7 +281,7 @@ TraversalNode::TraversalNode(ExecutionPlan* plan, size_t id,
|
||||||
Variable const* inVariable,
|
Variable const* inVariable,
|
||||||
std::string const& vertexId,
|
std::string const& vertexId,
|
||||||
std::vector<TRI_edge_direction_e> directions,
|
std::vector<TRI_edge_direction_e> directions,
|
||||||
traverser::TraverserOptions const& options)
|
std::unique_ptr<traverser::TraverserOptions>& options)
|
||||||
: ExecutionNode(plan, id),
|
: ExecutionNode(plan, id),
|
||||||
_vocbase(vocbase),
|
_vocbase(vocbase),
|
||||||
_vertexOutVariable(nullptr),
|
_vertexOutVariable(nullptr),
|
||||||
|
@ -291,10 +292,12 @@ TraversalNode::TraversalNode(ExecutionPlan* plan, size_t id,
|
||||||
_directions(directions),
|
_directions(directions),
|
||||||
_graphObj(nullptr),
|
_graphObj(nullptr),
|
||||||
_condition(nullptr),
|
_condition(nullptr),
|
||||||
_options(options),
|
|
||||||
_specializedNeighborsSearch(false),
|
_specializedNeighborsSearch(false),
|
||||||
_fromCondition(nullptr),
|
_fromCondition(nullptr),
|
||||||
_toCondition(nullptr) {
|
_toCondition(nullptr),
|
||||||
|
_optionsBuild(false) {
|
||||||
|
|
||||||
|
_options.reset(options.release());
|
||||||
_graphJson = arangodb::basics::Json(arangodb::basics::Json::Array, edgeColls.size());
|
_graphJson = arangodb::basics::Json(arangodb::basics::Json::Array, edgeColls.size());
|
||||||
|
|
||||||
for (auto& it : edgeColls) {
|
for (auto& it : edgeColls) {
|
||||||
|
@ -313,7 +316,6 @@ TraversalNode::TraversalNode(ExecutionPlan* plan,
|
||||||
_inVariable(nullptr),
|
_inVariable(nullptr),
|
||||||
_graphObj(nullptr),
|
_graphObj(nullptr),
|
||||||
_condition(nullptr),
|
_condition(nullptr),
|
||||||
_options(_plan->getAst()->query()->trx(), base),
|
|
||||||
_specializedNeighborsSearch(false),
|
_specializedNeighborsSearch(false),
|
||||||
_tmpObjVariable(nullptr),
|
_tmpObjVariable(nullptr),
|
||||||
_tmpObjVarNode(nullptr),
|
_tmpObjVarNode(nullptr),
|
||||||
|
@ -321,7 +323,10 @@ TraversalNode::TraversalNode(ExecutionPlan* plan,
|
||||||
_fromCondition(nullptr),
|
_fromCondition(nullptr),
|
||||||
_toCondition(nullptr),
|
_toCondition(nullptr),
|
||||||
_globalEdgeCondition(nullptr),
|
_globalEdgeCondition(nullptr),
|
||||||
_globalVertexCondition(nullptr) {
|
_globalVertexCondition(nullptr),
|
||||||
|
_optionsBuild(false) {
|
||||||
|
_options = std::make_unique<arangodb::traverser::TraverserOptions>(
|
||||||
|
_plan->getAst()->query()->trx(), base);
|
||||||
auto dirList = base.get("directions");
|
auto dirList = base.get("directions");
|
||||||
TRI_ASSERT(dirList.json() != nullptr);
|
TRI_ASSERT(dirList.json() != nullptr);
|
||||||
for (size_t i = 0; i < dirList.size(); ++i) {
|
for (size_t i = 0; i < dirList.size(); ++i) {
|
||||||
|
@ -512,9 +517,9 @@ int TraversalNode::checkIsOutVariable(size_t variableId) const {
|
||||||
/// @brief check whether an access is inside the specified range
|
/// @brief check whether an access is inside the specified range
|
||||||
bool TraversalNode::isInRange(uint64_t depth, bool isEdge) const {
|
bool TraversalNode::isInRange(uint64_t depth, bool isEdge) const {
|
||||||
if (isEdge) {
|
if (isEdge) {
|
||||||
return (depth < _options.maxDepth);
|
return (depth < _options->maxDepth);
|
||||||
}
|
}
|
||||||
return (depth <= _options.maxDepth);
|
return (depth <= _options->maxDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief check if all directions are equal
|
/// @brief check if all directions are equal
|
||||||
|
@ -604,7 +609,7 @@ void TraversalNode::toVelocyPackHelper(arangodb::velocypack::Builder& nodes,
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes.add(VPackValue("traversalFlags"));
|
nodes.add(VPackValue("traversalFlags"));
|
||||||
_options.toVelocyPack(nodes);
|
_options->toVelocyPack(nodes);
|
||||||
|
|
||||||
// Traversal Filter Conditions
|
// Traversal Filter Conditions
|
||||||
|
|
||||||
|
@ -666,9 +671,11 @@ void TraversalNode::toVelocyPackHelper(arangodb::velocypack::Builder& nodes,
|
||||||
/// @brief clone ExecutionNode recursively
|
/// @brief clone ExecutionNode recursively
|
||||||
ExecutionNode* TraversalNode::clone(ExecutionPlan* plan, bool withDependencies,
|
ExecutionNode* TraversalNode::clone(ExecutionPlan* plan, bool withDependencies,
|
||||||
bool withProperties) const {
|
bool withProperties) const {
|
||||||
auto c =
|
TRI_ASSERT(!_optionsBuild);
|
||||||
new TraversalNode(plan, _id, _vocbase, _edgeColls, _inVariable, _vertexId,
|
auto tmp =
|
||||||
_directions, _options);
|
std::make_unique<arangodb::traverser::TraverserOptions>(*_options.get());
|
||||||
|
auto c = new TraversalNode(plan, _id, _vocbase, _edgeColls, _inVariable,
|
||||||
|
_vertexId, _directions, tmp);
|
||||||
|
|
||||||
if (usesVertexOutVariable()) {
|
if (usesVertexOutVariable()) {
|
||||||
auto vertexOutVariable = _vertexOutVariable;
|
auto vertexOutVariable = _vertexOutVariable;
|
||||||
|
@ -783,27 +790,25 @@ double TraversalNode::estimateCost(size_t& nrItems) const {
|
||||||
}
|
}
|
||||||
nrItems = static_cast<size_t>(
|
nrItems = static_cast<size_t>(
|
||||||
incoming *
|
incoming *
|
||||||
std::pow(expectedEdgesPerDepth, static_cast<double>(_options.maxDepth)));
|
std::pow(expectedEdgesPerDepth, static_cast<double>(_options->maxDepth)));
|
||||||
if (nrItems == 0 && incoming > 0) {
|
if (nrItems == 0 && incoming > 0) {
|
||||||
nrItems = 1; // min value
|
nrItems = 1; // min value
|
||||||
}
|
}
|
||||||
return depCost + nrItems;
|
return depCost + nrItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraversalNode::fillTraversalOptions(
|
void TraversalNode::prepareOptions() {
|
||||||
arangodb::traverser::TraverserOptions* opts,
|
TRI_ASSERT(!_optionsBuild);
|
||||||
arangodb::Transaction* trx) const {
|
_options->_tmpVar = _tmpObjVariable;
|
||||||
opts->minDepth = _options.minDepth;
|
|
||||||
opts->maxDepth = _options.maxDepth;
|
|
||||||
opts->_tmpVar = _tmpObjVariable;
|
|
||||||
|
|
||||||
size_t numEdgeColls = _edgeColls.size();
|
size_t numEdgeColls = _edgeColls.size();
|
||||||
AstNode* condition = nullptr;
|
AstNode* condition = nullptr;
|
||||||
bool res = false;
|
bool res = false;
|
||||||
EdgeConditionBuilder globalEdgeConditionBuilder(this);
|
EdgeConditionBuilder globalEdgeConditionBuilder(this);
|
||||||
Ast* ast = _plan->getAst();
|
Ast* ast = _plan->getAst();
|
||||||
|
auto trx = ast->query()->trx();
|
||||||
|
|
||||||
opts->_baseLookupInfos.reserve(numEdgeColls);
|
_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) {
|
||||||
auto dir = _directions[i];
|
auto dir = _directions[i];
|
||||||
|
@ -833,7 +838,7 @@ void TraversalNode::fillTraversalOptions(
|
||||||
infoIn.idxHandles[0]);
|
infoIn.idxHandles[0]);
|
||||||
TRI_ASSERT(res); // Right now we have an enforced edge index which will
|
TRI_ASSERT(res); // Right now we have an enforced edge index which will
|
||||||
// always fit.
|
// always fit.
|
||||||
opts->_baseLookupInfos.emplace_back(std::move(infoIn));
|
_options->_baseLookupInfos.emplace_back(std::move(infoIn));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -844,11 +849,12 @@ void TraversalNode::fillTraversalOptions(
|
||||||
info.idxHandles[0]);
|
info.idxHandles[0]);
|
||||||
TRI_ASSERT(res); // Right now we have an enforced edge index which will
|
TRI_ASSERT(res); // Right now we have an enforced edge index which will
|
||||||
// always fit.
|
// always fit.
|
||||||
opts->_baseLookupInfos.emplace_back(std::move(info));
|
_options->_baseLookupInfos.emplace_back(std::move(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::pair<size_t, EdgeConditionBuilder> it : _edgeConditions) {
|
for (std::pair<size_t, EdgeConditionBuilder> it : _edgeConditions) {
|
||||||
auto ins = opts->_depthLookupInfo.emplace(it.first, std::vector<traverser::TraverserOptions::LookupInfo>());
|
auto ins = _options->_depthLookupInfo.emplace(
|
||||||
|
it.first, std::vector<traverser::TraverserOptions::LookupInfo>());
|
||||||
TRI_ASSERT(ins.second);
|
TRI_ASSERT(ins.second);
|
||||||
auto& infos = ins.first->second;
|
auto& infos = ins.first->second;
|
||||||
infos.reserve(numEdgeColls);
|
infos.reserve(numEdgeColls);
|
||||||
|
@ -898,13 +904,10 @@ void TraversalNode::fillTraversalOptions(
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& it : _vertexConditions) {
|
for (auto& it : _vertexConditions) {
|
||||||
opts->_vertexExpressions.emplace(it.first, new Expression(ast, it.second));
|
_options->_vertexExpressions.emplace(it.first, new Expression(ast, it.second));
|
||||||
TRI_ASSERT(!opts->_vertexExpressions[it.first]->isV8());
|
TRI_ASSERT(!_options->_vertexExpressions[it.first]->isV8());
|
||||||
}
|
}
|
||||||
|
_optionsBuild = true;
|
||||||
opts->useBreadthFirst = _options.useBreadthFirst;
|
|
||||||
opts->uniqueVertices = _options.uniqueVertices;
|
|
||||||
opts->uniqueEdges = _options.uniqueEdges;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief remember the condition to execute for early traversal abortion.
|
/// @brief remember the condition to execute for early traversal abortion.
|
||||||
|
@ -964,6 +967,10 @@ void TraversalNode::registerGlobalCondition(bool isConditionOnEdge,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
arangodb::traverser::TraverserOptions* TraversalNode::options() const {
|
||||||
|
return _options.get();
|
||||||
|
}
|
||||||
|
|
||||||
AstNode* TraversalNode::getTemporaryRefNode() const {
|
AstNode* TraversalNode::getTemporaryRefNode() const {
|
||||||
return _tmpObjVarNode;
|
return _tmpObjVarNode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ class TraversalNode : public ExecutionNode {
|
||||||
TraversalNode(ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase,
|
TraversalNode(ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase,
|
||||||
AstNode const* direction, AstNode const* start,
|
AstNode const* direction, AstNode const* start,
|
||||||
AstNode const* graph,
|
AstNode const* graph,
|
||||||
traverser::TraverserOptions const& options);
|
std::unique_ptr<traverser::TraverserOptions>& options);
|
||||||
|
|
||||||
TraversalNode(ExecutionPlan* plan, arangodb::basics::Json const& base);
|
TraversalNode(ExecutionPlan* plan, arangodb::basics::Json const& base);
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ class TraversalNode : public ExecutionNode {
|
||||||
std::vector<std::string> const& edgeColls,
|
std::vector<std::string> const& edgeColls,
|
||||||
Variable const* inVariable, std::string const& vertexId,
|
Variable const* inVariable, std::string const& vertexId,
|
||||||
std::vector<TRI_edge_direction_e> directions,
|
std::vector<TRI_edge_direction_e> directions,
|
||||||
traverser::TraverserOptions const& options);
|
std::unique_ptr<traverser::TraverserOptions>& options);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @brief return the type of the node
|
/// @brief return the type of the node
|
||||||
|
@ -192,11 +192,6 @@ class TraversalNode : public ExecutionNode {
|
||||||
|
|
||||||
std::string const getStartVertex() const { return _vertexId; }
|
std::string const getStartVertex() const { return _vertexId; }
|
||||||
|
|
||||||
/// @brief Fill the traversal options with all values known to this node or
|
|
||||||
/// with default values.
|
|
||||||
void fillTraversalOptions(arangodb::traverser::TraverserOptions* opts,
|
|
||||||
arangodb::Transaction*) const;
|
|
||||||
|
|
||||||
std::vector<std::string> const edgeColls() const { return _edgeColls; }
|
std::vector<std::string> const edgeColls() const { return _edgeColls; }
|
||||||
|
|
||||||
/// @brief remember the condition to execute for early traversal abortion.
|
/// @brief remember the condition to execute for early traversal abortion.
|
||||||
|
@ -225,17 +220,26 @@ class TraversalNode : public ExecutionNode {
|
||||||
|
|
||||||
void specializeToNeighborsSearch();
|
void specializeToNeighborsSearch();
|
||||||
|
|
||||||
traverser::TraverserOptions const* options() const { return &_options; }
|
traverser::TraverserOptions* options() const;
|
||||||
|
|
||||||
AstNode* getTemporaryRefNode() const;
|
AstNode* getTemporaryRefNode() const;
|
||||||
|
|
||||||
void getConditionVariables(std::vector<Variable const*>&) const;
|
void getConditionVariables(std::vector<Variable const*>&) const;
|
||||||
|
|
||||||
|
/// @brief Compute the traversal options containing the expressions
|
||||||
|
/// MUST! be called after optimization and before creation
|
||||||
|
/// of blocks.
|
||||||
|
void prepareOptions();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
#ifdef TRI_ENABLE_MAINTAINER_MODE
|
#ifdef TRI_ENABLE_MAINTAINER_MODE
|
||||||
void checkConditionsDefined() const;
|
void checkConditionsDefined() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// @brief the database
|
/// @brief the database
|
||||||
TRI_vocbase_t* _vocbase;
|
TRI_vocbase_t* _vocbase;
|
||||||
|
|
||||||
|
@ -273,7 +277,7 @@ class TraversalNode : public ExecutionNode {
|
||||||
std::unordered_set<Variable const*> _conditionVariables;
|
std::unordered_set<Variable const*> _conditionVariables;
|
||||||
|
|
||||||
/// @brief Options for traversals
|
/// @brief Options for traversals
|
||||||
traverser::TraverserOptions _options;
|
std::unique_ptr<traverser::TraverserOptions> _options;
|
||||||
|
|
||||||
/// @brief Defines if you use a specialized neighbors search instead of general purpose
|
/// @brief Defines if you use a specialized neighbors search instead of general purpose
|
||||||
/// traversal
|
/// traversal
|
||||||
|
@ -309,6 +313,11 @@ class TraversalNode : public ExecutionNode {
|
||||||
/// @brief List of all depth specific conditions for vertices
|
/// @brief List of all depth specific conditions for vertices
|
||||||
std::unordered_map<size_t, AstNode*> _vertexConditions;
|
std::unordered_map<size_t, AstNode*> _vertexConditions;
|
||||||
|
|
||||||
|
/// @brief Flag if options are already prepared. After
|
||||||
|
/// this flag was set the node cannot be cloned
|
||||||
|
/// any more.
|
||||||
|
bool _optionsBuild;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace arangodb::aql
|
} // namespace arangodb::aql
|
||||||
|
|
|
@ -116,8 +116,20 @@ void arangodb::traverser::TraverserOptions::LookupInfo::buildEngineInfo(
|
||||||
}
|
}
|
||||||
|
|
||||||
arangodb::traverser::TraverserOptions::TraverserOptions(
|
arangodb::traverser::TraverserOptions::TraverserOptions(
|
||||||
arangodb::Transaction* trx, Json const& json) {
|
arangodb::Transaction* trx, Json const& json)
|
||||||
|
: _trx(trx),
|
||||||
|
_tmpVar(nullptr),
|
||||||
|
_ctx(new aql::FixedVarExpressionContext()),
|
||||||
|
minDepth(1),
|
||||||
|
maxDepth(1),
|
||||||
|
useBreadthFirst(false),
|
||||||
|
uniqueVertices(UniquenessLevel::NONE),
|
||||||
|
uniqueEdges(UniquenessLevel::PATH) {
|
||||||
Json obj = json.get("traversalFlags");
|
Json obj = json.get("traversalFlags");
|
||||||
|
|
||||||
|
minDepth = JsonHelper::getNumericValue<uint64_t>(obj.json(), "minDepth", 1);
|
||||||
|
maxDepth = JsonHelper::getNumericValue<uint64_t>(obj.json(), "maxDepth", 1);
|
||||||
|
TRI_ASSERT(minDepth <= maxDepth);
|
||||||
useBreadthFirst = JsonHelper::getBooleanValue(obj.json(), "bfs", false);
|
useBreadthFirst = JsonHelper::getBooleanValue(obj.json(), "bfs", false);
|
||||||
std::string tmp = JsonHelper::getStringValue(obj.json(), "uniqueVertices", "");
|
std::string tmp = JsonHelper::getStringValue(obj.json(), "uniqueVertices", "");
|
||||||
if (tmp == "path") {
|
if (tmp == "path") {
|
||||||
|
@ -146,7 +158,14 @@ arangodb::traverser::TraverserOptions::TraverserOptions(
|
||||||
|
|
||||||
arangodb::traverser::TraverserOptions::TraverserOptions(
|
arangodb::traverser::TraverserOptions::TraverserOptions(
|
||||||
arangodb::aql::Query* query, VPackSlice info, VPackSlice collections)
|
arangodb::aql::Query* query, VPackSlice info, VPackSlice collections)
|
||||||
: _trx(query->trx()), _ctx(new aql::FixedVarExpressionContext()) {
|
: _trx(query->trx()),
|
||||||
|
_tmpVar(nullptr),
|
||||||
|
_ctx(new aql::FixedVarExpressionContext()),
|
||||||
|
minDepth(1),
|
||||||
|
maxDepth(1),
|
||||||
|
useBreadthFirst(false),
|
||||||
|
uniqueVertices(UniquenessLevel::NONE),
|
||||||
|
uniqueEdges(UniquenessLevel::PATH) {
|
||||||
// NOTE collections is an array of arrays of strings
|
// NOTE collections is an array of arrays of strings
|
||||||
VPackSlice read = info.get("minDepth");
|
VPackSlice read = info.get("minDepth");
|
||||||
if (!read.isInteger()) {
|
if (!read.isInteger()) {
|
||||||
|
@ -271,6 +290,22 @@ arangodb::traverser::TraverserOptions::TraverserOptions(
|
||||||
_tmpVar = query->ast()->variables()->createVariable(read);
|
_tmpVar = query->ast()->variables()->createVariable(read);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
arangodb::traverser::TraverserOptions::TraverserOptions(
|
||||||
|
TraverserOptions const& other)
|
||||||
|
: _trx(other._trx),
|
||||||
|
_tmpVar(nullptr),
|
||||||
|
_ctx(new aql::FixedVarExpressionContext()),
|
||||||
|
minDepth(other.minDepth),
|
||||||
|
maxDepth(other.maxDepth),
|
||||||
|
useBreadthFirst(other.useBreadthFirst),
|
||||||
|
uniqueVertices(other.uniqueVertices),
|
||||||
|
uniqueEdges(other.uniqueEdges) {
|
||||||
|
TRI_ASSERT(other._baseLookupInfos.empty());
|
||||||
|
TRI_ASSERT(other._depthLookupInfo.empty());
|
||||||
|
TRI_ASSERT(other._vertexExpressions.empty());
|
||||||
|
TRI_ASSERT(other._tmpVar == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
arangodb::traverser::TraverserOptions::~TraverserOptions() {
|
arangodb::traverser::TraverserOptions::~TraverserOptions() {
|
||||||
for (auto& pair : _vertexExpressions) {
|
for (auto& pair : _vertexExpressions) {
|
||||||
if (pair.second != nullptr) {
|
if (pair.second != nullptr) {
|
||||||
|
@ -282,24 +317,11 @@ arangodb::traverser::TraverserOptions::~TraverserOptions() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
arangodb::traverser::TraverserOptions::TraverserOptions(TraverserOptions const& other) {
|
|
||||||
TRI_ASSERT(_baseLookupInfos.empty());
|
|
||||||
TRI_ASSERT(_depthLookupInfo.empty());
|
|
||||||
TRI_ASSERT(_vertexExpressions.empty());
|
|
||||||
TRI_ASSERT(_tmpVar == nullptr);
|
|
||||||
|
|
||||||
_trx = other._trx;
|
|
||||||
_ctx = new aql::FixedVarExpressionContext();
|
|
||||||
minDepth = other.minDepth;
|
|
||||||
maxDepth = other.maxDepth;
|
|
||||||
useBreadthFirst = other.useBreadthFirst;
|
|
||||||
uniqueVertices = other.uniqueVertices;
|
|
||||||
uniqueEdges = other.uniqueEdges;
|
|
||||||
}
|
|
||||||
|
|
||||||
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("maxDepth", VPackValue(maxDepth));
|
||||||
builder.add("bfs", VPackValue(useBreadthFirst));
|
builder.add("bfs", VPackValue(useBreadthFirst));
|
||||||
|
|
||||||
switch (uniqueVertices) {
|
switch (uniqueVertices) {
|
||||||
|
|
|
@ -108,25 +108,25 @@ struct TraverserOptions {
|
||||||
|
|
||||||
explicit TraverserOptions(arangodb::Transaction* trx)
|
explicit TraverserOptions(arangodb::Transaction* trx)
|
||||||
: _trx(trx),
|
: _trx(trx),
|
||||||
|
_tmpVar(nullptr),
|
||||||
_ctx(new aql::FixedVarExpressionContext()),
|
_ctx(new aql::FixedVarExpressionContext()),
|
||||||
minDepth(1),
|
minDepth(1),
|
||||||
maxDepth(1),
|
maxDepth(1),
|
||||||
useBreadthFirst(false),
|
useBreadthFirst(false),
|
||||||
uniqueVertices(UniquenessLevel::NONE),
|
uniqueVertices(UniquenessLevel::NONE),
|
||||||
uniqueEdges(UniquenessLevel::PATH) {
|
uniqueEdges(UniquenessLevel::PATH) {}
|
||||||
}
|
|
||||||
|
|
||||||
TraverserOptions(arangodb::Transaction*, arangodb::basics::Json const&);
|
TraverserOptions(arangodb::Transaction*, arangodb::basics::Json const&);
|
||||||
|
|
||||||
TraverserOptions(arangodb::aql::Query*, arangodb::velocypack::Slice,
|
TraverserOptions(arangodb::aql::Query*, arangodb::velocypack::Slice,
|
||||||
arangodb::velocypack::Slice);
|
arangodb::velocypack::Slice);
|
||||||
|
|
||||||
~TraverserOptions();
|
|
||||||
|
|
||||||
/// @brief This copy constructor is only working during planning phase.
|
/// @brief This copy constructor is only working during planning phase.
|
||||||
/// After planning this node should not be copied anywhere.
|
/// After planning this node should not be copied anywhere.
|
||||||
TraverserOptions(TraverserOptions const&);
|
TraverserOptions(TraverserOptions const&);
|
||||||
|
|
||||||
|
~TraverserOptions();
|
||||||
|
|
||||||
/// @brief Build a velocypack for cloning in the plan.
|
/// @brief Build a velocypack for cloning in the plan.
|
||||||
void toVelocyPack(arangodb::velocypack::Builder&) const;
|
void toVelocyPack(arangodb::velocypack::Builder&) const;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue