mirror of https://gitee.com/bigwinds/arangodb
Factorized BaseOptions out of TraverserOptions. Those should be used in common for ShortestPath and Traversals. Right now only traverser use it.
This commit is contained in:
parent
bb25adf0e6
commit
d9dbf2111a
|
@ -217,10 +217,11 @@ SET(ARANGOD_SOURCES
|
||||||
GeneralServer/RestHandlerFactory.cpp
|
GeneralServer/RestHandlerFactory.cpp
|
||||||
GeneralServer/RestStatus.cpp
|
GeneralServer/RestStatus.cpp
|
||||||
GeneralServer/VppCommTask.cpp
|
GeneralServer/VppCommTask.cpp
|
||||||
Graph/BreadthFirstEnumerator.cpp
|
|
||||||
Graph/NeighborsEnumerator.cpp
|
|
||||||
Graph/AttributeWeightShortestPathFinder.cpp
|
Graph/AttributeWeightShortestPathFinder.cpp
|
||||||
|
Graph/BaseOptions.cpp
|
||||||
|
Graph/BreadthFirstEnumerator.cpp
|
||||||
Graph/ConstantWeightShortestPathFinder.cpp
|
Graph/ConstantWeightShortestPathFinder.cpp
|
||||||
|
Graph/NeighborsEnumerator.cpp
|
||||||
Indexes/Index.cpp
|
Indexes/Index.cpp
|
||||||
Indexes/IndexIterator.cpp
|
Indexes/IndexIterator.cpp
|
||||||
Indexes/SimpleAttributeEqualityMatcher.cpp
|
Indexes/SimpleAttributeEqualityMatcher.cpp
|
||||||
|
|
|
@ -0,0 +1,355 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// DISCLAIMER
|
||||||
|
///
|
||||||
|
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
|
||||||
|
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
/// you may not use this file except in compliance with the License.
|
||||||
|
/// You may obtain a copy of the License at
|
||||||
|
///
|
||||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
///
|
||||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
/// See the License for the specific language governing permissions and
|
||||||
|
/// limitations under the License.
|
||||||
|
///
|
||||||
|
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// @author Michael Hackstein
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "BaseOptions.h"
|
||||||
|
#include "Aql/Ast.h"
|
||||||
|
#include "Aql/Expression.h"
|
||||||
|
#include "Aql/Query.h"
|
||||||
|
#include "Indexes/Index.h"
|
||||||
|
#include "VocBase/TraverserCache.h"
|
||||||
|
|
||||||
|
#include <velocypack/Builder.h>
|
||||||
|
#include <velocypack/Iterator.h>
|
||||||
|
#include <velocypack/Slice.h>
|
||||||
|
#include <velocypack/velocypack-aliases.h>
|
||||||
|
|
||||||
|
using namespace arangodb;
|
||||||
|
using namespace arangodb::graph;
|
||||||
|
using namespace arangodb::traverser;
|
||||||
|
|
||||||
|
BaseOptions::LookupInfo::LookupInfo()
|
||||||
|
: expression(nullptr),
|
||||||
|
indexCondition(nullptr),
|
||||||
|
conditionNeedUpdate(false),
|
||||||
|
conditionMemberToUpdate(0) {
|
||||||
|
// NOTE: We need exactly one in this case for the optimizer to update
|
||||||
|
idxHandles.resize(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
BaseOptions::LookupInfo::~LookupInfo() {
|
||||||
|
if (expression != nullptr) {
|
||||||
|
delete expression;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseOptions::LookupInfo::LookupInfo(arangodb::aql::Query* query,
|
||||||
|
VPackSlice const& info,
|
||||||
|
VPackSlice const& shards) {
|
||||||
|
TRI_ASSERT(shards.isArray());
|
||||||
|
idxHandles.reserve(shards.length());
|
||||||
|
|
||||||
|
conditionNeedUpdate = arangodb::basics::VelocyPackHelper::getBooleanValue(
|
||||||
|
info, "condNeedUpdate", false);
|
||||||
|
conditionMemberToUpdate =
|
||||||
|
arangodb::basics::VelocyPackHelper::getNumericValue<size_t>(
|
||||||
|
info, "condMemberToUpdate", 0);
|
||||||
|
|
||||||
|
VPackSlice read = info.get("handle");
|
||||||
|
if (!read.isObject()) {
|
||||||
|
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||||
|
TRI_ERROR_BAD_PARAMETER, "Each lookup requires handle to be an object");
|
||||||
|
}
|
||||||
|
|
||||||
|
read = read.get("id");
|
||||||
|
if (!read.isString()) {
|
||||||
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER,
|
||||||
|
"Each handle requires id to be a string");
|
||||||
|
}
|
||||||
|
std::string idxId = read.copyString();
|
||||||
|
auto trx = query->trx();
|
||||||
|
|
||||||
|
for (auto const& it : VPackArrayIterator(shards)) {
|
||||||
|
if (!it.isString()) {
|
||||||
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER,
|
||||||
|
"Shards have to be a list of strings");
|
||||||
|
}
|
||||||
|
idxHandles.emplace_back(trx->getIndexByIdentifier(it.copyString(), idxId));
|
||||||
|
}
|
||||||
|
|
||||||
|
read = info.get("expression");
|
||||||
|
if (!read.isObject()) {
|
||||||
|
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||||
|
TRI_ERROR_BAD_PARAMETER,
|
||||||
|
"Each lookup requires expression to be an object");
|
||||||
|
}
|
||||||
|
|
||||||
|
expression = new aql::Expression(query->ast(), read);
|
||||||
|
|
||||||
|
read = info.get("condition");
|
||||||
|
if (!read.isObject()) {
|
||||||
|
THROW_ARANGO_EXCEPTION_MESSAGE(
|
||||||
|
TRI_ERROR_BAD_PARAMETER,
|
||||||
|
"Each lookup requires condition to be an object");
|
||||||
|
}
|
||||||
|
indexCondition = new aql::AstNode(query->ast(), read);
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseOptions::LookupInfo::LookupInfo(LookupInfo const& other)
|
||||||
|
: idxHandles(other.idxHandles),
|
||||||
|
expression(nullptr),
|
||||||
|
indexCondition(other.indexCondition),
|
||||||
|
conditionNeedUpdate(other.conditionNeedUpdate),
|
||||||
|
conditionMemberToUpdate(other.conditionMemberToUpdate) {
|
||||||
|
expression = other.expression->clone(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseOptions::LookupInfo::buildEngineInfo(VPackBuilder& result) const {
|
||||||
|
result.openObject();
|
||||||
|
result.add(VPackValue("handle"));
|
||||||
|
// We only run toVelocyPack on Coordinator.
|
||||||
|
TRI_ASSERT(idxHandles.size() == 1);
|
||||||
|
result.openObject();
|
||||||
|
idxHandles[0].toVelocyPack(result, false);
|
||||||
|
result.close();
|
||||||
|
result.add(VPackValue("expression"));
|
||||||
|
result.openObject(); // We need to encapsulate the expression into an
|
||||||
|
// expression object
|
||||||
|
result.add(VPackValue("expression"));
|
||||||
|
expression->toVelocyPack(result, true);
|
||||||
|
result.close();
|
||||||
|
result.add(VPackValue("condition"));
|
||||||
|
indexCondition->toVelocyPack(result, true);
|
||||||
|
result.add("condNeedUpdate", VPackValue(conditionNeedUpdate));
|
||||||
|
result.add("condMemberToUpdate", VPackValue(conditionMemberToUpdate));
|
||||||
|
result.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
double BaseOptions::LookupInfo::estimateCost(size_t& nrItems) const {
|
||||||
|
// If we do not have an index yet we cannot do anything.
|
||||||
|
// Should NOT be the case
|
||||||
|
TRI_ASSERT(!idxHandles.empty());
|
||||||
|
auto idx = idxHandles[0].getIndex();
|
||||||
|
if (idx->hasSelectivityEstimate()) {
|
||||||
|
double expected = 1 / idx->selectivityEstimate();
|
||||||
|
nrItems += static_cast<size_t>(expected);
|
||||||
|
return expected;
|
||||||
|
}
|
||||||
|
// Some hard-coded value
|
||||||
|
nrItems += 1000;
|
||||||
|
return 1000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseOptions::BaseOptions(transaction::Methods* trx)
|
||||||
|
: _ctx(new aql::FixedVarExpressionContext()),
|
||||||
|
_trx(trx),
|
||||||
|
_tmpVar(nullptr),
|
||||||
|
_isCoordinator(arangodb::ServerState::instance()->isCoordinator()),
|
||||||
|
_cache(std::make_unique<TraverserCache>(_trx)) {}
|
||||||
|
|
||||||
|
BaseOptions::BaseOptions(BaseOptions const& other)
|
||||||
|
: _ctx(new aql::FixedVarExpressionContext()),
|
||||||
|
_trx(other._trx),
|
||||||
|
_tmpVar(nullptr),
|
||||||
|
_isCoordinator(arangodb::ServerState::instance()->isCoordinator()),
|
||||||
|
_cache(std::make_unique<TraverserCache>(_trx)) {
|
||||||
|
TRI_ASSERT(other._baseLookupInfos.empty());
|
||||||
|
TRI_ASSERT(other._tmpVar == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseOptions::BaseOptions(arangodb::aql::Query* query, VPackSlice info,
|
||||||
|
VPackSlice collections)
|
||||||
|
: _ctx(new aql::FixedVarExpressionContext()),
|
||||||
|
_trx(query->trx()),
|
||||||
|
_tmpVar(nullptr),
|
||||||
|
_isCoordinator(arangodb::ServerState::instance()->isCoordinator()),
|
||||||
|
_cache(std::make_unique<TraverserCache>(_trx)) {
|
||||||
|
VPackSlice read = info.get("tmpVar");
|
||||||
|
if (!read.isObject()) {
|
||||||
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER,
|
||||||
|
"The options require a tmpVar");
|
||||||
|
}
|
||||||
|
_tmpVar = query->ast()->variables()->createVariable(read);
|
||||||
|
|
||||||
|
read = info.get("baseLookupInfos");
|
||||||
|
if (!read.isArray()) {
|
||||||
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER,
|
||||||
|
"The options require a baseLookupInfos");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length = read.length();
|
||||||
|
TRI_ASSERT(read.length() == collections.length());
|
||||||
|
_baseLookupInfos.reserve(length);
|
||||||
|
for (size_t j = 0; j < length; ++j) {
|
||||||
|
_baseLookupInfos.emplace_back(query, read.at(j), collections.at(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseOptions::~BaseOptions() { delete _ctx; }
|
||||||
|
|
||||||
|
void BaseOptions::toVelocyPackIndexes(VPackBuilder& builder) const {
|
||||||
|
builder.openObject();
|
||||||
|
injectVelocyPackIndexes(builder);
|
||||||
|
builder.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseOptions::buildEngineInfo(VPackBuilder& result) const {
|
||||||
|
result.openObject();
|
||||||
|
injectEngineInfo(result);
|
||||||
|
result.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseOptions::setVariable(aql::Variable const* variable) {
|
||||||
|
_tmpVar = variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseOptions::addLookupInfo(aql::Ast* ast,
|
||||||
|
std::string const& collectionName,
|
||||||
|
std::string const& attributeName,
|
||||||
|
aql::AstNode* condition) {
|
||||||
|
injectLookupInfoInList(_baseLookupInfos, ast, collectionName, attributeName,
|
||||||
|
condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseOptions::injectLookupInfoInList(std::vector<LookupInfo>& list,
|
||||||
|
aql::Ast* ast,
|
||||||
|
std::string const& collectionName,
|
||||||
|
std::string const& attributeName,
|
||||||
|
aql::AstNode* condition) {
|
||||||
|
LookupInfo info;
|
||||||
|
info.indexCondition = condition;
|
||||||
|
info.expression = new aql::Expression(ast, condition->clone(ast));
|
||||||
|
bool res = _trx->getBestIndexHandleForFilterCondition(
|
||||||
|
collectionName, info.indexCondition, _tmpVar, 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<arangodb::aql::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 != arangodb::aql::AstNodeType::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 != _tmpVar) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (pathCmp.second.size() == 1 &&
|
||||||
|
pathCmp.second[0].name == attributeName) {
|
||||||
|
info.conditionNeedUpdate = true;
|
||||||
|
info.conditionMemberToUpdate = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list.emplace_back(std::move(info));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseOptions::clearVariableValues() { _ctx->clearVariableValues(); }
|
||||||
|
|
||||||
|
void BaseOptions::setVariableValue(aql::Variable const* var,
|
||||||
|
aql::AqlValue const value) {
|
||||||
|
_ctx->setVariableValue(var, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseOptions::serializeVariables(VPackBuilder& builder) const {
|
||||||
|
TRI_ASSERT(builder.isOpenArray());
|
||||||
|
_ctx->serializeAllVariables(_trx, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
arangodb::transaction::Methods* BaseOptions::trx() const { return _trx; }
|
||||||
|
|
||||||
|
arangodb::traverser::TraverserCache* BaseOptions::cache() const {
|
||||||
|
return _cache.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseOptions::injectVelocyPackIndexes(VPackBuilder& builder) const {
|
||||||
|
TRI_ASSERT(builder.isOpenObject());
|
||||||
|
|
||||||
|
// base indexes
|
||||||
|
builder.add("base", VPackValue(VPackValueType::Array));
|
||||||
|
for (auto const& it : _baseLookupInfos) {
|
||||||
|
for (auto const& it2 : it.idxHandles) {
|
||||||
|
builder.openObject();
|
||||||
|
it2.getIndex()->toVelocyPack(builder, false);
|
||||||
|
builder.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseOptions::injectEngineInfo(VPackBuilder& result) const {
|
||||||
|
TRI_ASSERT(result.isOpenObject());
|
||||||
|
result.add(VPackValue("baseLookupInfos"));
|
||||||
|
result.openArray();
|
||||||
|
for (auto const& it : _baseLookupInfos) {
|
||||||
|
it.buildEngineInfo(result);
|
||||||
|
}
|
||||||
|
result.close();
|
||||||
|
|
||||||
|
result.add(VPackValue("tmpVar"));
|
||||||
|
_tmpVar->toVelocyPack(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
arangodb::aql::Expression* BaseOptions::getEdgeExpression(
|
||||||
|
size_t cursorId) const {
|
||||||
|
TRI_ASSERT(!_baseLookupInfos.empty());
|
||||||
|
TRI_ASSERT(_baseLookupInfos.size() > cursorId);
|
||||||
|
return _baseLookupInfos[cursorId].expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BaseOptions::evaluateExpression(arangodb::aql::Expression* expression,
|
||||||
|
VPackSlice value) const {
|
||||||
|
if (expression == nullptr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRI_ASSERT(!expression->isV8());
|
||||||
|
expression->setVariable(_tmpVar, value);
|
||||||
|
bool mustDestroy = false;
|
||||||
|
aql::AqlValue res = expression->execute(_trx, _ctx, mustDestroy);
|
||||||
|
TRI_ASSERT(res.isBoolean());
|
||||||
|
bool result = res.toBoolean();
|
||||||
|
expression->clearVariable(_tmpVar);
|
||||||
|
if (mustDestroy) {
|
||||||
|
res.destroy();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
double BaseOptions::costForLookupInfoList(
|
||||||
|
std::vector<BaseOptions::LookupInfo> const& list,
|
||||||
|
size_t& createItems) const {
|
||||||
|
double cost = 0;
|
||||||
|
createItems = 0;
|
||||||
|
for (auto const& li : list) {
|
||||||
|
cost += li.estimateCost(createItems);
|
||||||
|
}
|
||||||
|
return cost;
|
||||||
|
}
|
|
@ -0,0 +1,163 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// DISCLAIMER
|
||||||
|
///
|
||||||
|
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
|
||||||
|
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
/// you may not use this file except in compliance with the License.
|
||||||
|
/// You may obtain a copy of the License at
|
||||||
|
///
|
||||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
///
|
||||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
/// See the License for the specific language governing permissions and
|
||||||
|
/// limitations under the License.
|
||||||
|
///
|
||||||
|
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// @author Michael Hackstein
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef ARANGOD_GRAPH_BASE_OPTIONS_H
|
||||||
|
#define ARANGOD_GRAPH_BASE_OPTIONS_H 1
|
||||||
|
|
||||||
|
#include "Basics/Common.h"
|
||||||
|
#include "Aql/FixedVarExpressionContext.h"
|
||||||
|
#include "Cluster/ServerState.h"
|
||||||
|
#include "Transaction/Methods.h"
|
||||||
|
|
||||||
|
namespace arangodb {
|
||||||
|
|
||||||
|
namespace aql {
|
||||||
|
class AstNode;
|
||||||
|
class Expression;
|
||||||
|
class Query;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace traverser {
|
||||||
|
class TraverserCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace velocypack {
|
||||||
|
class Builder;
|
||||||
|
class Slice;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace graph {
|
||||||
|
|
||||||
|
struct BaseOptions {
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
struct LookupInfo {
|
||||||
|
// This struct does only take responsibility for the expression
|
||||||
|
// NOTE: The expression can be nullptr!
|
||||||
|
std::vector<transaction::Methods::IndexHandle> idxHandles;
|
||||||
|
aql::Expression* expression;
|
||||||
|
aql::AstNode* indexCondition;
|
||||||
|
// Flag if we have to update _from / _to in the index search condition
|
||||||
|
bool conditionNeedUpdate;
|
||||||
|
// Position of _from / _to in the index search condition
|
||||||
|
size_t conditionMemberToUpdate;
|
||||||
|
|
||||||
|
LookupInfo();
|
||||||
|
~LookupInfo();
|
||||||
|
|
||||||
|
LookupInfo(LookupInfo const&);
|
||||||
|
|
||||||
|
LookupInfo(arangodb::aql::Query*, arangodb::velocypack::Slice const&,
|
||||||
|
arangodb::velocypack::Slice const&);
|
||||||
|
|
||||||
|
/// @brief Build a velocypack containing all relevant information
|
||||||
|
/// for DBServer traverser engines.
|
||||||
|
void buildEngineInfo(arangodb::velocypack::Builder&) const;
|
||||||
|
|
||||||
|
double estimateCost(size_t& nrItems) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BaseOptions(transaction::Methods* trx);
|
||||||
|
|
||||||
|
/// @brief This copy constructor is only working during planning phase.
|
||||||
|
/// After planning this node should not be copied anywhere.
|
||||||
|
explicit BaseOptions(BaseOptions const&);
|
||||||
|
|
||||||
|
BaseOptions(arangodb::aql::Query*, arangodb::velocypack::Slice,
|
||||||
|
arangodb::velocypack::Slice);
|
||||||
|
|
||||||
|
virtual ~BaseOptions();
|
||||||
|
|
||||||
|
// Creates a complete Object containing all EngineInfo
|
||||||
|
// in the given builder.
|
||||||
|
virtual void buildEngineInfo(arangodb::velocypack::Builder&) const;
|
||||||
|
|
||||||
|
void setVariable(aql::Variable const*);
|
||||||
|
|
||||||
|
void addLookupInfo(aql::Ast* ast, std::string const& collectionName,
|
||||||
|
std::string const& attributeName, aql::AstNode* condition);
|
||||||
|
|
||||||
|
void clearVariableValues();
|
||||||
|
|
||||||
|
void setVariableValue(aql::Variable const*, aql::AqlValue const);
|
||||||
|
|
||||||
|
void serializeVariables(arangodb::velocypack::Builder&) const;
|
||||||
|
|
||||||
|
transaction::Methods* trx() const;
|
||||||
|
|
||||||
|
traverser::TraverserCache* cache() const;
|
||||||
|
|
||||||
|
/// @brief Build a velocypack for cloning in the plan.
|
||||||
|
virtual void toVelocyPack(arangodb::velocypack::Builder&) const = 0;
|
||||||
|
|
||||||
|
// Creates a complete Object containing all index information
|
||||||
|
// in the given builder.
|
||||||
|
virtual void toVelocyPackIndexes(arangodb::velocypack::Builder&) const;
|
||||||
|
|
||||||
|
/// @brief Estimate the total cost for this operation
|
||||||
|
virtual double estimateCost(size_t& nrItems) const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
double costForLookupInfoList(std::vector<LookupInfo> const& list,
|
||||||
|
size_t& createItems) const;
|
||||||
|
|
||||||
|
// Requires an open Object in the given builder an
|
||||||
|
// will inject index information into it.
|
||||||
|
// Does not close the builder.
|
||||||
|
void injectVelocyPackIndexes(arangodb::velocypack::Builder&) const;
|
||||||
|
|
||||||
|
// Requires an open Object in the given builder an
|
||||||
|
// will inject EngineInfo into it.
|
||||||
|
// Does not close the builder.
|
||||||
|
void injectEngineInfo(arangodb::velocypack::Builder&) const;
|
||||||
|
|
||||||
|
aql::Expression* getEdgeExpression(size_t cursorId) const;
|
||||||
|
|
||||||
|
bool evaluateExpression(aql::Expression*, arangodb::velocypack::Slice varValue) const;
|
||||||
|
|
||||||
|
void injectLookupInfoInList(std::vector<LookupInfo>&, aql::Ast* ast,
|
||||||
|
std::string const& collectionName,
|
||||||
|
std::string const& attributeName,
|
||||||
|
aql::AstNode* condition);
|
||||||
|
|
||||||
|
private:
|
||||||
|
aql::FixedVarExpressionContext* _ctx;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
transaction::Methods* _trx;
|
||||||
|
std::vector<LookupInfo> _baseLookupInfos;
|
||||||
|
aql::Variable const* _tmpVar;
|
||||||
|
bool const _isCoordinator;
|
||||||
|
|
||||||
|
/// @brief the traverser cache
|
||||||
|
std::unique_ptr<traverser::TraverserCache> _cache;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace graph
|
||||||
|
} // namespace arangodb
|
||||||
|
#endif
|
|
@ -47,7 +47,7 @@ SingleServerEdgeCursor::SingleServerEdgeCursor(ManagedDocumentResult* mmdr,
|
||||||
TraverserOptions* opts,
|
TraverserOptions* opts,
|
||||||
size_t nrCursors, std::vector<size_t> const* mapping)
|
size_t nrCursors, std::vector<size_t> const* mapping)
|
||||||
: _opts(opts),
|
: _opts(opts),
|
||||||
_trx(opts->_trx),
|
_trx(opts->trx()),
|
||||||
_mmdr(mmdr),
|
_mmdr(mmdr),
|
||||||
_cursors(),
|
_cursors(),
|
||||||
_currentCursor(0),
|
_currentCursor(0),
|
||||||
|
|
|
@ -35,152 +35,28 @@
|
||||||
#include <velocypack/Iterator.h>
|
#include <velocypack/Iterator.h>
|
||||||
#include <velocypack/velocypack-aliases.h>
|
#include <velocypack/velocypack-aliases.h>
|
||||||
|
|
||||||
|
using namespace arangodb;
|
||||||
|
using namespace arangodb::graph;
|
||||||
using namespace arangodb::transaction;
|
using namespace arangodb::transaction;
|
||||||
|
using namespace arangodb::traverser;
|
||||||
|
|
||||||
using VPackHelper = arangodb::basics::VelocyPackHelper;
|
using VPackHelper = arangodb::basics::VelocyPackHelper;
|
||||||
using TraverserOptions = arangodb::traverser::TraverserOptions;
|
|
||||||
|
|
||||||
arangodb::traverser::TraverserOptions::LookupInfo::LookupInfo()
|
TraverserOptions::TraverserOptions(transaction::Methods* trx)
|
||||||
: expression(nullptr),
|
: BaseOptions(trx),
|
||||||
indexCondition(nullptr),
|
|
||||||
conditionNeedUpdate(false),
|
|
||||||
conditionMemberToUpdate(0) {
|
|
||||||
// NOTE: We need exactly one in this case for the optimizer to update
|
|
||||||
idxHandles.resize(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
arangodb::traverser::TraverserOptions::LookupInfo::~LookupInfo() {
|
|
||||||
if (expression != nullptr) {
|
|
||||||
delete expression;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arangodb::traverser::TraverserOptions::LookupInfo::LookupInfo(
|
|
||||||
arangodb::aql::Query* query, VPackSlice const& info, VPackSlice const& shards) {
|
|
||||||
TRI_ASSERT(shards.isArray());
|
|
||||||
idxHandles.reserve(shards.length());
|
|
||||||
|
|
||||||
conditionNeedUpdate = arangodb::basics::VelocyPackHelper::getBooleanValue(
|
|
||||||
info, "condNeedUpdate", false);
|
|
||||||
conditionMemberToUpdate =
|
|
||||||
arangodb::basics::VelocyPackHelper::getNumericValue<size_t>(
|
|
||||||
info, "condMemberToUpdate", 0);
|
|
||||||
|
|
||||||
VPackSlice read = info.get("handle");
|
|
||||||
if (!read.isObject()) {
|
|
||||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
|
||||||
TRI_ERROR_BAD_PARAMETER,
|
|
||||||
"Each lookup requires handle to be an object");
|
|
||||||
}
|
|
||||||
|
|
||||||
read = read.get("id");
|
|
||||||
if (!read.isString()) {
|
|
||||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
|
||||||
TRI_ERROR_BAD_PARAMETER,
|
|
||||||
"Each handle requires id to be a string");
|
|
||||||
}
|
|
||||||
std::string idxId = read.copyString();
|
|
||||||
auto trx = query->trx();
|
|
||||||
|
|
||||||
for (auto const& it : VPackArrayIterator(shards)) {
|
|
||||||
if (!it.isString()) {
|
|
||||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
|
||||||
TRI_ERROR_BAD_PARAMETER,
|
|
||||||
"Shards have to be a list of strings");
|
|
||||||
}
|
|
||||||
idxHandles.emplace_back(trx->getIndexByIdentifier(it.copyString(), idxId));
|
|
||||||
}
|
|
||||||
|
|
||||||
read = info.get("expression");
|
|
||||||
if (!read.isObject()) {
|
|
||||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
|
||||||
TRI_ERROR_BAD_PARAMETER,
|
|
||||||
"Each lookup requires expression to be an object");
|
|
||||||
}
|
|
||||||
|
|
||||||
expression = new aql::Expression(query->ast(), read);
|
|
||||||
|
|
||||||
read = info.get("condition");
|
|
||||||
if (!read.isObject()) {
|
|
||||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
|
||||||
TRI_ERROR_BAD_PARAMETER,
|
|
||||||
"Each lookup requires condition to be an object");
|
|
||||||
}
|
|
||||||
indexCondition = new aql::AstNode(query->ast(), read);
|
|
||||||
}
|
|
||||||
|
|
||||||
arangodb::traverser::TraverserOptions::LookupInfo::LookupInfo(
|
|
||||||
LookupInfo const& other)
|
|
||||||
: idxHandles(other.idxHandles),
|
|
||||||
expression(nullptr),
|
|
||||||
indexCondition(other.indexCondition),
|
|
||||||
conditionNeedUpdate(other.conditionNeedUpdate),
|
|
||||||
conditionMemberToUpdate(other.conditionMemberToUpdate) {
|
|
||||||
expression = other.expression->clone(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void arangodb::traverser::TraverserOptions::LookupInfo::buildEngineInfo(
|
|
||||||
VPackBuilder& result) const {
|
|
||||||
result.openObject();
|
|
||||||
result.add(VPackValue("handle"));
|
|
||||||
// We only run toVelocyPack on Coordinator.
|
|
||||||
TRI_ASSERT(idxHandles.size() == 1);
|
|
||||||
result.openObject();
|
|
||||||
idxHandles[0].toVelocyPack(result, false);
|
|
||||||
result.close();
|
|
||||||
result.add(VPackValue("expression"));
|
|
||||||
result.openObject(); // We need to encapsulate the expression into an expression object
|
|
||||||
result.add(VPackValue("expression"));
|
|
||||||
expression->toVelocyPack(result, true);
|
|
||||||
result.close();
|
|
||||||
result.add(VPackValue("condition"));
|
|
||||||
indexCondition->toVelocyPack(result, true);
|
|
||||||
result.add("condNeedUpdate", VPackValue(conditionNeedUpdate));
|
|
||||||
result.add("condMemberToUpdate", VPackValue(conditionMemberToUpdate));
|
|
||||||
result.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
double arangodb::traverser::TraverserOptions::LookupInfo::estimateCost(size_t& nrItems) const {
|
|
||||||
// If we do not have an index yet we cannot do anything.
|
|
||||||
// Should NOT be the case
|
|
||||||
TRI_ASSERT(!idxHandles.empty());
|
|
||||||
auto idx = idxHandles[0].getIndex();
|
|
||||||
if (idx->hasSelectivityEstimate()) {
|
|
||||||
double expected = 1 / idx->selectivityEstimate();
|
|
||||||
nrItems += static_cast<size_t>(expected);
|
|
||||||
return expected;
|
|
||||||
}
|
|
||||||
// Some hard-coded value
|
|
||||||
nrItems += 1000;
|
|
||||||
return 1000.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
arangodb::traverser::TraverserCache* arangodb::traverser::TraverserOptions::cache() const {
|
|
||||||
return _cache.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
arangodb::traverser::TraverserOptions::TraverserOptions(transaction::Methods* trx)
|
|
||||||
: _trx(trx),
|
|
||||||
_baseVertexExpression(nullptr),
|
_baseVertexExpression(nullptr),
|
||||||
_tmpVar(nullptr),
|
|
||||||
_ctx(new aql::FixedVarExpressionContext()),
|
|
||||||
_traverser(nullptr),
|
_traverser(nullptr),
|
||||||
_isCoordinator(trx->state()->isCoordinator()),
|
|
||||||
_cache(new TraverserCache(trx)),
|
|
||||||
minDepth(1),
|
minDepth(1),
|
||||||
maxDepth(1),
|
maxDepth(1),
|
||||||
useBreadthFirst(false),
|
useBreadthFirst(false),
|
||||||
uniqueVertices(UniquenessLevel::NONE),
|
uniqueVertices(UniquenessLevel::NONE),
|
||||||
uniqueEdges(UniquenessLevel::PATH) {}
|
uniqueEdges(UniquenessLevel::PATH) {}
|
||||||
|
|
||||||
arangodb::traverser::TraverserOptions::TraverserOptions(
|
TraverserOptions::TraverserOptions(
|
||||||
transaction::Methods* trx, VPackSlice const& slice)
|
transaction::Methods* trx, VPackSlice const& slice)
|
||||||
: _trx(trx),
|
: BaseOptions(trx),
|
||||||
_baseVertexExpression(nullptr),
|
_baseVertexExpression(nullptr),
|
||||||
_tmpVar(nullptr),
|
|
||||||
_ctx(new aql::FixedVarExpressionContext()),
|
|
||||||
_traverser(nullptr),
|
_traverser(nullptr),
|
||||||
_isCoordinator(arangodb::ServerState::instance()->isCoordinator()),
|
|
||||||
_cache(new TraverserCache(trx)),
|
|
||||||
minDepth(1),
|
minDepth(1),
|
||||||
maxDepth(1),
|
maxDepth(1),
|
||||||
useBreadthFirst(false),
|
useBreadthFirst(false),
|
||||||
|
@ -228,13 +104,9 @@ 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()),
|
: BaseOptions(query->trx()),
|
||||||
_baseVertexExpression(nullptr),
|
_baseVertexExpression(nullptr),
|
||||||
_tmpVar(nullptr),
|
|
||||||
_ctx(new aql::FixedVarExpressionContext()),
|
|
||||||
_traverser(nullptr),
|
_traverser(nullptr),
|
||||||
_isCoordinator(arangodb::ServerState::instance()->isCoordinator()),
|
|
||||||
_cache(new TraverserCache(_trx)),
|
|
||||||
minDepth(1),
|
minDepth(1),
|
||||||
maxDepth(1),
|
maxDepth(1),
|
||||||
useBreadthFirst(false),
|
useBreadthFirst(false),
|
||||||
|
@ -387,13 +259,9 @@ arangodb::traverser::TraverserOptions::TraverserOptions(
|
||||||
|
|
||||||
arangodb::traverser::TraverserOptions::TraverserOptions(
|
arangodb::traverser::TraverserOptions::TraverserOptions(
|
||||||
TraverserOptions const& other)
|
TraverserOptions const& other)
|
||||||
: _trx(other._trx),
|
: BaseOptions(other.trx()),
|
||||||
_baseVertexExpression(nullptr),
|
_baseVertexExpression(nullptr),
|
||||||
_tmpVar(nullptr),
|
|
||||||
_ctx(new aql::FixedVarExpressionContext()),
|
|
||||||
_traverser(nullptr),
|
_traverser(nullptr),
|
||||||
_isCoordinator(arangodb::ServerState::instance()->isCoordinator()),
|
|
||||||
_cache(new TraverserCache(_trx)),
|
|
||||||
minDepth(other.minDepth),
|
minDepth(other.minDepth),
|
||||||
maxDepth(other.maxDepth),
|
maxDepth(other.maxDepth),
|
||||||
useBreadthFirst(other.useBreadthFirst),
|
useBreadthFirst(other.useBreadthFirst),
|
||||||
|
@ -419,7 +287,6 @@ arangodb::traverser::TraverserOptions::~TraverserOptions() {
|
||||||
delete pair.second;
|
delete pair.second;
|
||||||
}
|
}
|
||||||
delete _baseVertexExpression;
|
delete _baseVertexExpression;
|
||||||
delete _ctx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void arangodb::traverser::TraverserOptions::toVelocyPack(VPackBuilder& builder) const {
|
void arangodb::traverser::TraverserOptions::toVelocyPack(VPackBuilder& builder) const {
|
||||||
|
@ -589,38 +456,27 @@ bool arangodb::traverser::TraverserOptions::evaluateEdgeExpression(
|
||||||
TRI_ASSERT(specific->second.size() > cursorId);
|
TRI_ASSERT(specific->second.size() > cursorId);
|
||||||
expression = specific->second[cursorId].expression;
|
expression = specific->second[cursorId].expression;
|
||||||
} else {
|
} else {
|
||||||
TRI_ASSERT(!_baseLookupInfos.empty());
|
expression = getEdgeExpression(cursorId);
|
||||||
TRI_ASSERT(_baseLookupInfos.size() > cursorId);
|
|
||||||
expression = _baseLookupInfos[cursorId].expression;
|
|
||||||
}
|
}
|
||||||
if (expression != nullptr) {
|
if (expression == nullptr) {
|
||||||
TRI_ASSERT(!expression->isV8());
|
return true;
|
||||||
expression->setVariable(_tmpVar, edge);
|
|
||||||
|
|
||||||
// inject _from/_to value
|
|
||||||
auto node = expression->nodeForModification();
|
|
||||||
|
|
||||||
TRI_ASSERT(node->numMembers() > 0);
|
|
||||||
auto dirCmp = node->getMemberUnchecked(node->numMembers() - 1);
|
|
||||||
TRI_ASSERT(dirCmp->type == aql::NODE_TYPE_OPERATOR_BINARY_EQ);
|
|
||||||
TRI_ASSERT(dirCmp->numMembers() == 2);
|
|
||||||
|
|
||||||
auto idNode = dirCmp->getMemberUnchecked(1);
|
|
||||||
TRI_ASSERT(idNode->type == aql::NODE_TYPE_VALUE);
|
|
||||||
TRI_ASSERT(idNode->isValueType(aql::VALUE_TYPE_STRING));
|
|
||||||
idNode->stealComputedValue();
|
|
||||||
idNode->setStringValue(vertexId.data(), vertexId.length());
|
|
||||||
|
|
||||||
bool mustDestroy = false;
|
|
||||||
aql::AqlValue res = expression->execute(_trx, _ctx, mustDestroy);
|
|
||||||
expression->clearVariable(_tmpVar);
|
|
||||||
bool result = res.toBoolean();
|
|
||||||
if (mustDestroy) {
|
|
||||||
res.destroy();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
// inject _from/_to value
|
||||||
|
auto node = expression->nodeForModification();
|
||||||
|
|
||||||
|
TRI_ASSERT(node->numMembers() > 0);
|
||||||
|
auto dirCmp = node->getMemberUnchecked(node->numMembers() - 1);
|
||||||
|
TRI_ASSERT(dirCmp->type == aql::NODE_TYPE_OPERATOR_BINARY_EQ);
|
||||||
|
TRI_ASSERT(dirCmp->numMembers() == 2);
|
||||||
|
|
||||||
|
auto idNode = dirCmp->getMemberUnchecked(1);
|
||||||
|
TRI_ASSERT(idNode->type == aql::NODE_TYPE_VALUE);
|
||||||
|
TRI_ASSERT(idNode->isValueType(aql::VALUE_TYPE_STRING));
|
||||||
|
idNode->stealComputedValue();
|
||||||
|
idNode->setStringValue(vertexId.data(), vertexId.length());
|
||||||
|
|
||||||
|
return evaluateExpression(expression, edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool arangodb::traverser::TraverserOptions::evaluateVertexExpression(
|
bool arangodb::traverser::TraverserOptions::evaluateVertexExpression(
|
||||||
|
@ -635,21 +491,7 @@ bool arangodb::traverser::TraverserOptions::evaluateVertexExpression(
|
||||||
expression = _baseVertexExpression;
|
expression = _baseVertexExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expression == nullptr) {
|
return evaluateExpression(expression, vertex);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRI_ASSERT(!expression->isV8());
|
|
||||||
expression->setVariable(_tmpVar, vertex);
|
|
||||||
bool mustDestroy = false;
|
|
||||||
aql::AqlValue res = expression->execute(_trx, _ctx, mustDestroy);
|
|
||||||
TRI_ASSERT(res.isBoolean());
|
|
||||||
bool result = res.toBoolean();
|
|
||||||
expression->clearVariable(_tmpVar);
|
|
||||||
if (mustDestroy) {
|
|
||||||
res.destroy();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
arangodb::traverser::EdgeCursor*
|
arangodb::traverser::EdgeCursor*
|
||||||
|
@ -709,37 +551,11 @@ arangodb::traverser::TraverserOptions::nextCursorCoordinator(
|
||||||
return cursor.release();
|
return cursor.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void arangodb::traverser::TraverserOptions::clearVariableValues() {
|
|
||||||
_ctx->clearVariableValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
void arangodb::traverser::TraverserOptions::setVariableValue(
|
|
||||||
aql::Variable const* var, aql::AqlValue const value) {
|
|
||||||
_ctx->setVariableValue(var, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void arangodb::traverser::TraverserOptions::linkTraverser(
|
void arangodb::traverser::TraverserOptions::linkTraverser(
|
||||||
arangodb::traverser::ClusterTraverser* trav) {
|
arangodb::traverser::ClusterTraverser* trav) {
|
||||||
_traverser = trav;
|
_traverser = trav;
|
||||||
}
|
}
|
||||||
|
|
||||||
void arangodb::traverser::TraverserOptions::serializeVariables(
|
|
||||||
VPackBuilder& builder) const {
|
|
||||||
TRI_ASSERT(builder.isOpenArray());
|
|
||||||
_ctx->serializeAllVariables(_trx, builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
double arangodb::traverser::TraverserOptions::costForLookupInfoList(
|
|
||||||
std::vector<arangodb::traverser::TraverserOptions::LookupInfo> const& list,
|
|
||||||
size_t& createItems) const {
|
|
||||||
double cost = 0;
|
|
||||||
createItems = 0;
|
|
||||||
for (auto const& li : list) {
|
|
||||||
cost += li.estimateCost(createItems);
|
|
||||||
}
|
|
||||||
return cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
#include "Basics/StringRef.h"
|
#include "Basics/StringRef.h"
|
||||||
#include "Aql/FixedVarExpressionContext.h"
|
#include "Aql/FixedVarExpressionContext.h"
|
||||||
|
#include "Graph/BaseOptions.h"
|
||||||
#include "StorageEngine/TransactionState.h"
|
#include "StorageEngine/TransactionState.h"
|
||||||
#include "Transaction/Methods.h"
|
#include "Transaction/Methods.h"
|
||||||
|
|
||||||
|
@ -62,59 +63,19 @@ class 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 {
|
|
||||||
friend class arangodb::aql::TraversalNode;
|
friend class arangodb::aql::TraversalNode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum UniquenessLevel { NONE, PATH, GLOBAL };
|
enum UniquenessLevel { NONE, PATH, GLOBAL };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
struct LookupInfo {
|
|
||||||
// This struct does only take responsibility for the expression
|
|
||||||
// NOTE: The expression can be nullptr!
|
|
||||||
std::vector<transaction::Methods::IndexHandle> idxHandles;
|
|
||||||
aql::Expression* expression;
|
|
||||||
aql::AstNode* indexCondition;
|
|
||||||
// Flag if we have to update _from / _to in the index search condition
|
|
||||||
bool conditionNeedUpdate;
|
|
||||||
// Position of _from / _to in the index search condition
|
|
||||||
size_t conditionMemberToUpdate;
|
|
||||||
|
|
||||||
LookupInfo();
|
|
||||||
~LookupInfo();
|
|
||||||
|
|
||||||
LookupInfo(LookupInfo const&);
|
|
||||||
|
|
||||||
LookupInfo(arangodb::aql::Query*, arangodb::velocypack::Slice const&,
|
|
||||||
arangodb::velocypack::Slice const&);
|
|
||||||
|
|
||||||
/// @brief Build a velocypack containing all relevant information
|
|
||||||
/// for DBServer traverser engines.
|
|
||||||
void buildEngineInfo(arangodb::velocypack::Builder&) const;
|
|
||||||
|
|
||||||
double estimateCost(size_t& nrItems) const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
transaction::Methods* _trx;
|
|
||||||
protected:
|
|
||||||
std::vector<LookupInfo> _baseLookupInfos;
|
|
||||||
std::unordered_map<uint64_t, std::vector<LookupInfo>> _depthLookupInfo;
|
std::unordered_map<uint64_t, std::vector<LookupInfo>> _depthLookupInfo;
|
||||||
std::unordered_map<uint64_t, aql::Expression*> _vertexExpressions;
|
std::unordered_map<uint64_t, aql::Expression*> _vertexExpressions;
|
||||||
aql::Expression* _baseVertexExpression;
|
aql::Expression* _baseVertexExpression;
|
||||||
aql::Variable const* _tmpVar;
|
|
||||||
aql::FixedVarExpressionContext* _ctx;
|
|
||||||
arangodb::traverser::ClusterTraverser* _traverser;
|
arangodb::traverser::ClusterTraverser* _traverser;
|
||||||
bool const _isCoordinator;
|
|
||||||
|
|
||||||
/// @brief the traverser cache
|
|
||||||
std::unique_ptr<TraverserCache> _cache;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
uint64_t minDepth;
|
uint64_t minDepth;
|
||||||
|
@ -160,23 +121,12 @@ struct TraverserOptions {
|
||||||
|
|
||||||
EdgeCursor* nextCursor(ManagedDocumentResult*, StringRef vid, uint64_t);
|
EdgeCursor* nextCursor(ManagedDocumentResult*, StringRef vid, uint64_t);
|
||||||
|
|
||||||
void clearVariableValues();
|
|
||||||
|
|
||||||
void setVariableValue(aql::Variable const*, aql::AqlValue const);
|
|
||||||
|
|
||||||
void linkTraverser(arangodb::traverser::ClusterTraverser*);
|
void linkTraverser(arangodb::traverser::ClusterTraverser*);
|
||||||
|
|
||||||
void serializeVariables(arangodb::velocypack::Builder&) const;
|
|
||||||
|
|
||||||
double estimateCost(size_t& nrItems) const;
|
double estimateCost(size_t& nrItems) const;
|
||||||
|
|
||||||
TraverserCache* cache() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
double costForLookupInfoList(std::vector<LookupInfo> const& list,
|
|
||||||
size_t& createItems) const;
|
|
||||||
|
|
||||||
EdgeCursor* nextCursorLocal(ManagedDocumentResult*,
|
EdgeCursor* nextCursorLocal(ManagedDocumentResult*,
|
||||||
StringRef vid, uint64_t,
|
StringRef vid, uint64_t,
|
||||||
std::vector<LookupInfo>&);
|
std::vector<LookupInfo>&);
|
||||||
|
|
Loading…
Reference in New Issue