1
0
Fork 0

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:
Michael Hackstein 2016-07-29 17:07:40 +02:00
parent 207d978afc
commit 5ee93a8d6c
8 changed files with 122 additions and 82 deletions

View File

@ -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) {

View File

@ -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(),

View File

@ -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();

View File

@ -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;

View File

@ -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;
} }

View File

@ -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

View File

@ -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) {

View File

@ -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;