8000 Add a fake FASTFORWARD call into a subquery-skipped ModificationExecu… · arangodb/arangodb@e6a8dcb · GitHub
[go: up one dir, main page]

Skip to content

Commit e6a8dcb

Browse files
committed
Add a fake FASTFORWARD call into a subquery-skipped ModificationExecutor.
1 parent d766db9 commit e6a8dcb

File tree

2 files changed

+54
-19
lines changed

2 files changed

+54
-19
lines changed

arangod/Aql/AqlCallStack.h

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,6 @@ class AqlCallStack {
6363
// Put another call on top of the stack.
6464
void pushCall(AqlCall&& call);
6565

66-
// fill up all missing calls within this stack s.t. we reach depth == 0
67-
// This needs to be called if an executor requires to be fully executed, even if skipped,
68-
// even if the subquery it is located in is skipped.
69-
// The default operations added here will correspond to produce all Rows, unlimitted.
70-
// e.g. every Modification Executor needs to call this functionality, as modifictions need to be
71-
// performed even if skipped.
72-
void stackUpMissingCalls();
73-
7466
// Pops one subquery level.
7567
// if this isRelevent it pops the top-most call from the stack.
7668
// if this is not revelent it reduces the depth by 1.
@@ -94,12 +86,35 @@ class AqlCallStack {
9486

9587
auto is36Compatible() const noexcept -> bool { return _compatibilityMode3_6; }
9688

89+
/**
90+
* @brief Create an equivalent call stack that does a full-produce
91+
* of all Subquery levels. This is required for blocks
92+
* that are not allowed to be bpassed.
93+
* The top-most call remains unmodified, as the Executor might
94+
* require some soft limit on it.
95+
*
96+
* @return AqlCallStack a stack of equivalent size, that does not skip
97+
* on any lower subquery.
98+
*/
99+
auto createEquivalentFetchAllShadowRowsStack() const -> AqlCallStack;
100+
101+
/**
102+
* @brief Check if we are in a subquery that is in-fact required to
103+
* be skipped. This is relevant for executors that have created
104+
* an equivalentFetchAllShadowRows stack, in order to decide if
105+
* the need to produce output or if they are skipped.
106+
*
107+
* @return true
108+
* @return false
109+
*/
110+
auto needToSkipSubquery() const noexcept -> bool;
111+
97112
private:
98-
explicit AqlCallStack(std::stack<AqlCall>&& operations);
113+
explicit AqlCallStack(std::vector<AqlCall>&& operations);
99114

100115
private:
101116
// The list of operations, stacked by depth (e.g. bottom element is from main query)
102-
std::stack<AqlCall> _operations;
117+
std::vector<AqlCall> _operations;
103118

104119
// The depth of subqueries that have not issued calls into operations,
105120
// as they have been skipped.

arangod/Aql/ExecutionBlockImpl.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,14 +1229,7 @@ static auto fastForwardType(AqlCall const& call, Executor const& e) -> FastForwa
12291229
}
12301230
// TODO: We only need to do this is the executor actually require to call.
12311231
// e.g. Modifications will always need to be called. Limit only if it needs to report fullCount
1232-
if constexpr (is_one_of_v<Executor, LimitExecutor, ModificationExecutor<AllRowsFetcher, InsertModifier>,
1233-
ModificationExecutor<SingleRowFetcher<BlockPassthrough::Disable>, InsertModifier>,
1234-
ModificationExecutor<AllRowsFetcher, RemoveModifier>,
1235-
ModificationExecutor<SingleRowFetcher<BlockPassthrough::Disable>, RemoveModifier>,
1236-
ModificationExecutor<AllRowsFetcher, UpdateReplaceModifier>,
1237-
ModificationExecutor<SingleRowFetcher<BlockPassthrough::Disable>, UpdateReplaceModifier>,
1238-
ModificationExecutor<AllRowsFetcher, UpsertModifier>,
1239-
ModificationExecutor<SingleRowFetcher<BlockPassthrough::Disable>, UpsertModifier>>) {
1232+
if constexpr (std::is_same_v<Executor, LimitExecutor> || executorHasSideEffects<Executor>) {
12401233
return FastForwardVariant::EXECUTOR;
12411234
}
12421235
return FastForwardVariant::FETCHER;
@@ -1676,6 +1669,16 @@ ExecutionBlockImpl<Executor>::executeWithoutTrace(AqlCallStack stack) {
16761669
case ExecState::CHECKCALL: {
16771670
LOG_QUERY("cfe46", DEBUG)
16781671
<< printTypeInfo() << " determine next action on call " << clientCall;
1672+
1673+
if constexpr (executorHasSideEffects<Executor>) {
1674+
// If the executor has sideEffects, and we need to skip the results we would
1675+
// produce here because we actually skip the subquery, we instead do a
1676+
// hardLimit 0 (aka FastForward) call instead to the local Executor
1677+
if (stack.needToSkipSubquery()) {
1678+
_execState = ExecState::FASTFORWARD;
1679+
break;
1680+
}
1681+
}
16791682
_execState = nextState(clientCall);
16801683
break;
16811684
}
@@ -1830,8 +1833,25 @@ ExecutionBlockImpl<Executor>::executeWithoutTrace(AqlCallStack stack) {
18301833
case ExecState::FASTFORWARD: {
18311834
LOG_QUERY("96e2c", DEBUG)
18321835
<< printTypeInfo() << " all produced, fast forward to end up (sub-)query.";
1836+
AqlCall callCopy = clientCall;
1837+
if constexpr (executorHasSideEffects<Executor>) {
1838+
if (stack.needToSkipSubquery()) {
1839+
// Fast Forward call.
1840+
callCopy = AqlCall{0, false, 0, AqlCall::LimitType::HARD};
1841+
}
1842+
}
18331843
auto [state, stats, skippedLocal, call, dependency] =
1834-
executeFastForward(_lastRange, clientCall);
1844+
executeFastForward(_lastRange, callCopy);
1845+
if constexpr (executorHasSideEffects<Executor>) {
1846+
if (!stack.needToSkipSubquery()) {
1847+
// We need to modify the original call.
1848+
clientCall = callCopy;
1849+
}
1850+
// else: We are bypassing the results.
1851+
// Do not count them here.
1852+
} else {
1853+
clientCall = callCopy;
1854+
}
18351855

18361856
_requestedDependency = dependency;
18371857
_skipped.didSkip(skippedLocal);

0 commit comments

Comments
 (0)
0