1
0
Fork 0

refactoring (#9411)

This commit is contained in:
Jan 2019-07-09 11:15:52 +02:00 committed by GitHub
parent 420326be25
commit c52f2a8315
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 341 additions and 475 deletions

View File

@ -180,7 +180,7 @@ bool Constituent::logMatches(arangodb::consensus::index_t prevLogIndex,
// entry, then we know that this or a later entry was
// already committed by a majority and is therefore
// set in stone. Therefore the check must return true
// here and this is correct behaviour.
// here and this is correct behavior.
// The other case in which we do not have the log entry
// is if it is so new that we have never heard about it
// in this case we can safely return true here as well,

View File

@ -325,7 +325,7 @@ void AqlItemBlock::rescale(size_t nrItems, RegisterId nrRegs) {
// _data.capacity() might have been more accurate. Now, _data.size() stays at
// _data.capacity(), or at least, is never reduced.
// So I decided for now to report the memory usage based on numEntries() only,
// to mimic the previous behaviour. I'm not sure whether it should stay this
// to mimic the previous behavior. I'm not sure whether it should stay this
// way; because currently, we are tracking the memory we need, instead of the
// memory we have.
if (targetSize > _data.size()) {

View File

@ -208,7 +208,7 @@ std::unique_ptr<OutputAqlItemRow> ExecutionBlockImpl<Executor>::createOutputRow(
return std::make_unique<OutputAqlItemRow>(newBlock, infos().getOutputRegisters(),
infos().registersToKeep(),
infos().registersToClear(),
OutputAqlItemRow::CopyRowBehaviour::DoNotCopyInputRows);
OutputAqlItemRow::CopyRowBehavior::DoNotCopyInputRows);
} else {
return std::make_unique<OutputAqlItemRow>(newBlock, infos().getOutputRegisters(),
infos().registersToKeep(),
@ -377,7 +377,7 @@ std::pair<ExecutionState, Result> ExecutionBlockImpl<Executor>::initializeCursor
"initializeCursor method!");
InitializeCursor<customInit>::init(_executor, _rowFetcher, _infos);
// // use this with c++17 instead of specialisation below
// // use this with c++17 instead of specialization below
// if constexpr (std::is_same_v<Executor, IdExecutor>) {
// if (items != nullptr) {
// _executor._inputRegisterValues.reset(

View File

@ -30,6 +30,7 @@
#include "Aql/Function.h"
#include "Aql/IResearchViewNode.h"
#include "Aql/Optimizer.h"
#include "Aql/OptimizerRule.h"
#include "Aql/Query.h"
#include "Aql/SortCondition.h"
#include "Aql/SortNode.h"
@ -268,7 +269,7 @@ namespace iresearch {
/// @brief move filters and sort conditions into views
void handleViewsRule(arangodb::aql::Optimizer* opt,
std::unique_ptr<arangodb::aql::ExecutionPlan> plan,
arangodb::aql::OptimizerRule const* rule) {
arangodb::aql::OptimizerRule const& rule) {
TRI_ASSERT(plan && plan->getAst() && plan->getAst()->query());
// ensure 'Optimizer::addPlan' will be called
@ -340,7 +341,7 @@ void handleViewsRule(arangodb::aql::Optimizer* opt,
void scatterViewInClusterRule(arangodb::aql::Optimizer* opt,
std::unique_ptr<arangodb::aql::ExecutionPlan> plan,
arangodb::aql::OptimizerRule const* rule) {
arangodb::aql::OptimizerRule const& rule) {
TRI_ASSERT(arangodb::ServerState::instance()->isCoordinator());
bool wasModified = false;
SmallVector<ExecutionNode*>::allocator_type::arena_type a;

View File

@ -39,14 +39,14 @@ namespace iresearch {
/// @brief move filters and sort conditions into views
void handleViewsRule(arangodb::aql::Optimizer* opt,
std::unique_ptr<arangodb::aql::ExecutionPlan> plan,
arangodb::aql::OptimizerRule const* rule);
arangodb::aql::OptimizerRule const& rule);
/// @brief scatter view query in cluster
/// this rule inserts scatter, gather and remote nodes so operations on sharded
/// views
void scatterViewInClusterRule(arangodb::aql::Optimizer* opt,
std::unique_ptr<arangodb::aql::ExecutionPlan> plan,
arangodb::aql::OptimizerRule const* rule);
arangodb::aql::OptimizerRule const& rule);
} // namespace iresearch
} // namespace arangodb

View File

@ -60,9 +60,9 @@ bool Optimizer::runOnlyRequiredRules(size_t extraPlans) const {
// @brief add a plan to the optimizer
void Optimizer::addPlan(std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule, bool wasModified, int newLevel) {
OptimizerRule const& rule, bool wasModified, int newLevel) {
TRI_ASSERT(plan != nullptr);
TRI_ASSERT(&_currentRule->second.rule == rule);
TRI_ASSERT(_currentRule->second.rule.level == rule.level);
plan->setValidity(true);
@ -75,10 +75,10 @@ void Optimizer::addPlan(std::unique_ptr<ExecutionPlan> plan,
}
if (wasModified) {
if (!rule->isHidden) {
if (!rule.isHidden()) {
// register which rules modified / created the plan
// hidden rules are excluded here
plan->addAppliedRule(static_cast<int>(rule->level));
plan->addAppliedRule(static_cast<int>(rule.level));
}
plan->clearVarUsageComputed();
@ -149,20 +149,20 @@ int Optimizer::createPlans(std::unique_ptr<ExecutionPlan> plan,
auto it = _currentRule;
TRI_ASSERT(it != _rules.end());
auto& rule = it->second.rule;
auto const& rule = it->second.rule;
// skip over rules if we should
// however, we don't want to skip those rules that will not create
// additional plans
if (!it->second.enabled ||
(_runOnlyRequiredRules && rule.canCreateAdditionalPlans && rule.canBeDisabled)) {
(_runOnlyRequiredRules && rule.canCreateAdditionalPlans() && rule.canBeDisabled())) {
// we picked a disabled rule or we have reached the max number of
// plans and just skip this rule
++it; // move it to the next rule to be processed in the next
// iteration
_newPlans.push_back(std::move(p), it); // nothing to do, just keep it
if (!rule.isHidden) {
if (!rule.isHidden()) {
++_stats.rulesSkipped;
}
@ -185,9 +185,9 @@ int Optimizer::createPlans(std::unique_ptr<ExecutionPlan> plan,
// thus the rule must not have deleted the plan itself or add it
// back to the optimizer
p->setValidity(false);
rule.func(this, std::move(p), &rule);
rule.func(this, std::move(p), rule);
if (!rule.isHidden) {
if (!rule.isHidden()) {
++_stats.rulesExecuted;
}
}

View File

@ -132,7 +132,7 @@ class Optimizer {
QueryOptions const& queryOptions, bool estimateAllPlans);
/// @brief add a plan to the optimizer
void addPlan(std::unique_ptr<ExecutionPlan>, OptimizerRule const*, bool, int newLevel = 0);
void addPlan(std::unique_ptr<ExecutionPlan>, OptimizerRule const&, bool wasModified, int newLevel = 0);
void disableRule(int rule);

View File

@ -25,6 +25,8 @@
#include "Basics/Common.h"
#include <type_traits>
namespace arangodb {
namespace aql {
class ExecutionPlan;
@ -38,10 +40,49 @@ struct OptimizerRule;
/// set the level of the appended plan to the largest level of rule
/// that ought to be considered as done to indicate which rule is to be
/// applied next.
typedef std::function<void(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*)> RuleFunction;
typedef void (*RuleFunction)(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief type of an optimizer rule
struct OptimizerRule {
enum class Flags : int {
Default = 0,
Hidden = 1,
ClusterOnly = 2,
CanBeDisabled = 4,
CanCreateAdditionalPlans = 8,
};
/// @brief helper for building flags
template <typename... Args>
static std::underlying_type<Flags>::type makeFlags(Flags flag, Args... args) {
return static_cast<std::underlying_type<Flags>::type>(flag) + makeFlags(args...);
}
static std::underlying_type<Flags>::type makeFlags() {
return static_cast<std::underlying_type<Flags>::type>(Flags::Default);
}
/// @brief check a flag for the rule
bool hasFlag(Flags flag) const {
return ((flags & static_cast<std::underlying_type<Flags>::type>(flag)) != 0);
}
bool canBeDisabled() const {
return hasFlag(Flags::CanBeDisabled);
}
bool isClusterOnly() const {
return hasFlag(Flags::ClusterOnly);
}
bool isHidden() const {
return hasFlag(Flags::Hidden);
}
bool canCreateAdditionalPlans() const {
return hasFlag(Flags::CanCreateAdditionalPlans);
}
/// @brief optimizer rules
enum RuleLevel : int {
// List all the rules in the system here:
@ -56,9 +97,6 @@ struct OptimizerRule {
inlineSubqueriesRule,
// split and-combined filters into multiple smaller filters
splitFiltersRule,
/// simplify some conditions in CalculationNodes
simplifyConditionsRule,
@ -197,7 +235,9 @@ struct OptimizerRule {
// optimize queries in the cluster so that the entire query
// gets pushed to a single server
optimizeClusterSingleShardRule,
// if applied, this rule will turn all other cluster rules off
// for the current plan
clusterOneShardRule,
// make operations on sharded collections use distribute
distributeInClusterRule,
@ -250,20 +290,15 @@ struct OptimizerRule {
std::string name;
RuleFunction func;
RuleLevel const level;
bool const canCreateAdditionalPlans;
bool const canBeDisabled;
bool const isHidden;
std::underlying_type<Flags>::type const flags;
OptimizerRule() = delete;
OptimizerRule(std::string const& name, RuleFunction const& func, RuleLevel level,
bool canCreateAdditionalPlans, bool canBeDisabled, bool isHidden)
OptimizerRule(std::string const& name, RuleFunction const& func, RuleLevel level, std::underlying_type<Flags>::type flags)
: name(name),
func(func),
level(level),
canCreateAdditionalPlans(canCreateAdditionalPlans),
canBeDisabled(canBeDisabled),
isHidden(isHidden) {}
flags(flags) {}
};
} // namespace aql

View File

@ -840,7 +840,7 @@ Collection* addCollectionToQuery(Query* query, std::string const& cname, bool as
/// @brief adds a SORT operation for IN right-hand side operands
void arangodb::aql::sortInValuesRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::FILTER, true);
@ -1018,7 +1018,7 @@ void arangodb::aql::sortInValuesRule(Optimizer* opt, std::unique_ptr<ExecutionPl
/// - sorts that are covered by earlier sorts will be removed
void arangodb::aql::removeRedundantSortsRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::SORT, true);
@ -1168,7 +1168,7 @@ void arangodb::aql::removeRedundantSortsRule(Optimizer* opt,
/// - filters that are always false will be replaced by a NoResults node
void arangodb::aql::removeUnnecessaryFiltersRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::FILTER, true);
@ -1227,7 +1227,7 @@ void arangodb::aql::removeUnnecessaryFiltersRule(Optimizer* opt,
/// additionally remove all unused aggregate calculations from a COLLECT
void arangodb::aql::removeCollectVariablesRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::COLLECT, true);
@ -1558,7 +1558,7 @@ class PropagateConstantAttributesHelper {
/// @brief propagate constant attributes in FILTERs
void arangodb::aql::propagateConstantAttributesRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
PropagateConstantAttributesHelper helper(plan.get());
helper.propagateConstants();
@ -1571,7 +1571,7 @@ void arangodb::aql::propagateConstantAttributesRule(Optimizer* opt,
/// avoid redundant calculations in inner loops
void arangodb::aql::moveCalculationsUpRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::CALCULATION, true);
@ -1659,7 +1659,7 @@ void arangodb::aql::moveCalculationsUpRule(Optimizer* opt,
/// FILTER and LIMIT operations
void arangodb::aql::moveCalculationsDownRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::CALCULATION, true);
@ -1768,7 +1768,7 @@ void arangodb::aql::moveCalculationsDownRule(Optimizer* opt,
/// this rule cannot be turned off (otherwise, the query result might be wrong!)
void arangodb::aql::specializeCollectRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::COLLECT, true);
@ -1859,7 +1859,7 @@ void arangodb::aql::specializeCollectRule(Optimizer* opt,
if (nodes.size() > 1) {
// this will tell the optimizer to optimize the cloned plan with this
// specific rule again
opt->addPlan(std::move(newPlan), rule, true, static_cast<int>(rule->level - 1));
opt->addPlan(std::move(newPlan), rule, true, static_cast<int>(rule.level - 1));
} else {
// no need to run this specific rule again on the cloned plan
opt->addPlan(std::move(newPlan), rule, true);
@ -1904,79 +1904,13 @@ void arangodb::aql::specializeCollectRule(Optimizer* opt,
opt->addPlan(std::move(plan), rule, modified);
}
/// @brief split and-combined filters and break them into smaller parts
void arangodb::aql::splitFiltersRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::FILTER, true);
bool modified = false;
for (auto const& n : nodes) {
auto fn = ExecutionNode::castTo<FilterNode const*>(n);
auto setter = plan->getVarSetBy(fn->inVariable()->id);
if (setter == nullptr || setter->getType() != EN::CALCULATION) {
continue;
}
auto cn = ExecutionNode::castTo<CalculationNode*>(setter);
auto const expression = cn->expression();
if (!expression->isDeterministic() ||
expression->node()->type != NODE_TYPE_OPERATOR_BINARY_AND) {
continue;
}
std::vector<AstNode*> stack{expression->nodeForModification()};
while (!stack.empty()) {
auto current = stack.back();
stack.pop_back();
if (current->type == NODE_TYPE_OPERATOR_BINARY_AND) {
stack.emplace_back(current->getMember(0));
stack.emplace_back(current->getMember(1));
} else {
modified = true;
ExecutionNode* calculationNode = nullptr;
auto outVar = plan->getAst()->variables()->createTemporaryVariable();
auto expression = new Expression(plan.get(), plan->getAst(), current);
try {
calculationNode =
new CalculationNode(plan.get(), plan->nextId(), expression, outVar);
} catch (...) {
delete expression;
throw;
}
plan->registerNode(calculationNode);
plan->insertDependency(n, calculationNode);
auto filterNode = new FilterNode(plan.get(), plan->nextId(), outVar);
plan->registerNode(filterNode);
plan->insertDependency(n, filterNode);
}
}
if (modified) {
plan->unlinkNode(n, false);
}
}
opt->addPlan(std::move(plan), rule, modified);
}
/// @brief move filters up in the plan
/// this rule modifies the plan in place
/// filters are moved as far up in the plan as possible to make result sets
/// as small as possible as early as possible
/// filters are not pushed beyond limits
void arangodb::aql::moveFiltersUpRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::FILTER, true);
@ -2293,7 +2227,7 @@ class arangodb::aql::RedundantCalculationsReplacer final
/// @brief simplify conditions in CalculationNodes
void arangodb::aql::simplifyConditionsRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::CALCULATION, true);
@ -2516,7 +2450,7 @@ void arangodb::aql::simplifyConditionsRule(Optimizer* opt,
/// @brief fuse filter conditions that follow each other
void arangodb::aql::fuseFiltersRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::FILTER, true);
@ -2606,7 +2540,7 @@ void arangodb::aql::fuseFiltersRule(Optimizer* opt, std::unique_ptr<ExecutionPla
/// (i.e. common expressions)
void arangodb::aql::removeRedundantCalculationsRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::CALCULATION, true);
@ -2732,7 +2666,7 @@ void arangodb::aql::removeRedundantCalculationsRule(Optimizer* opt,
/// this modifies an existing plan in place
void arangodb::aql::removeUnnecessaryCalculationsRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, ::removeUnnecessaryCalculationsNodeTypes, true);
@ -2903,7 +2837,7 @@ void arangodb::aql::removeUnnecessaryCalculationsRule(Optimizer* opt,
/// @brief useIndex, try to use an index for filtering
void arangodb::aql::useIndexesRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
// These are all the nodes where we start traversing (including all
// subqueries)
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
@ -3370,7 +3304,7 @@ struct SortToIndexNode final : public WalkerWorker<ExecutionNode> {
};
void arangodb::aql::useIndexForSortRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::SORT, true);
@ -3394,7 +3328,7 @@ void arangodb::aql::useIndexForSortRule(Optimizer* opt, std::unique_ptr<Executio
/// @brief try to remove filters which are covered by indexes
void arangodb::aql::removeFiltersCoveredByIndexRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::FILTER, true);
@ -3477,7 +3411,7 @@ void arangodb::aql::removeFiltersCoveredByIndexRule(Optimizer* opt,
handled = true;
// pass the new plan into this rule again, to optimize even
// further
newLevel = static_cast<int>(rule->level - 1);
newLevel = static_cast<int>(rule.level - 1);
}
}
}
@ -3536,7 +3470,7 @@ static bool NextPermutationTuple(std::vector<size_t>& data, std::vector<size_t>&
/// @brief interchange adjacent EnumerateCollectionNodes in all possible ways
void arangodb::aql::interchangeAdjacentEnumerationsRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
@ -3653,111 +3587,12 @@ void arangodb::aql::interchangeAdjacentEnumerationsRule(Optimizer* opt,
opt->addPlan(std::move(plan), rule, false);
}
/// @brief optimize queries in the cluster so that the entire query gets pushed
/// to a single server
#if 0
void arangodb::aql::optimizeClusterSingleShardRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
TRI_ASSERT(arangodb::ServerState::instance()->isCoordinator());
bool wasModified = false;
bool done = false;
std::unordered_set<std::string> responsibleServers;
auto collections = plan->getAst()->query()->collections();
for (auto const& it : *(collections->collections())) {
Collection* c = it.second;
TRI_ASSERT(c != nullptr);
if (c->numberOfShards() != 1) {
// more than one shard for this collection
done = true;
break;
}
size_t n = c->responsibleServers(responsibleServers);
if (n != 1) {
// more than one responsible server for this collection
done = true;
break;
}
}
if (done || responsibleServers.size() != 1) {
opt->addPlan(std::move(plan), rule, wasModified);
return;
}
// we only found a single responsible server, and all collections involved
// have exactly one shard
// that means we can move the entire query onto that server
// TODO: handle Traversals and ShortestPaths here!
// TODO: properly handle subqueries here
SmallVector<ExecutionNode*>::allocator_type::arena_type s;
SmallVector<ExecutionNode*> nodes{s};
std::vector<ExecutionNode::NodeType> types = {ExecutionNode::TRAVERSAL,
ExecutionNode::K_SHORTEST_PATHS,
ExecutionNode::SHORTEST_PATH,
ExecutionNode::SUBQUERY};
plan->findNodesOfType(nodes, types, true);
bool hasIncompatibleNodes = !nodes.empty();
nodes.clear();
types = {ExecutionNode::INDEX, ExecutionNode::ENUMERATE_COLLECTION, ExecutionNode::TRAVERSAL};
plan->findNodesOfType(nodes, types, false);
if (!nodes.empty() && !hasIncompatibleNodes) {
// turn off all other cluster optimization rules now as they are superfluous
//opt->disableRule(OptimizerRule::optimizeClusterJoinsRule);
opt->disableRule(OptimizerRule::distributeInClusterRule);
opt->disableRule(OptimizerRule::scatterInClusterRule);
opt->disableRule(OptimizerRule::distributeFilternCalcToClusterRule);
opt->disableRule(OptimizerRule::distributeSortToClusterRule);
opt->disableRule(OptimizerRule::removeUnnecessaryRemoteScatterRule);
#ifdef USE_ENTERPRISE
opt->disableRule(OptimizerRule::removeSatelliteJoinsRule);
#endif
opt->disableRule(OptimizerRule::undistributeRemoveAfterEnumCollRule);
// get first collection from query
Collection const* c = ::getCollection(nodes[0]);
TRI_ASSERT(c != nullptr);
auto& vocbase = plan->getAst()->query()->vocbase();
ExecutionNode* rootNode = plan->root();
// insert a remote node
ExecutionNode* remoteNode =
new RemoteNode(plan.get(), plan->nextId(), &vocbase, "", "", "");
plan->registerNode(remoteNode);
remoteNode->addDependency(rootNode);
// insert a gather node
auto const sortMode = GatherNode::evaluateSortMode(c->numberOfShards());
auto* gatherNode = new GatherNode(plan.get(), plan->nextId(), sortMode);
plan->registerNode(gatherNode);
gatherNode->addDependency(remoteNode);
plan->root(gatherNode, true);
wasModified = true;
}
opt->addPlan(std::move(plan), rule, wasModified);
}
#endif
/// @brief scatter operations in cluster
/// this rule inserts scatter, gather and remote nodes so operations on sharded
/// collections actually work
/// it will change plans in place
void arangodb::aql::scatterInClusterRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
TRI_ASSERT(arangodb::ServerState::instance()->isCoordinator());
bool wasModified = false;
@ -3922,7 +3757,7 @@ void arangodb::aql::scatterInClusterRule(Optimizer* opt, std::unique_ptr<Executi
/// it will change plans in place
void arangodb::aql::distributeInClusterRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
TRI_ASSERT(arangodb::ServerState::instance()->isCoordinator());
bool wasModified = false;
// we are a coordinator, we replace the root if it is a modification node
@ -4146,7 +3981,7 @@ void arangodb::aql::distributeInClusterRule(Optimizer* opt,
}
void arangodb::aql::collectInClusterRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
TRI_ASSERT(arangodb::ServerState::instance()->isCoordinator());
bool wasModified = false;
@ -4450,7 +4285,7 @@ void arangodb::aql::collectInClusterRule(Optimizer* opt, std::unique_ptr<Executi
/// as small as possible as early as possible
void arangodb::aql::distributeFilternCalcToClusterRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
bool modified = false;
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
@ -4603,7 +4438,7 @@ void arangodb::aql::distributeFilternCalcToClusterRule(Optimizer* opt,
/// filters are not pushed beyond limits
void arangodb::aql::distributeSortToClusterRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::GATHER, true);
@ -4712,7 +4547,7 @@ void arangodb::aql::distributeSortToClusterRule(Optimizer* opt,
/// only a SingletonNode and possibly some CalculationNodes as dependencies
void arangodb::aql::removeUnnecessaryRemoteScatterRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::REMOTE, true);
@ -4777,7 +4612,7 @@ void arangodb::aql::removeUnnecessaryRemoteScatterRule(Optimizer* opt,
/// @brief try to restrict fragments to a single shard if possible
void arangodb::aql::restrictToSingleShardRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
TRI_ASSERT(arangodb::ServerState::instance()->isCoordinator());
bool wasModified = false;
@ -5200,7 +5035,7 @@ class RemoveToEnumCollFinder final : public WalkerWorker<ExecutionNode> {
/// @brief recognizes that a RemoveNode can be moved to the shards.
void arangodb::aql::undistributeRemoveAfterEnumCollRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::REMOVE, true);
@ -5502,7 +5337,7 @@ struct OrSimplifier {
// when the OR conditions are present in the same FILTER node, and refer to the
// same (single) attribute.
void arangodb::aql::replaceOrWithInRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::FILTER, true);
@ -5676,7 +5511,7 @@ struct RemoveRedundantOr {
void arangodb::aql::removeRedundantOrRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::FILTER, true);
@ -5729,7 +5564,7 @@ void arangodb::aql::removeRedundantOrRule(Optimizer* opt,
/// if not required
void arangodb::aql::removeDataModificationOutVariablesRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
bool modified = false;
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
@ -5804,7 +5639,7 @@ void arangodb::aql::removeDataModificationOutVariablesRule(Optimizer* opt,
/// entire collection to operate in batches
void arangodb::aql::patchUpdateStatementsRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
// no need to dive into subqueries here
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
@ -5889,7 +5724,7 @@ void arangodb::aql::patchUpdateStatementsRule(Optimizer* opt,
/// merges filter nodes into graph traversal nodes
void arangodb::aql::optimizeTraversalsRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> tNodes{a};
plan->findNodesOfType(tNodes, EN::TRAVERSAL, true);
@ -5948,7 +5783,7 @@ void arangodb::aql::optimizeTraversalsRule(Optimizer* opt,
// remove filter nodes already covered by a traversal
void arangodb::aql::removeFiltersCoveredByTraversal(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> fNodes{a};
plan->findNodesOfType(fNodes, EN::FILTER, true);
@ -6059,7 +5894,7 @@ void arangodb::aql::removeFiltersCoveredByTraversal(Optimizer* opt,
/// `removeFiltersCoveredByTraversal`. Should significantly reduce overhead
void arangodb::aql::removeTraversalPathVariable(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> tNodes{a};
plan->findNodesOfType(tNodes, EN::TRAVERSAL, true);
@ -6086,7 +5921,7 @@ void arangodb::aql::removeTraversalPathVariable(Optimizer* opt,
/// @brief prepares traversals for execution (hidden rule)
void arangodb::aql::prepareTraversalsRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> tNodes{a};
plan->findNodesOfType(tNodes, EN::TRAVERSAL, true);
@ -6135,7 +5970,7 @@ void arangodb::aql::prepareTraversalsRule(Optimizer* opt,
/// LET x = tmp.test
/// RETURN x.a
void arangodb::aql::inlineSubqueriesRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::SUBQUERY, true);
@ -6954,7 +6789,7 @@ static bool applyGeoOptimization(ExecutionPlan* plan, LimitNode* ln,
}
void arangodb::aql::geoIndexRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
bool mod = false;
@ -7015,7 +6850,7 @@ void arangodb::aql::geoIndexRule(Optimizer* opt, std::unique_ptr<ExecutionPlan>
}
void arangodb::aql::sortLimitRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
bool mod = false;
@ -7057,7 +6892,7 @@ void arangodb::aql::sortLimitRule(Optimizer* opt, std::unique_ptr<ExecutionPlan>
void arangodb::aql::optimizeSubqueriesRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
bool modified = false;
SmallVector<ExecutionNode*>::allocator_type::arena_type a;

View File

@ -40,98 +40,99 @@ struct Collection;
Collection* addCollectionToQuery(Query* query, std::string const& cname, bool assert = true);
/// @brief adds a SORT operation for IN right-hand side operands
void sortInValuesRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void sortInValuesRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief remove redundant sorts
/// this rule modifies the plan in place:
/// - sorts that are covered by earlier sorts will be removed
void removeRedundantSortsRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief remove all unnecessary filters
/// this rule modifies the plan in place:
/// - filters that are always true are removed completely
/// - filters that are always false will be replaced by a NoResults node
void removeUnnecessaryFiltersRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief remove unused INTO variable from COLLECT, or unused aggregates
void removeCollectVariablesRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief propagate constant attributes in FILTERs
void propagateConstantAttributesRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief move calculations up in the plan
/// this rule modifies the plan in place
/// it aims to move up calculations as far up in the plan as possible, to
/// avoid redundant calculations in inner loops
void moveCalculationsUpRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void moveCalculationsUpRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief move calculations down in the plan
/// this rule modifies the plan in place
/// it aims to move down calculations as far down in the plan as possible,
/// beyond FILTER and LIMIT statements
void moveCalculationsDownRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief determine the "right" type of CollectNode and
/// add a sort node for each COLLECT (may be removed later)
/// this rule cannot be turned off (otherwise, the query result might be wrong!)
void specializeCollectRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void specializeCollectRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief split and-combined filters and break them into smaller parts
void splitFiltersRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void splitFiltersRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief move filters up in the plan
/// this rule modifies the plan in place
/// filters are moved as far up in the plan as possible to make result sets
/// as small as possible as early as possible
/// filters are not pushed beyond limits
void moveFiltersUpRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void moveFiltersUpRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief simplify some conditions in CalculationNodes
void simplifyConditionsRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void simplifyConditionsRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief fuse filter conditions that follow each other
void fuseFiltersRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void fuseFiltersRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief remove redundant CalculationNodes
void removeRedundantCalculationsRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief remove CalculationNodes and SubqueryNodes that are never needed
void removeUnnecessaryCalculationsRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief useIndex, try to use an index for filtering
void useIndexesRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void useIndexesRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief try to use the index for sorting
void useIndexForSortRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void useIndexForSortRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief try to remove filters which are covered by indexes
void removeFiltersCoveredByIndexRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief interchange adjacent EnumerateCollectionNodes in all possible ways
void interchangeAdjacentEnumerationsRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief replace single document operations in cluster by special handling
void substituteClusterSingleDocumentOperations(Optimizer* opt,
void substituteClusterSingleDocumentOperationsRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule);
OptimizerRule const&);
#ifdef USE_ENTERPRISE
/// @brief optimize queries in the cluster so that the entire query gets pushed
/// to a single server
void optimizeClusterSingleShardRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
void clusterOneShardRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
#endif
/// @brief scatter operations in cluster - send all incoming rows to all remote
/// clients
void scatterInClusterRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void scatterInClusterRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief distribute operations in cluster - send each incoming row to every
/// remote client precisely once. This happens in queries like:
@ -141,7 +142,7 @@ void scatterInClusterRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerR
/// where coll2 is sharded by _key, but not if it is sharded by anything else.
/// The collections coll1 and coll2 do not have to be distinct for this.
void distributeInClusterRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
#ifdef USE_ENTERPRISE
ExecutionNode* distributeInClusterRuleSmartEdgeCollection(ExecutionPlan*, SubqueryNode* snode,
@ -151,29 +152,29 @@ ExecutionNode* distributeInClusterRuleSmartEdgeCollection(ExecutionPlan*, Subque
/// @brief remove scatter/gather and remote nodes for satellite collections
void removeSatelliteJoinsRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
void smartJoinsRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
#endif
/// @brief try to restrict fragments to a single shard if possible
void restrictToSingleShardRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief move collect to the DB servers in cluster
void collectInClusterRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void collectInClusterRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
void distributeFilternCalcToClusterRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
void distributeSortToClusterRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief try to get rid of a RemoteNode->ScatterNode combination which has
/// only a SingletonNode and possibly some CalculationNodes as dependencies
void removeUnnecessaryRemoteScatterRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief this rule removes Remote-Gather-Scatter/Distribute-Remote nodes from
/// plans arising from queries of the form:
@ -201,7 +202,7 @@ void removeUnnecessaryRemoteScatterRule(Optimizer*, std::unique_ptr<ExecutionPla
/// where f is some function.
///
void undistributeRemoveAfterEnumCollRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief this rule replaces expressions of the type:
/// x.val == 1 || x.val == 2 || x.val == 3
@ -209,54 +210,54 @@ void undistributeRemoveAfterEnumCollRule(Optimizer*, std::unique_ptr<ExecutionPl
// x.val IN [1,2,3]
// when the OR conditions are present in the same FILTER node, and refer to the
// same (single) attribute.
void replaceOrWithInRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void replaceOrWithInRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
void removeRedundantOrRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void removeRedundantOrRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief remove $OLD and $NEW variables from data-modification statements
/// if not required
void removeDataModificationOutVariablesRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief patch UPDATE statement on single collection that iterates over the
/// entire collection to operate in batches
void patchUpdateStatementsRule(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
/// @brief optimizes away unused traversal output variables and
/// merges filter nodes into graph traversal nodes
void optimizeTraversalsRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule);
OptimizerRule const&);
/// @brief removes filter nodes already covered by the traversal and removes
/// unused variables
void removeFiltersCoveredByTraversal(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule);
OptimizerRule const&);
/// @brief removes redundant path variables, after applying
/// `removeFiltersCoveredByTraversal`. Should significantly reduce overhead
void removeTraversalPathVariable(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule);
OptimizerRule const&);
/// @brief prepares traversals for execution (hidden rule)
void prepareTraversalsRule(Optimizer* opt, std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule);
OptimizerRule const&);
/// @brief moves simple subqueries one level higher
void inlineSubqueriesRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void inlineSubqueriesRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief replace FILTER and SORT containing DISTANCE function
void geoIndexRule(Optimizer*, std::unique_ptr<aql::ExecutionPlan>, OptimizerRule const*);
void geoIndexRule(Optimizer*, std::unique_ptr<aql::ExecutionPlan>, OptimizerRule const&);
/// @brief make sort node aware of limit to enable internal optimizations
void sortLimitRule(Optimizer*, std::unique_ptr<aql::ExecutionPlan>, OptimizerRule const*);
void sortLimitRule(Optimizer*, std::unique_ptr<aql::ExecutionPlan>, OptimizerRule const&);
/// @brief push LIMIT into subqueries, and simplify them
void optimizeSubqueriesRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const*);
void optimizeSubqueriesRule(Optimizer*, std::unique_ptr<ExecutionPlan>, OptimizerRule const&);
/// @brief replace legacy JS functions in the plan.
void replaceNearWithinFulltext(Optimizer*, std::unique_ptr<ExecutionPlan>,
OptimizerRule const*);
OptimizerRule const&);
} // namespace aql
} // namespace arangodb

View File

@ -179,7 +179,7 @@ void replaceNode(ExecutionPlan* plan, ExecutionNode* oldNode, ExecutionNode* new
}
bool substituteClusterSingleDocumentOperationsIndex(Optimizer* opt, ExecutionPlan* plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
bool modified = false;
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
@ -275,7 +275,7 @@ bool substituteClusterSingleDocumentOperationsIndex(Optimizer* opt, ExecutionPla
}
bool substituteClusterSingleDocumentOperationsNoIndex(Optimizer* opt, ExecutionPlan* plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
bool modified = false;
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
@ -388,8 +388,11 @@ bool substituteClusterSingleDocumentOperationsNoIndex(Optimizer* opt, ExecutionP
} // namespace
void arangodb::aql::substituteClusterSingleDocumentOperations(
Optimizer* opt, std::unique_ptr<ExecutionPlan> plan, OptimizerRule const* rule) {
namespace arangodb {
namespace aql {
void substituteClusterSingleDocumentOperationsRule(
Optimizer* opt, std::unique_ptr<ExecutionPlan> plan, OptimizerRule const& rule) {
bool modified = false;
for (auto const& fun : {&::substituteClusterSingleDocumentOperationsIndex,
@ -402,3 +405,6 @@ void arangodb::aql::substituteClusterSingleDocumentOperations(
opt->addPlan(std::move(plan), rule, modified);
}
}
}

View File

@ -42,16 +42,10 @@ std::map<int, OptimizerRule> OptimizerRulesFeature::_rules;
// @brief lookup from rule name to rule level
std::unordered_map<std::string, std::pair<int, bool>> OptimizerRulesFeature::_ruleLookup;
constexpr bool CreatesAdditionalPlans = true;
constexpr bool DoesNotCreateAdditionalPlans = false;
constexpr bool CanBeDisabled = true;
constexpr bool CanNotBeDisabled = false;
OptimizerRulesFeature::OptimizerRulesFeature(application_features::ApplicationServer& server)
: application_features::ApplicationFeature(server, "OptimizerRules") {
setOptional(false);
startsAfter("V8Phase");
startsAfter("Aql");
}
@ -65,23 +59,21 @@ void OptimizerRulesFeature::unprepare() {
/// @brief register a rule
void OptimizerRulesFeature::registerRule(std::string const& name, RuleFunction func,
OptimizerRule::RuleLevel level,
bool canCreateAdditionalPlans,
bool canBeDisabled, bool isHidden) {
if (_ruleLookup.find(name) != _ruleLookup.end()) {
// duplicate rule names are not allowed
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"duplicate optimizer rule name");
std::underlying_type<OptimizerRule::Flags>::type flags) {
// duplicate rules are not allowed
TRI_ASSERT(_ruleLookup.find(name) == _ruleLookup.end());
TRI_ASSERT(_rules.find(level) == _rules.end());
OptimizerRule rule(name, func, level, flags);
if (rule.isClusterOnly() && !ServerState::instance()->isCoordinator()) {
// cluster-only rule... however, we are not a coordinator, so we can just
// ignore this rule
return;
}
_ruleLookup.emplace(name, std::make_pair(level, canBeDisabled));
if (_rules.find(level) != _rules.end()) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"duplicate optimizer rule level");
}
_rules.emplace(level, OptimizerRule(name, func, level, canCreateAdditionalPlans,
canBeDisabled, isHidden));
_ruleLookup.emplace(name, std::make_pair(level, rule.canBeDisabled()));
_rules.emplace(level, std::move(rule));
}
/// @brief set up the optimizer rules once and forever
@ -91,45 +83,35 @@ void OptimizerRulesFeature::addRules() {
// note that levels must be unique
// "Pass 1": moving nodes "up" (potentially outside loops):
#if 0
// rule not yet tested
registerRule("split-filters",
splitFiltersRule,
splitFiltersRule,
true);
#endif
// determine the "right" type of CollectNode and
// add a sort node for each COLLECT (may be removed later)
// this rule cannot be turned off (otherwise, the query result might be
// wrong!)
registerHiddenRule("specialize-collect", specializeCollectRule,
OptimizerRule::specializeCollectRule,
CreatesAdditionalPlans, CanNotBeDisabled);
registerRule("specialize-collect", specializeCollectRule, OptimizerRule::specializeCollectRule,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanCreateAdditionalPlans, OptimizerRule::Flags::Hidden));
// inline subqueries one level higher
registerRule("inline-subqueries", inlineSubqueriesRule, OptimizerRule::inlineSubqueriesRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// move calculations up the dependency chain (to pull them out of
// inner loops etc.)
registerRule("move-calculations-up", moveCalculationsUpRule, OptimizerRule::moveCalculationsUpRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// move filters up the dependency chain (to make result sets as small
// as possible as early as possible)
registerRule("move-filters-up", moveFiltersUpRule, OptimizerRule::moveFiltersUpRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// simplify conditions
registerRule("simplify-conditions", simplifyConditionsRule, OptimizerRule::simplifyConditionsRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// remove redundant calculations
registerRule("remove-redundant-calculations", removeRedundantCalculationsRule,
OptimizerRule::removeRedundantCalculationsRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
/// "Pass 2": try to remove redundant or unnecessary nodes
@ -138,60 +120,63 @@ void OptimizerRulesFeature::addRules() {
// filters that are always false will be replaced with a NoResults node
registerRule("remove-unnecessary-filters", removeUnnecessaryFiltersRule,
OptimizerRule::removeUnnecessaryFiltersRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// remove calculations that are never necessary
registerRule("remove-unnecessary-calculations", removeUnnecessaryCalculationsRule,
OptimizerRule::removeUnnecessaryCalculationsRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// remove redundant sort blocks
registerRule("remove-redundant-sorts", removeRedundantSortsRule,
OptimizerRule::removeRedundantSortsRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// push limits into subqueries and simplify them
registerRule("optimize-subqueries", optimizeSubqueriesRule, OptimizerRule::optimizeSubqueriesRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
registerRule("optimize-subqueries", optimizeSubqueriesRule,
OptimizerRule::optimizeSubqueriesRule,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
/// "Pass 3": interchange EnumerateCollection nodes in all possible ways
/// this is level 500, please never let new plans from higher
/// levels go back to this or lower levels!
registerRule("interchange-adjacent-enumerations", interchangeAdjacentEnumerationsRule,
OptimizerRule::interchangeAdjacentEnumerationsRule,
CreatesAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanCreateAdditionalPlans, OptimizerRule::Flags::CanBeDisabled));
// "Pass 4": moving nodes "up" (potentially outside loops) (second try):
// move calculations up the dependency chain (to pull them out of
// inner loops etc.)
registerRule("move-calculations-up-2", moveCalculationsUpRule,
OptimizerRule::moveCalculationsUpRule2,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// move filters up the dependency chain (to make result sets as small
// as possible as early as possible)
registerRule("move-filters-up-2", moveFiltersUpRule, OptimizerRule::moveFiltersUpRule2,
DoesNotCreateAdditionalPlans, CanBeDisabled);
registerRule("move-filters-up-2", moveFiltersUpRule,
OptimizerRule::moveFiltersUpRule2,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// merge filters into traversals
registerRule("optimize-traversals", optimizeTraversalsRule, OptimizerRule::optimizeTraversalsRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
registerRule("optimize-traversals", optimizeTraversalsRule,
OptimizerRule::optimizeTraversalsRule,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// optimize unneccessary filters already applied by the traversal
registerRule("remove-filter-covered-by-traversal", removeFiltersCoveredByTraversal,
OptimizerRule::removeFiltersCoveredByTraversal,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// optimize unneccessary filters already applied by the traversal. Only ever
// does something if previous rules remove all filters using the path variable
registerRule("remove-redundant-path-var", removeTraversalPathVariable,
OptimizerRule::removeTraversalPathVariable,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// prepare traversal info
registerHiddenRule("prepare-traversals", prepareTraversalsRule,
registerRule("prepare-traversals", prepareTraversalsRule,
OptimizerRule::prepareTraversalsRule,
DoesNotCreateAdditionalPlans, CanNotBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::Hidden));
/// "Pass 5": try to remove redundant or unnecessary nodes (second try)
// remove filters from the query that are not necessary at all
@ -199,151 +184,159 @@ void OptimizerRulesFeature::addRules() {
// filters that are always false will be replaced with a NoResults node
registerRule("remove-unnecessary-filters-2", removeUnnecessaryFiltersRule,
OptimizerRule::removeUnnecessaryFiltersRule2,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// remove redundant sort node
registerRule("remove-redundant-sorts-2", removeRedundantSortsRule,
OptimizerRule::removeRedundantSortsRule2,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// remove unused INTO variable from COLLECT, or unused aggregates
registerRule("remove-collect-variables", removeCollectVariablesRule,
OptimizerRule::removeCollectVariablesRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// remove unused out variables for data-modification queries
registerRule("remove-data-modification-out-variables", removeDataModificationOutVariablesRule,
OptimizerRule::removeDataModificationOutVariablesRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// propagate constant attributes in FILTERs
registerRule("propagate-constant-attributes", propagateConstantAttributesRule,
OptimizerRule::propagateConstantAttributesRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
/// "Pass 6": use indexes if possible for FILTER and/or SORT nodes
// try to replace simple OR conditions with IN
registerRule("replace-or-with-in", replaceOrWithInRule, OptimizerRule::replaceOrWithInRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
registerRule("replace-or-with-in", replaceOrWithInRule,
OptimizerRule::replaceOrWithInRule,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// try to remove redundant OR conditions
registerRule("remove-redundant-or", removeRedundantOrRule, OptimizerRule::removeRedundantOrRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// try to find a filter after an enumerate collection and find indexes
registerRule("use-indexes", useIndexesRule, OptimizerRule::useIndexesRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
registerRule("use-indexes", useIndexesRule,
OptimizerRule::useIndexesRule,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// try to remove filters which are covered by index ranges
registerRule("remove-filter-covered-by-index", removeFiltersCoveredByIndexRule,
OptimizerRule::removeFiltersCoveredByIndexRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// try to find sort blocks which are superseeded by indexes
registerRule("use-index-for-sort", useIndexForSortRule, OptimizerRule::useIndexForSortRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
registerRule("use-index-for-sort", useIndexForSortRule,
OptimizerRule::useIndexForSortRule,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// sort in-values in filters (note: must come after
// remove-filter-covered-by-index rule)
registerRule("sort-in-values", sortInValuesRule, OptimizerRule::sortInValuesRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
registerRule("sort-in-values", sortInValuesRule,
OptimizerRule::sortInValuesRule,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// remove calculations that are never necessary
registerRule("remove-unnecessary-calculations-2", removeUnnecessaryCalculationsRule,
OptimizerRule::removeUnnecessaryCalculationsRule2,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// fuse multiple adjacent filters into one
registerRule("fuse-filters", fuseFiltersRule, OptimizerRule::fuseFiltersRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
registerRule("fuse-filters", fuseFiltersRule,
OptimizerRule::fuseFiltersRule,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// finally, push calculations as far down as possible
registerRule("move-calculations-down", moveCalculationsDownRule,
OptimizerRule::moveCalculationsDownRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// patch update statements
registerRule("patch-update-statements", patchUpdateStatementsRule,
OptimizerRule::patchUpdateStatementsRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
registerRule("replace-function-with-index", replaceNearWithinFulltext,
OptimizerRule::replaceNearWithinFulltext,
DoesNotCreateAdditionalPlans, CanNotBeDisabled);
OptimizerRule::makeFlags());
// move filters and sort conditions into views
registerRule("handle-arangosearch-views", arangodb::iresearch::handleViewsRule,
OptimizerRule::handleArangoSearchViewsRule,
DoesNotCreateAdditionalPlans, CanNotBeDisabled);
OptimizerRule::makeFlags());
// remove FILTER DISTANCE(...) and SORT DISTANCE(...)
OptimizerRulesFeature::registerRule("geo-index-optimizer", geoIndexRule,
registerRule("geo-index-optimizer", geoIndexRule,
OptimizerRule::applyGeoIndexRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// make sort node aware of subsequent limit statements for internal optimizations
OptimizerRulesFeature::registerRule("sort-limit", sortLimitRule,
registerRule("sort-limit", sortLimitRule,
OptimizerRule::applySortLimitRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
if (arangodb::ServerState::instance()->isCoordinator()) {
registerRule("optimize-cluster-single-document-operations",
substituteClusterSingleDocumentOperations,
OptimizerRule::substituteSingleDocumentOperations,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
#if 0
registerRule("optimize-cluster-single-shard", optimizeClusterSingleShardRule,
OptimizerRule::optimizeClusterSingleShardRule, DoesNotCreateAdditionalPlans, CanBeDisabled);
#ifdef USE_ENTERPRISE
// must be the first cluster optimizer rule
registerRule("cluster-one-shard", clusterOneShardRule,
OptimizerRule::clusterOneShardRule,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
#endif
#endif
registerRule("optimize-cluster-single-document-operations", substituteClusterSingleDocumentOperationsRule,
OptimizerRule::substituteSingleDocumentOperations,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
// distribute operations in cluster
registerRule("scatter-in-cluster", scatterInClusterRule, OptimizerRule::scatterInClusterRule,
DoesNotCreateAdditionalPlans, CanNotBeDisabled);
registerRule("scatter-in-cluster", scatterInClusterRule,
OptimizerRule::scatterInClusterRule,
OptimizerRule::makeFlags(OptimizerRule::Flags::ClusterOnly));
registerRule("distribute-in-cluster", distributeInClusterRule,
OptimizerRule::distributeInClusterRule,
DoesNotCreateAdditionalPlans, CanNotBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::ClusterOnly));
registerRule("collect-in-cluster", collectInClusterRule, OptimizerRule::collectInClusterRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
registerRule("collect-in-cluster", collectInClusterRule,
OptimizerRule::collectInClusterRule,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
// distribute operations in cluster
registerRule("distribute-filtercalc-to-cluster", distributeFilternCalcToClusterRule,
OptimizerRule::distributeFilternCalcToClusterRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
registerRule("distribute-sort-to-cluster", distributeSortToClusterRule,
OptimizerRule::distributeSortToClusterRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
registerRule("remove-unnecessary-remote-scatter", removeUnnecessaryRemoteScatterRule,
OptimizerRule::removeUnnecessaryRemoteScatterRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
registerRule("undistribute-remove-after-enum-coll", undistributeRemoveAfterEnumCollRule,
OptimizerRule::undistributeRemoveAfterEnumCollRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
#ifdef USE_ENTERPRISE
registerRule("remove-satellite-joins", removeSatelliteJoinsRule,
OptimizerRule::removeSatelliteJoinsRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
registerRule("smart-joins", smartJoinsRule,
OptimizerRule::smartJoinsRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
#endif
// distribute view queries in cluster
registerRule("scatter-arangosearch-view-in-cluster",
arangodb::iresearch::scatterViewInClusterRule,
registerRule("scatter-arangosearch-view-in-cluster", arangodb::iresearch::scatterViewInClusterRule,
OptimizerRule::scatterIResearchViewInClusterRule,
DoesNotCreateAdditionalPlans, CanNotBeDisabled);
OptimizerRule::makeFlags(OptimizerRule::Flags::ClusterOnly));
registerRule("restrict-to-single-shard", restrictToSingleShardRule,
OptimizerRule::restrictToSingleShardRule,
DoesNotCreateAdditionalPlans, CanBeDisabled);
}
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
// finally add the storage-engine specific rules
addStorageEngineRules();
@ -409,7 +402,7 @@ void OptimizerRulesFeature::disableRule(std::string const& name,
if (arangodb::velocypack::StringRef(p, size) == "all") {
// disable all rules
for (auto const& it : _rules) {
if (it.second.canBeDisabled) {
if (it.second.canBeDisabled()) {
disabled.emplace(it.first);
}
}

View File

@ -44,22 +44,15 @@ class OptimizerRulesFeature final : public application_features::ApplicationFeat
static std::vector<std::string> translateRules(std::vector<int> const&);
/// @brief translate a single rule
static char const* translateRule(int);
static char const* translateRule(int rule);
/// @brief look up the ids of all disabled rules
static std::unordered_set<int> getDisabledRuleIds(std::vector<std::string> const&);
static std::unordered_set<int> getDisabledRuleIds(std::vector<std::string> const& names);
/// @brief register a rule
static void registerRule(std::string const& name, RuleFunction func,
OptimizerRule::RuleLevel level, bool canCreateAdditionalPlans,
bool canBeDisabled, bool isHidden = false);
/// @brief register a hidden rule
static void registerHiddenRule(std::string const& name, RuleFunction const& func,
OptimizerRule::RuleLevel level,
bool canCreateAdditionalPlans, bool canBeDisabled) {
registerRule(name, func, level, canCreateAdditionalPlans, canBeDisabled, true);
}
std::underlying_type<OptimizerRule::Flags>::type flags);
private:
void addRules();

View File

@ -552,7 +552,7 @@ AstNode* replaceFullText(AstNode* funAstNode, ExecutionNode* calcNode, Execution
//! @brief replace legacy JS Functions with pure AQL
void arangodb::aql::replaceNearWithinFulltext(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
bool modified = false;
SmallVector<ExecutionNode*>::allocator_type::arena_type a;

View File

@ -38,14 +38,14 @@ OutputAqlItemRow::OutputAqlItemRow(
std::shared_ptr<std::unordered_set<RegisterId> const> outputRegisters,
std::shared_ptr<std::unordered_set<RegisterId> const> registersToKeep,
std::shared_ptr<std::unordered_set<RegisterId> const> registersToClear,
CopyRowBehaviour copyRowBehaviour)
CopyRowBehavior copyRowBehavior)
: _block(std::move(block)),
_baseIndex(0),
_lastBaseIndex(0),
_inputRowCopied(false),
_lastSourceRow{CreateInvalidInputRowHint{}},
_numValuesWritten(0),
_doNotCopyInputRow(copyRowBehaviour == CopyRowBehaviour::DoNotCopyInputRows),
_doNotCopyInputRow(copyRowBehavior == CopyRowBehavior::DoNotCopyInputRows),
_outputRegisters(std::move(outputRegisters)),
_registersToKeep(std::move(registersToKeep)),
_registersToClear(std::move(registersToClear)),

View File

@ -44,14 +44,14 @@ struct AqlValue;
*/
class OutputAqlItemRow {
public:
// TODO Implement this behaviour via a template parameter instead?
enum class CopyRowBehaviour { CopyInputRows, DoNotCopyInputRows };
// TODO Implement this behavior via a template parameter instead?
enum class CopyRowBehavior { CopyInputRows, DoNotCopyInputRows };
explicit OutputAqlItemRow(SharedAqlItemBlockPtr block,
std::shared_ptr<std::unordered_set<RegisterId> const> outputRegisters,
std::shared_ptr<std::unordered_set<RegisterId> const> registersToKeep,
std::shared_ptr<std::unordered_set<RegisterId> const> registersToClear,
CopyRowBehaviour = CopyRowBehaviour::CopyInputRows);
CopyRowBehavior = CopyRowBehavior::CopyInputRows);
OutputAqlItemRow(OutputAqlItemRow const&) = delete;
OutputAqlItemRow& operator=(OutputAqlItemRow const&) = delete;

View File

@ -424,7 +424,7 @@ void auth::User::grantDatabase(std::string const& dbname, auth::Level level) {
it->second._databaseAuthLevel = level;
} else {
// grantDatabase is not supposed to change any rights on the
// collection level code which relies on the old behaviour
// collection level code which relies on the old behavior
// will need to be adjusted
_dbAccess.emplace(dbname, DBAuthContext(level, CollLevelMap()));
}

View File

@ -448,7 +448,7 @@ OperationID ClusterComm::getOperationID() { return TRI_NewTickServer(); }
/// limit the time to send the initial request away. If `initTimeout`
/// is negative (as for example in the default value), then `initTimeout`
/// is taken to be the same as `timeout`. The idea behind the two timeouts
/// is to be able to specify correct behaviour for automatic failover.
/// is to be able to specify correct behavior for automatic failover.
/// The idea is that if the initial request cannot be sent within
/// `initTimeout`, one can retry after a potential failover.
////////////////////////////////////////////////////////////////////////////////

View File

@ -246,7 +246,7 @@ struct ClusterCommResult {
if (response == nullptr) {
status = CL_COMM_ERROR;
} else {
// mop: wow..this is actually the old behaviour :S
// mop: wow..this is actually the old behavior :S
fromResponse(std::move(response));
}
}
@ -255,14 +255,14 @@ struct ClusterCommResult {
void fromResponse(std::unique_ptr<GeneralResponse> response) {
sendWasComplete = true;
errorCode = TRI_ERROR_NO_ERROR;
// mop: simulate the old behaviour where the original request
// mop: simulate the old behavior where the original request
// was sent to the recipient and was simply accepted. Then the backend would
// do its work and send a request to the target containing the result of
// that
// operation in this request. This is mind boggling but this is how it used
// to
// work....now it gets even funnier: as the new system only does
// request => response we simulate the old behaviour now and fake a request
// request => response we simulate the old behavior now and fake a request
// containing the body of our response
// :snake: OPST_CIRCUS
auto httpResponse = dynamic_cast<HttpResponse*>(response.get());

View File

@ -2925,7 +2925,7 @@ std::vector<std::shared_ptr<LogicalCollection>> ClusterMethods::persistCollectio
size_t replicationFactor = col->replicationFactor();
size_t numberOfShards = col->numberOfShards();
// the default behaviour however is to bail out and inform the user
// the default behavior however is to bail out and inform the user
// that the requested replicationFactor is not possible right now
if (dbServers.size() < replicationFactor) {
LOG_TOPIC("9ce2e", DEBUG, Logger::CLUSTER)

View File

@ -868,7 +868,7 @@ bool SynchronizeShard::first() {
auto sy = details->slice();
auto const endTime = system_clock::now();
// Long shard sync initialisation
// Long shard sync initialization
if (endTime - startTime > seconds(5)) {
LOG_TOPIC("ca7e3", INFO, Logger::MAINTENANCE)
<< "synchronizeOneShard: long call to syncCollection for shard"

View File

@ -167,7 +167,7 @@ class ClusterCollection final : public PhysicalCollection {
private:
void addIndex(std::shared_ptr<arangodb::Index> idx);
// keep locks just to adhere to behaviour in other collections
// keep locks just to adhere to behavior in other collections
mutable basics::ReadWriteLock _exclusiveLock;
ClusterEngineType _engineType;
velocypack::Builder _info;

View File

@ -58,7 +58,7 @@ class GraphOperations {
: _graph(graph_), _vocbase(vocbase) {}
// TODO I added the complex result type for the get* methods to exactly
// reproduce (in the RestGraphHandler) the behaviour of the similar methods
// reproduce (in the RestGraphHandler) the behavior of the similar methods
// in the RestDocumentHandler. A simpler type, e.g. ResultT<OperationResult>,
// would be preferable.

View File

@ -68,7 +68,7 @@ class KShortestPathsFinder : public ShortestPathFinder {
double _weight;
// Where this path branched off the previous shortest path
// This is an optimisation because we only need to consider
// This is an optimization because we only need to consider
// spur paths from after the branch point
size_t _branchpoint;

View File

@ -178,7 +178,7 @@ bool upgradeSingleServerArangoSearchView0_1(
// In order to upgrade ArangoSearch views from version 0 to version 1 we need to
// differentiate between single server and cluster, therefore we temporary set role in 'ServerState',
// actually supplied by a user, only for the duration of task to avoid other upgrade tasks, that
// potentially rely on the original behaviour, to be affected.
// potentially rely on the original behavior, to be affected.
struct ServerRoleGuard {
ServerRoleGuard() {
auto const* clusterFeature = ApplicationServer::lookupFeature<arangodb::ClusterFeature>("Cluster");

View File

@ -686,7 +686,7 @@ arangodb::Result IResearchLink::drop() {
);
// may occur if the link was already unlinked from the view via another instance
// this behaviour was seen user-access-right-drop-view-arangosearch-spec.js
// this behavior was seen user-access-right-drop-view-arangosearch-spec.js
// where the collection drop was called through REST,
// the link was dropped as a result of the collection drop call
// then the view was dropped via a separate REST call

View File

@ -137,9 +137,9 @@ struct IResearchViewCoordinator::ViewFactory : public arangodb::ViewFactory {
std::to_string(impl->id())); // refresh view from Agency
if (view) {
view->open(); // open view to match the behaviour in
view->open(); // open view to match the behavior in
// StorageEngine::openExistingDatabase(...) and original
// behaviour of TRI_vocbase_t::createView(...)
// behavior of TRI_vocbase_t::createView(...)
}
return arangodb::Result();

View File

@ -43,13 +43,14 @@ using EN = arangodb::aql::ExecutionNode;
void MMFilesOptimizerRules::registerResources() {
// remove SORT RAND() if appropriate
OptimizerRulesFeature::registerRule("remove-sort-rand", removeSortRandRule,
OptimizerRule::removeSortRandRule, false, true);
OptimizerRule::removeSortRandRule,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
}
/// @brief remove SORT RAND() if appropriate
void MMFilesOptimizerRules::removeSortRandRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::SORT, true);

View File

@ -38,7 +38,7 @@ struct MMFilesOptimizerRules {
static void removeSortRandRule(aql::Optimizer* opt,
std::unique_ptr<aql::ExecutionPlan> plan,
aql::OptimizerRule const* rule);
aql::OptimizerRule const& rule);
};
} // namespace arangodb

View File

@ -67,7 +67,7 @@ void RestAdminServerHandler::handleId() {
auto instance = ServerState::instance();
if (!instance->isRunningInCluster()) {
// old behaviour...klingt komisch, is aber so
// old behavior...klingt komisch, is aber so
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_HTTP_SERVER_ERROR);
return;
}

View File

@ -113,7 +113,7 @@ Result RestGraphHandler::executeGharial() {
// most operations. So fetching an edge via
// /_api/gharial/{graph}/vertex/{coll}/{key} works just fine. Should this be
// changed? One way or the other, make sure there are tests for the desired
// behaviour!
// behavior!
/*
if (collType == vertex) {
if (graph->vertexCollections().find(setName) ==

View File

@ -2427,7 +2427,7 @@ void RestReplicationHandler::handleCommandHoldReadLockCollection() {
// This is an optional parameter, it may not be set (backwards compatible)
// If it is not set it will default to a hard-lock, otherwise we do a
// potentially faster soft-lock synchronisation with a smaller hard-lock
// potentially faster soft-lock synchronization with a smaller hard-lock
// phase.
bool doSoftLock = VelocyPackHelper::getBooleanValue(body, "doSoftLockOnly", false);

View File

@ -55,19 +55,20 @@ std::vector<ExecutionNode::NodeType> const reduceExtractionToProjectionTypes = {
void RocksDBOptimizerRules::registerResources() {
// simplify an EnumerationCollectionNode that fetches an entire document to a
// projection of this document
OptimizerRulesFeature::registerRule("reduce-extraction-to-projection",
reduceExtractionToProjectionRule,
OptimizerRulesFeature::registerRule("reduce-extraction-to-projection", reduceExtractionToProjectionRule,
OptimizerRule::reduceExtractionToProjectionRule,
false, true);
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
// remove SORT RAND() LIMIT 1 if appropriate
OptimizerRulesFeature::registerRule("remove-sort-rand-limit-1", removeSortRandRule,
OptimizerRule::removeSortRandRule, false, true);
OptimizerRule::removeSortRandRule,
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
}
// simplify an EnumerationCollectionNode that fetches an entire document to a
// projection of this document
void RocksDBOptimizerRules::reduceExtractionToProjectionRule(
Optimizer* opt, std::unique_ptr<ExecutionPlan> plan, OptimizerRule const* rule) {
Optimizer* opt, std::unique_ptr<ExecutionPlan> plan, OptimizerRule const& rule) {
// These are all the nodes where we start traversing (including all
// subqueries)
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
@ -349,7 +350,7 @@ void RocksDBOptimizerRules::reduceExtractionToProjectionRule(
/// @brief remove SORT RAND() if appropriate
void RocksDBOptimizerRules::removeSortRandRule(Optimizer* opt,
std::unique_ptr<ExecutionPlan> plan,
OptimizerRule const* rule) {
OptimizerRule const& rule) {
SmallVector<ExecutionNode*>::allocator_type::arena_type a;
SmallVector<ExecutionNode*> nodes{a};
plan->findNodesOfType(nodes, EN::SORT, true);

View File

@ -39,11 +39,11 @@ struct RocksDBOptimizerRules {
// projection of this document
static void reduceExtractionToProjectionRule(aql::Optimizer* opt,
std::unique_ptr<aql::ExecutionPlan> plan,
aql::OptimizerRule const* rule);
aql::OptimizerRule const& rule);
// remove SORT RAND() LIMIT 1 if appropriate
static void removeSortRandRule(aql::Optimizer* opt,
std::unique_ptr<aql::ExecutionPlan> plan,
aql::OptimizerRule const* rule);
aql::OptimizerRule const& rule);
};
} // namespace arangodb

View File

@ -228,7 +228,7 @@ Result RocksDBReplicationContext::getInventory(TRI_vocbase_t& vocbase, bool incl
TRI_ASSERT(_snapshot != nullptr);
// FIXME is it technically correct to include newly created collections ?
// simon: I think no, but this has been the behaviour since 3.2
// simon: I think no, but this has been the behavior since 3.2
TRI_voc_tick_t tick = TRI_NewTickServer(); // = _lastArangoTick
if (global) {
// global inventory

View File

@ -3063,7 +3063,7 @@ Result transaction::Methods::addCollection(TRI_voc_cid_t cid, std::string const&
});
if (!resolver()->visitCollections(visitor, cid) || res.fail()) {
// trigger exception as per the original behaviour (tests depend on this)
// trigger exception as per the original behavior (tests depend on this)
if (res.ok() && !visited) {
addCollectionCallback(cid); // will throw on error
}

View File

@ -288,9 +288,9 @@ Result LogicalView::rename(std::string&& newName) {
std::to_string(impl->id())); // refresh view from Agency
if (view) {
view->open(); // open view to match the behaviour in
view->open(); // open view to match the behavior in
// StorageEngine::openExistingDatabase(...) and original
// behaviour of TRI_vocbase_t::createView(...)
// behavior of TRI_vocbase_t::createView(...)
}
return Result();

View File

@ -127,7 +127,7 @@ struct TRI_vocbase_t {
TEST_VIRTUAL ~TRI_vocbase_t();
private:
// explicitly document implicit behaviour (due to presence of locks)
// explicitly document implicit behavior (due to presence of locks)
TRI_vocbase_t(TRI_vocbase_t&&) = delete;
TRI_vocbase_t(TRI_vocbase_t const&) = delete;
TRI_vocbase_t& operator=(TRI_vocbase_t&&) = delete;

View File

@ -380,7 +380,7 @@ end
end
end
# super carrot fix for strange SSL behaviour on windows
# super carrot fix for strange SSL behavior on windows
# on some windowses the first SSL request somehow throws strange SSL errors
# after that everything is fine...so make a dummy request first
if $ssl == '1'

View File

@ -244,6 +244,7 @@ function testSuite() {
arango.DELETE("/_api/analyzer/" + name + j);
}
},
testAnalyzerLinks : function() {
let body = JSON.stringify({
name : name,

View File

@ -115,7 +115,7 @@ function CollectionCacheSuite () {
});
},
testCollectionCacheBehaviour : function () {
testCollectionCacheBehavior : function () {
let c = db._create(cn, {cacheEnabled:true});
let p = c.properties();
assertTrue(p.cacheEnabled, p);

View File

@ -404,9 +404,8 @@ function CollectionSuite () {
c.unload();
},
testEdgeCacheBehaviour : function() {
var cn = "UnitLoadBehaviour123";
testEdgeCacheBehavior : function() {
var cn = "UnitLoadBehavior123";
db._drop(cn);
var c = db._createEdgeCollection(cn);
c.load();

View File

@ -237,12 +237,12 @@ function basicTestSuite() {
},
testPageRank: function () {
// should test correct convergence behaviour, might fail if EPS is too low
// should test correct convergence behavior, might fail if EPS is too low
testAlgo("pagerank", { threshold: EPS / 10, resultField: "result", store: true });
},
testPageRankMMap: function () {
// should test correct convergence behaviour, might fail if EPS is too low
// should test correct convergence behavior, might fail if EPS is too low
testAlgo("pagerank", { threshold: EPS / 10, resultField: "result", store: true, useMemoryMaps: true });
},

View File

@ -148,12 +148,12 @@ function basicTestSuite() {
},
testPageRank: function () {
// should test correct convergence behaviour, might fail if EPS is too low
// should test correct convergence behavior, might fail if EPS is too low
testAlgo("pagerank", { threshold: EPS / 10, resultField: "result", store: true });
},
testPageRankMMap: function () {
// should test correct convergence behaviour, might fail if EPS is too low
// should test correct convergence behavior, might fail if EPS is too low
testAlgo("pagerank", { threshold: EPS / 10, resultField: "result", store: true, useMemoryMaps: true });
},