mirror of https://gitee.com/bigwinds/arangodb
refactoring (#9411)
This commit is contained in:
parent
420326be25
commit
c52f2a8315
|
@ -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,
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
std::unique_ptr<ExecutionPlan> plan,
|
||||
OptimizerRule const* rule);
|
||||
void substituteClusterSingleDocumentOperationsRule(Optimizer* opt,
|
||||
std::unique_ptr<ExecutionPlan> plan,
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,71 +59,59 @@ 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
|
||||
void OptimizerRulesFeature::addRules() {
|
||||
// List all the rules in the system here:
|
||||
// lower level values mean earlier rule execution
|
||||
// List all the rules in the system here:
|
||||
// lower level values mean earlier rule execution
|
||||
|
||||
// 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
|
||||
// note that levels must be unique
|
||||
|
||||
// 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,
|
||||
OptimizerRule::prepareTraversalsRule,
|
||||
DoesNotCreateAdditionalPlans, CanNotBeDisabled);
|
||||
registerRule("prepare-traversals", prepareTraversalsRule,
|
||||
OptimizerRule::prepareTraversalsRule,
|
||||
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,
|
||||
OptimizerRule::applyGeoIndexRule,
|
||||
DoesNotCreateAdditionalPlans, CanBeDisabled);
|
||||
registerRule("geo-index-optimizer", geoIndexRule,
|
||||
OptimizerRule::applyGeoIndexRule,
|
||||
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled));
|
||||
|
||||
// make sort node aware of subsequent limit statements for internal optimizations
|
||||
OptimizerRulesFeature::registerRule("sort-limit", sortLimitRule,
|
||||
OptimizerRule::applySortLimitRule,
|
||||
DoesNotCreateAdditionalPlans, CanBeDisabled);
|
||||
|
||||
if (arangodb::ServerState::instance()->isCoordinator()) {
|
||||
registerRule("optimize-cluster-single-document-operations",
|
||||
substituteClusterSingleDocumentOperations,
|
||||
OptimizerRule::substituteSingleDocumentOperations,
|
||||
DoesNotCreateAdditionalPlans, CanBeDisabled);
|
||||
registerRule("sort-limit", sortLimitRule,
|
||||
OptimizerRule::applySortLimitRule,
|
||||
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
|
||||
|
||||
// distribute operations in cluster
|
||||
registerRule("scatter-in-cluster", scatterInClusterRule, OptimizerRule::scatterInClusterRule,
|
||||
DoesNotCreateAdditionalPlans, CanNotBeDisabled);
|
||||
registerRule("optimize-cluster-single-document-operations", substituteClusterSingleDocumentOperationsRule,
|
||||
OptimizerRule::substituteSingleDocumentOperations,
|
||||
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
|
||||
|
||||
registerRule("distribute-in-cluster", distributeInClusterRule,
|
||||
OptimizerRule::distributeInClusterRule,
|
||||
DoesNotCreateAdditionalPlans, CanNotBeDisabled);
|
||||
// distribute operations in cluster
|
||||
registerRule("scatter-in-cluster", scatterInClusterRule,
|
||||
OptimizerRule::scatterInClusterRule,
|
||||
OptimizerRule::makeFlags(OptimizerRule::Flags::ClusterOnly));
|
||||
|
||||
registerRule("collect-in-cluster", collectInClusterRule, OptimizerRule::collectInClusterRule,
|
||||
DoesNotCreateAdditionalPlans, CanBeDisabled);
|
||||
registerRule("distribute-in-cluster", distributeInClusterRule,
|
||||
OptimizerRule::distributeInClusterRule,
|
||||
OptimizerRule::makeFlags(OptimizerRule::Flags::ClusterOnly));
|
||||
|
||||
// distribute operations in cluster
|
||||
registerRule("distribute-filtercalc-to-cluster", distributeFilternCalcToClusterRule,
|
||||
OptimizerRule::distributeFilternCalcToClusterRule,
|
||||
DoesNotCreateAdditionalPlans, CanBeDisabled);
|
||||
registerRule("collect-in-cluster", collectInClusterRule,
|
||||
OptimizerRule::collectInClusterRule,
|
||||
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
|
||||
|
||||
registerRule("distribute-sort-to-cluster", distributeSortToClusterRule,
|
||||
OptimizerRule::distributeSortToClusterRule,
|
||||
DoesNotCreateAdditionalPlans, CanBeDisabled);
|
||||
// distribute operations in cluster
|
||||
registerRule("distribute-filtercalc-to-cluster", distributeFilternCalcToClusterRule,
|
||||
OptimizerRule::distributeFilternCalcToClusterRule,
|
||||
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
|
||||
|
||||
registerRule("remove-unnecessary-remote-scatter", removeUnnecessaryRemoteScatterRule,
|
||||
OptimizerRule::removeUnnecessaryRemoteScatterRule,
|
||||
DoesNotCreateAdditionalPlans, CanBeDisabled);
|
||||
registerRule("distribute-sort-to-cluster", distributeSortToClusterRule,
|
||||
OptimizerRule::distributeSortToClusterRule,
|
||||
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
|
||||
|
||||
registerRule("undistribute-remove-after-enum-coll", undistributeRemoveAfterEnumCollRule,
|
||||
OptimizerRule::undistributeRemoveAfterEnumCollRule,
|
||||
DoesNotCreateAdditionalPlans, CanBeDisabled);
|
||||
registerRule("remove-unnecessary-remote-scatter", removeUnnecessaryRemoteScatterRule,
|
||||
OptimizerRule::removeUnnecessaryRemoteScatterRule,
|
||||
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
|
||||
|
||||
registerRule("undistribute-remove-after-enum-coll", undistributeRemoveAfterEnumCollRule,
|
||||
OptimizerRule::undistributeRemoveAfterEnumCollRule,
|
||||
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
|
||||
|
||||
#ifdef USE_ENTERPRISE
|
||||
registerRule("remove-satellite-joins", removeSatelliteJoinsRule,
|
||||
OptimizerRule::removeSatelliteJoinsRule,
|
||||
DoesNotCreateAdditionalPlans, CanBeDisabled);
|
||||
registerRule("remove-satellite-joins", removeSatelliteJoinsRule,
|
||||
OptimizerRule::removeSatelliteJoinsRule,
|
||||
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
|
||||
|
||||
registerRule("smart-joins", smartJoinsRule,
|
||||
OptimizerRule::smartJoinsRule,
|
||||
DoesNotCreateAdditionalPlans, CanBeDisabled);
|
||||
registerRule("smart-joins", smartJoinsRule,
|
||||
OptimizerRule::smartJoinsRule,
|
||||
OptimizerRule::makeFlags(OptimizerRule::Flags::CanBeDisabled, OptimizerRule::Flags::ClusterOnly));
|
||||
#endif
|
||||
|
||||
// distribute view queries in cluster
|
||||
registerRule("scatter-arangosearch-view-in-cluster",
|
||||
arangodb::iresearch::scatterViewInClusterRule,
|
||||
OptimizerRule::scatterIResearchViewInClusterRule,
|
||||
DoesNotCreateAdditionalPlans, CanNotBeDisabled);
|
||||
// distribute view queries in cluster
|
||||
registerRule("scatter-arangosearch-view-in-cluster", arangodb::iresearch::scatterViewInClusterRule,
|
||||
OptimizerRule::scatterIResearchViewInClusterRule,
|
||||
OptimizerRule::makeFlags(OptimizerRule::Flags::ClusterOnly));
|
||||
|
||||
registerRule("restrict-to-single-shard", restrictToSingleShardRule,
|
||||
OptimizerRule::restrictToSingleShardRule,
|
||||
DoesNotCreateAdditionalPlans, CanBeDisabled);
|
||||
}
|
||||
registerRule("restrict-to-single-shard", restrictToSingleShardRule,
|
||||
OptimizerRule::restrictToSingleShardRule,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
OptimizerRule::RuleLevel level,
|
||||
std::underlying_type<OptimizerRule::Flags>::type flags);
|
||||
|
||||
private:
|
||||
void addRules();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) ==
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -244,6 +244,7 @@ function testSuite() {
|
|||
arango.DELETE("/_api/analyzer/" + name + j);
|
||||
}
|
||||
},
|
||||
|
||||
testAnalyzerLinks : function() {
|
||||
let body = JSON.stringify({
|
||||
name : name,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 });
|
||||
},
|
||||
|
||||
|
|
|
@ -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 });
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in New Issue