mirror of https://gitee.com/bigwinds/arangodb
Observe limits
This commit is contained in:
parent
6eec6d1d5f
commit
ab77416063
|
@ -77,7 +77,7 @@ AqlValue&& ModifierOutput::getNewValue() const {
|
||||||
template <typename FetcherType, typename ModifierType>
|
template <typename FetcherType, typename ModifierType>
|
||||||
ModificationExecutor<FetcherType, ModifierType>::ModificationExecutor(Fetcher& fetcher,
|
ModificationExecutor<FetcherType, ModifierType>::ModificationExecutor(Fetcher& fetcher,
|
||||||
Infos& infos)
|
Infos& infos)
|
||||||
: _lastState(ExecutionState::HASMORE), _infos(infos), _fetcher(fetcher), _modifier(infos) {
|
: _infos(infos), _fetcher(fetcher), _modifier(infos) {
|
||||||
// In MMFiles we need to make sure that the data is not moved in memory or collected
|
// In MMFiles we need to make sure that the data is not moved in memory or collected
|
||||||
// for this collection as soon as we start writing to it.
|
// for this collection as soon as we start writing to it.
|
||||||
// This pin makes sure that no memory is moved pointers we get from a collection stay
|
// This pin makes sure that no memory is moved pointers we get from a collection stay
|
||||||
|
@ -129,8 +129,9 @@ ExecutorState ModificationExecutor<FetcherType, ModifierType>::doCollect(
|
||||||
InputAqlItemRow row{CreateInvalidInputRowHint{}};
|
InputAqlItemRow row{CreateInvalidInputRowHint{}};
|
||||||
ExecutorState state = ExecutorState::HASMORE;
|
ExecutorState state = ExecutorState::HASMORE;
|
||||||
|
|
||||||
const size_t maxOutputs = std::min(atMost, _modifier.getBatchSize());
|
// TODO: getHardLimit isn't named particularly well; maybe we need to
|
||||||
while (inputRange.hasMore() && _modifier.nrOfOperations() < maxOutputs) {
|
// just add a property to modifiers
|
||||||
|
while (inputRange.hasMore() && _modifier.nrOfOperations() < atMost) {
|
||||||
// if inputRange.hasMore() == true then the row is
|
// if inputRange.hasMore() == true then the row is
|
||||||
// guaranteed to be initialized.
|
// guaranteed to be initialized.
|
||||||
std::tie(state, row) = inputRange.next();
|
std::tie(state, row) = inputRange.next();
|
||||||
|
@ -178,7 +179,7 @@ std::pair<ExecutionState, typename ModificationExecutor<FetcherType, ModifierTyp
|
||||||
ModificationExecutor<FetcherType, ModifierType>::produceRows(OutputAqlItemRow& output) {
|
ModificationExecutor<FetcherType, ModifierType>::produceRows(OutputAqlItemRow& output) {
|
||||||
TRI_ASSERT(false);
|
TRI_ASSERT(false);
|
||||||
ModificationExecutor::Stats stats;
|
ModificationExecutor::Stats stats;
|
||||||
return {_lastState, ModificationExecutor::Stats{}};
|
return {ExecutionState::DONE, ModificationExecutor::Stats{}};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FetcherType, typename ModifierType>
|
template <typename FetcherType, typename ModifierType>
|
||||||
|
@ -187,15 +188,23 @@ std::tuple<ExecutorState, typename ModificationExecutor<FetcherType, ModifierTyp
|
||||||
ModificationExecutor<FetcherType, ModifierType>::produceRows(size_t atMost,
|
ModificationExecutor<FetcherType, ModifierType>::produceRows(size_t atMost,
|
||||||
AqlItemBlockInputRange& inputRange,
|
AqlItemBlockInputRange& inputRange,
|
||||||
OutputAqlItemRow& output) {
|
OutputAqlItemRow& output) {
|
||||||
|
// Ask the modifier whether it wants to impose any limits.
|
||||||
|
// Currently this is just the Upsert modifier who needs to set
|
||||||
|
// soft and hard limit to 1
|
||||||
|
AqlCall upstreamCall;
|
||||||
|
_modifier.adjustUpstreamCall(upstreamCall);
|
||||||
|
|
||||||
TRI_IF_FAILURE("ModificationBlock::getSome") {
|
TRI_IF_FAILURE("ModificationBlock::getSome") {
|
||||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect modifications for submission to transaction
|
|
||||||
ExecutorState state = ExecutorState::HASMORE;
|
ExecutorState state = ExecutorState::HASMORE;
|
||||||
state = doCollect(atMost, inputRange);
|
|
||||||
|
|
||||||
// Submit modifications
|
// This is really just an exception for Upsert, where
|
||||||
|
// we can only do one input/output
|
||||||
|
atMost = std::min(upstreamCall.getLimit(), atMost);
|
||||||
|
|
||||||
|
state = doCollect(atMost, inputRange);
|
||||||
_modifier.transact();
|
_modifier.transact();
|
||||||
|
|
||||||
// If the query is silent, there is no way to relate
|
// If the query is silent, there is no way to relate
|
||||||
|
@ -205,19 +214,14 @@ ModificationExecutor<FetcherType, ModifierType>::produceRows(size_t atMost,
|
||||||
// Yes. Really.
|
// Yes. Really.
|
||||||
TRI_ASSERT(_infos._options.silent || _modifier.nrOfDocuments() == _modifier.nrOfResults());
|
TRI_ASSERT(_infos._options.silent || _modifier.nrOfDocuments() == _modifier.nrOfResults());
|
||||||
|
|
||||||
// Produce output from collected modifications and the results of the
|
ModificationExecutor::Stats stats;
|
||||||
// submitted operations
|
|
||||||
doOutput(output);
|
doOutput(output);
|
||||||
|
|
||||||
ModificationExecutor::Stats stats;
|
|
||||||
if (_infos._doCount) {
|
if (_infos._doCount) {
|
||||||
stats.addWritesExecuted(_modifier.nrOfWritesExecuted());
|
stats.addWritesExecuted(_modifier.nrOfWritesExecuted());
|
||||||
stats.addWritesIgnored(_modifier.nrOfWritesIgnored());
|
stats.addWritesIgnored(_modifier.nrOfWritesIgnored());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Check this is correct
|
|
||||||
AqlCall upstreamCall;
|
|
||||||
upstreamCall.softLimit = atMost;
|
|
||||||
return {state, std::move(stats), upstreamCall};
|
return {state, std::move(stats), upstreamCall};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,8 @@ class ModifierOutput {
|
||||||
std::unique_ptr<AqlValue> _newValue;
|
std::unique_ptr<AqlValue> _newValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: As soon as the fetcher argument goes away out of the constructor, we can
|
||||||
|
// remove that template parameter.
|
||||||
template <typename FetcherType, typename ModifierType>
|
template <typename FetcherType, typename ModifierType>
|
||||||
class ModificationExecutor {
|
class ModificationExecutor {
|
||||||
public:
|
public:
|
||||||
|
@ -167,13 +169,8 @@ class ModificationExecutor {
|
||||||
protected:
|
protected:
|
||||||
ExecutorState doCollect(size_t const atMost, AqlItemBlockInputRange& inputRange);
|
ExecutorState doCollect(size_t const atMost, AqlItemBlockInputRange& inputRange);
|
||||||
std::pair<ExecutionState, Stats> doCollect(size_t const maxOutputs);
|
std::pair<ExecutionState, Stats> doCollect(size_t const maxOutputs);
|
||||||
void doOutput(OutputAqlItemRow& output);
|
void doOutput(OutputAqlItemRow& outputs);
|
||||||
|
|
||||||
// The state that was returned on the last call to produceRows. For us
|
|
||||||
// this is relevant because we might have collected some documents in the
|
|
||||||
// modifier's accumulator, but not written them yet, because we ran into
|
|
||||||
// WAITING
|
|
||||||
ExecutionState _lastState;
|
|
||||||
ModificationExecutorInfos& _infos;
|
ModificationExecutorInfos& _infos;
|
||||||
FetcherType& _fetcher;
|
FetcherType& _fetcher;
|
||||||
ModifierType _modifier;
|
ModifierType _modifier;
|
||||||
|
|
|
@ -134,8 +134,7 @@ SimpleModifier<ModifierCompletion, Enable>::SimpleModifier(ModificationExecutorI
|
||||||
: _infos(infos),
|
: _infos(infos),
|
||||||
_completion(infos),
|
_completion(infos),
|
||||||
_accumulator(nullptr),
|
_accumulator(nullptr),
|
||||||
_resultsIterator(VPackSlice::emptyArraySlice()),
|
_resultsIterator(VPackSlice::emptyArraySlice()) {}
|
||||||
_batchSize(ExecutionBlock::DefaultBatchSize()) {}
|
|
||||||
|
|
||||||
template <typename ModifierCompletion, typename Enable>
|
template <typename ModifierCompletion, typename Enable>
|
||||||
SimpleModifier<ModifierCompletion, Enable>::~SimpleModifier() = default;
|
SimpleModifier<ModifierCompletion, Enable>::~SimpleModifier() = default;
|
||||||
|
@ -206,10 +205,10 @@ ModificationExecutorInfos& SimpleModifier<ModifierCompletion, Enable>::getInfos(
|
||||||
return _infos;
|
return _infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Yes this is intentionally empty.
|
||||||
template <typename ModifierCompletion, typename Enable>
|
template <typename ModifierCompletion, typename Enable>
|
||||||
size_t SimpleModifier<ModifierCompletion, Enable>::getBatchSize() const noexcept {
|
void SimpleModifier<ModifierCompletion, Enable>::adjustUpstreamCall(AqlCall& call) const
|
||||||
return _batchSize;
|
noexcept {}
|
||||||
}
|
|
||||||
|
|
||||||
template <typename ModifierCompletion, typename Enable>
|
template <typename ModifierCompletion, typename Enable>
|
||||||
bool SimpleModifier<ModifierCompletion, Enable>::resultAvailable() const {
|
bool SimpleModifier<ModifierCompletion, Enable>::resultAvailable() const {
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "Aql/ModificationExecutorAccumulator.h"
|
#include "Aql/ModificationExecutorAccumulator.h"
|
||||||
#include "Aql/ModificationExecutorInfos.h"
|
#include "Aql/ModificationExecutorInfos.h"
|
||||||
|
|
||||||
|
#include "Aql/AqlCall.h"
|
||||||
#include "Aql/InsertModifier.h"
|
#include "Aql/InsertModifier.h"
|
||||||
#include "Aql/RemoveModifier.h"
|
#include "Aql/RemoveModifier.h"
|
||||||
#include "Aql/UpdateReplaceModifier.h"
|
#include "Aql/UpdateReplaceModifier.h"
|
||||||
|
@ -117,14 +118,14 @@ class SimpleModifier {
|
||||||
size_t nrOfDocuments() const;
|
size_t nrOfDocuments() const;
|
||||||
// The number of entries in the results slice
|
// The number of entries in the results slice
|
||||||
size_t nrOfResults() const;
|
size_t nrOfResults() const;
|
||||||
|
// The number of errors that occurred in a transaction
|
||||||
size_t nrOfErrors() const;
|
size_t nrOfErrors() const;
|
||||||
|
|
||||||
size_t nrOfWritesExecuted() const;
|
size_t nrOfWritesExecuted() const;
|
||||||
size_t nrOfWritesIgnored() const;
|
size_t nrOfWritesIgnored() const;
|
||||||
|
|
||||||
ModificationExecutorInfos& getInfos() const noexcept;
|
ModificationExecutorInfos& getInfos() const noexcept;
|
||||||
size_t getBatchSize() const noexcept;
|
void adjustUpstreamCall(AqlCall& call) const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool resultAvailable() const;
|
bool resultAvailable() const;
|
||||||
|
@ -140,8 +141,6 @@ class SimpleModifier {
|
||||||
|
|
||||||
std::vector<ModOp>::const_iterator _operationsIterator;
|
std::vector<ModOp>::const_iterator _operationsIterator;
|
||||||
VPackArrayIterator _resultsIterator;
|
VPackArrayIterator _resultsIterator;
|
||||||
|
|
||||||
size_t const _batchSize;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using InsertModifier = SimpleModifier<InsertModifierCompletion>;
|
using InsertModifier = SimpleModifier<InsertModifierCompletion>;
|
||||||
|
|
|
@ -132,13 +132,7 @@ typename UpsertModifier::OutputIterator UpsertModifier::OutputIterator::end() co
|
||||||
}
|
}
|
||||||
|
|
||||||
UpsertModifier::UpsertModifier(ModificationExecutorInfos& infos)
|
UpsertModifier::UpsertModifier(ModificationExecutorInfos& infos)
|
||||||
: _infos(infos),
|
: _infos(infos) {}
|
||||||
|
|
||||||
// Batch size has to be 1 so that the upsert modifier sees its own
|
|
||||||
// writes.
|
|
||||||
// This behaviour could be improved, if we can prove that an UPSERT
|
|
||||||
// does not need to see its own writes
|
|
||||||
_batchSize(1) {}
|
|
||||||
|
|
||||||
UpsertModifier::~UpsertModifier() = default;
|
UpsertModifier::~UpsertModifier() = default;
|
||||||
|
|
||||||
|
@ -312,4 +306,7 @@ size_t UpsertModifier::nrOfWritesExecuted() const {
|
||||||
|
|
||||||
size_t UpsertModifier::nrOfWritesIgnored() const { return nrOfErrors(); }
|
size_t UpsertModifier::nrOfWritesIgnored() const { return nrOfErrors(); }
|
||||||
|
|
||||||
size_t UpsertModifier::getBatchSize() const { return _batchSize; }
|
void UpsertModifier::adjustUpstreamCall(AqlCall& call) const noexcept {
|
||||||
|
call.softLimit = 1;
|
||||||
|
call.hardLimit = 1;
|
||||||
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ class UpsertModifier {
|
||||||
size_t nrOfWritesExecuted() const;
|
size_t nrOfWritesExecuted() const;
|
||||||
size_t nrOfWritesIgnored() const;
|
size_t nrOfWritesIgnored() const;
|
||||||
|
|
||||||
size_t getBatchSize() const;
|
void adjustUpstreamCall(AqlCall& call) const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool resultAvailable() const;
|
bool resultAvailable() const;
|
||||||
|
@ -104,8 +104,6 @@ class UpsertModifier {
|
||||||
|
|
||||||
OperationResult _updateResults;
|
OperationResult _updateResults;
|
||||||
OperationResult _insertResults;
|
OperationResult _insertResults;
|
||||||
|
|
||||||
size_t const _batchSize;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace aql
|
} // namespace aql
|
||||||
|
|
Loading…
Reference in New Issue