1
0
Fork 0

Aql by line mixed fixes (#8349)

This commit is contained in:
Tobias Gödderz 2019-03-14 19:38:41 +01:00 committed by Jan
parent a2ca779e71
commit 8d649903f7
26 changed files with 170 additions and 78 deletions

View File

@ -41,6 +41,7 @@ class ExecutionEngineResult {
ExecutionEngineResult(int errorNumber, std::string&& errorMessage);
// This is not explicit on purpose
// cppcheck-suppress noExplicitConstructor
// NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
ExecutionEngineResult(Result const& result);
explicit ExecutionEngineResult(ExecutionEngine*);

View File

@ -40,7 +40,10 @@ using namespace arangodb::aql;
CountCollectExecutorInfos::CountCollectExecutorInfos(
RegisterId collectRegister, RegisterId nrInputRegisters,
RegisterId nrOutputRegisters, std::unordered_set<RegisterId> registersToClear,
RegisterId nrOutputRegisters,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToKeep)
: ExecutorInfos(std::make_shared<std::unordered_set<RegisterId>>(),
make_shared_unordered_set({collectRegister}),

View File

@ -45,8 +45,10 @@ using namespace arangodb;
using namespace arangodb::aql;
EnumerateCollectionExecutorInfos::EnumerateCollectionExecutorInfos(
RegisterId outputRegister, RegisterId nrInputRegisters,
RegisterId nrOutputRegisters, std::unordered_set<RegisterId> registersToClear,
RegisterId outputRegister, RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToKeep, ExecutionEngine* engine,
Collection const* collection, Variable const* outVariable, bool produceResult,
std::vector<std::string> const& projections, transaction::Methods* trxPtr,

View File

@ -40,7 +40,10 @@ using namespace arangodb::aql;
EnumerateListExecutorInfos::EnumerateListExecutorInfos(
RegisterId inputRegister, RegisterId outputRegister, RegisterId nrInputRegisters,
RegisterId nrOutputRegisters, std::unordered_set<RegisterId> registersToClear,
RegisterId nrOutputRegisters,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToKeep)
: ExecutorInfos(make_shared_unordered_set({inputRegister}),
make_shared_unordered_set({outputRegister}),

View File

@ -50,6 +50,7 @@ class SingleRowFetcher;
class EnumerateListExecutorInfos : public ExecutorInfos {
public:
// cppcheck-suppress passedByValue
EnumerateListExecutorInfos(RegisterId inputRegister, RegisterId outputRegister,
RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
std::unordered_set<RegisterId> registersToClear,

View File

@ -24,10 +24,15 @@
using namespace arangodb::aql;
ExecutorInfos::ExecutorInfos(std::shared_ptr<std::unordered_set<RegisterId>> readableInputRegisters,
ExecutorInfos::ExecutorInfos(
// cppcheck-suppress passedByValue
std::shared_ptr<std::unordered_set<RegisterId>> readableInputRegisters,
// cppcheck-suppress passedByValue
std::shared_ptr<std::unordered_set<RegisterId>> writeableOutputRegisters,
RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToKeep)
: _inRegs(std::move(readableInputRegisters)),
_outRegs(std::move(writeableOutputRegisters)),

View File

@ -40,7 +40,9 @@ using namespace arangodb::aql;
FilterExecutorInfos::FilterExecutorInfos(RegisterId inputRegister, RegisterId nrInputRegisters,
RegisterId nrOutputRegisters,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToKeep)
: ExecutorInfos(std::make_shared<std::unordered_set<RegisterId>>(inputRegister),
nullptr, nrInputRegisters, nrOutputRegisters,

View File

@ -32,7 +32,9 @@ using namespace arangodb;
using namespace arangodb::aql;
IdExecutorInfos::IdExecutorInfos(RegisterId nrInOutRegisters,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> toKeep,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear)
: ExecutorInfos(make_shared_unordered_set(), make_shared_unordered_set(),
nrInOutRegisters, nrInOutRegisters,

View File

@ -56,6 +56,10 @@ void InAndOutRowExpressionContext::setInputRow(InputAqlItemRow input) {
_input = input;
}
void InAndOutRowExpressionContext::invalidateInputRow() {
_input = InputAqlItemRow{CreateInvalidInputRowHint{}};
}
AqlValue const& InAndOutRowExpressionContext::getRegisterValue(size_t i) const {
TRI_ASSERT(_input.isInitialized());
TRI_ASSERT(i < _regs.size());

View File

@ -49,6 +49,8 @@ class InAndOutRowExpressionContext final : public QueryExpressionContext {
void setInputRow(InputAqlItemRow input);
void invalidateInputRow();
size_t numRegisters() const override { return _regs.size(); }
AqlValue const& getRegisterValue(size_t i) const override;

View File

@ -43,6 +43,7 @@
#include <lib/Logger/LogMacros.h>
#include <memory>
#include <utility>
using namespace arangodb;
@ -65,8 +66,10 @@ static void resolveFCallConstAttributes(AstNode* fcall) {
} // namespace
IndexExecutorInfos::IndexExecutorInfos(
RegisterId outputRegister, RegisterId nrInputRegisters,
RegisterId nrOutputRegisters, std::unordered_set<RegisterId> registersToClear,
RegisterId outputRegister, RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToKeep, ExecutionEngine* engine,
Collection const* collection, Variable const* outVariable, bool produceResult,
std::vector<std::string> const& projections, transaction::Methods* trxPtr,
@ -80,7 +83,7 @@ IndexExecutorInfos::IndexExecutorInfos(
make_shared_unordered_set({outputRegister}),
nrInputRegisters, nrOutputRegisters,
std::move(registersToClear), std::move(registersToKeep)),
_indexes(indexes),
_indexes(std::move(indexes)),
_condition(condition),
_ast(ast),
_hasMultipleExpansions(false),
@ -107,9 +110,10 @@ IndexExecutor::IndexExecutor(Fetcher& fetcher, Infos& infos)
_allowCoveringIndexOptimization(false),
_cursor(nullptr),
_cursors(_infos.getIndexes().size()),
_currentIndex(0),
_alreadyReturned(),
_indexesExhausted(false),
_isLastIndex(false) {
TRI_ASSERT(!_infos.getIndexes().empty());
if (_infos.getCondition() != nullptr) {
@ -340,7 +344,7 @@ void IndexExecutor::executeExpressions(InputAqlItemRow& input) {
// The following are needed to evaluate expressions with local data from
// the current incoming item:
auto ast = _infos.getAst();
AstNode* condition = const_cast<AstNode*>(_infos.getCondition());
auto* condition = const_cast<AstNode*>(_infos.getCondition());
// modify the existing node in place
TEMPORARILY_UNLOCK_NODE(condition);
@ -435,7 +439,7 @@ std::pair<ExecutionState, IndexStats> IndexExecutor::produceRow(OutputAqlItemRow
}
}
TRI_ASSERT(_input.isInitialized());
TRI_ASSERT(getCursor()->hasMore());
TRI_ASSERT(getCursor() != nullptr && getCursor()->hasMore());
IndexIterator::DocumentCallback callback;
@ -473,10 +477,8 @@ std::pair<ExecutionState, IndexStats> IndexExecutor::produceRow(OutputAqlItemRow
TRI_ASSERT(!getIndexesExhausted());
// Read the next elements from the indexes
// auto saveReturned = _infos.getReturned();
bool more = readIndex(callback, hasWritten);
// TRI_ASSERT(!more || _infos.getCursor()->hasMore());
TRI_ASSERT((getCursor() != nullptr || !more) || (getCursor() != nullptr && more == getCursor()->hasMore()));
TRI_ASSERT(getCursor() != nullptr || !more);
if (!more) {
_input = InputAqlItemRow{CreateInvalidInputRowHint{}};

View File

@ -181,11 +181,10 @@ class IndexExecutor {
typedef std::function<void(InputAqlItemRow&, OutputAqlItemRow&, arangodb::velocypack::Slice, RegisterId)> DocumentProducingFunction;
void setProducingFunction(DocumentProducingFunction documentProducer) {
_documentProducer = documentProducer;
_documentProducer = std::move(documentProducer);
}
private:
bool initializeCursor();
bool advanceCursor();
void executeExpressions(InputAqlItemRow& input);
bool initIndexes(InputAqlItemRow& input);

View File

@ -58,7 +58,9 @@ class InputAqlItemRow {
explicit InputAqlItemRow(CreateInvalidInputRowHint)
: _blockShell(nullptr), _baseIndex(0) {}
InputAqlItemRow(std::shared_ptr<AqlItemBlockShell> blockShell, size_t baseIndex)
InputAqlItemRow(
// cppcheck-suppress passedByValue
std::shared_ptr<AqlItemBlockShell> blockShell, size_t baseIndex)
: _blockShell(std::move(blockShell)), _baseIndex(baseIndex) {
TRI_ASSERT(_blockShell != nullptr);
}

View File

@ -39,7 +39,9 @@ using namespace arangodb;
using namespace arangodb::aql;
LimitExecutorInfos::LimitExecutorInfos(RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToKeep,
size_t offset, size_t limit, bool fullCount)
: ExecutorInfos(std::make_shared<std::unordered_set<RegisterId>>(),

View File

@ -25,6 +25,8 @@
#include "Aql/InAndOutRowExpressionContext.h"
#include <utility>
namespace arangodb {
namespace velocypack {
class Slice;
@ -48,7 +50,8 @@ class PruneExpressionEvaluator {
~PruneExpressionEvaluator();
bool evaluate();
void prepareContext(InputAqlItemRow input) { _ctx.setInputRow(input); }
void prepareContext(InputAqlItemRow input) { _ctx.setInputRow(std::move(input)); }
void unPrepareContext() { _ctx.invalidateInputRow(); }
bool needsVertex() const { return _ctx.needsVertexValue(); }
void injectVertex(velocypack::Slice v) { _ctx.setVertexValue(v); }

View File

@ -52,8 +52,6 @@ class ReturnExecutorInfos : public ExecutorInfos {
ReturnExecutorInfos(ReturnExecutorInfos const&) = delete;
~ReturnExecutorInfos() = default;
Variable const& inVariable() const { return *_inVariable; }
RegisterId getInputRegisterId() const { return _inputRegisterId; }
RegisterId getOutputRegisterId() const {
@ -68,7 +66,6 @@ class ReturnExecutorInfos : public ExecutorInfos {
private:
/// @brief the variable produced by Return
Variable const* _inVariable;
RegisterId _inputRegisterId;
bool _doCount;
bool _returnInheritedResults;

View File

@ -35,6 +35,8 @@
#include <velocypack/StringRef.h>
#include <velocypack/velocypack-aliases.h>
#include <utility>
using namespace arangodb;
using namespace arangodb::aql;
using namespace arangodb::graph;
@ -55,7 +57,8 @@ ShortestPathExecutorInfos::ShortestPathExecutorInfos(
std::unique_ptr<graph::ShortestPathFinder>&& finder,
std::unordered_map<OutputName, RegisterId, OutputNameHash>&& registerMapping,
InputVertex&& source, InputVertex&& target)
: ExecutorInfos(inputRegisters, outputRegisters, nrInputRegisters, nrOutputRegisters,
: ExecutorInfos(std::move(inputRegisters), std::move(outputRegisters),
nrInputRegisters, nrOutputRegisters,
std::move(registersToClear), std::move(registersToKeep)),
_finder(std::move(finder)),
_registerMapping(std::move(registerMapping)),

View File

@ -58,9 +58,11 @@ class ShortestPathExecutorInfos : public ExecutorInfos {
RegisterId reg;
std::string value;
InputVertex(std::string const value)
: type(CONSTANT), reg(0), value(value) {}
InputVertex(RegisterId reg) : type(REGISTER), reg(reg), value("") {}
// cppcheck-suppress passedByValue
explicit InputVertex(std::string value)
: type(CONSTANT), reg(0), value(std::move(value)) {}
explicit InputVertex(RegisterId reg)
: type(REGISTER), reg(reg), value("") {}
};
enum OutputName { VERTEX, EDGE };

View File

@ -72,21 +72,22 @@ static void parseNodeInput(AstNode const* node, std::string& id, Variable const*
}
static ShortestPathExecutorInfos::InputVertex prepareVertexInput(ShortestPathNode const* node,
bool isTarget) {
using InputVertex = ShortestPathExecutorInfos::InputVertex;
if (isTarget) {
if (node->usesTargetInVariable()) {
auto it = node->getRegisterPlan()->varInfo.find(node->targetInVariable()->id);
TRI_ASSERT(it != node->getRegisterPlan()->varInfo.end());
return {it->second.registerId};
return InputVertex{it->second.registerId};
} else {
return {node->getTargetVertex()};
return InputVertex{node->getTargetVertex()};
}
} else {
if (node->usesStartInVariable()) {
auto it = node->getRegisterPlan()->varInfo.find(node->startInVariable()->id);
TRI_ASSERT(it != node->getRegisterPlan()->varInfo.end());
return {it->second.registerId};
return InputVertex{it->second.registerId};
} else {
return {node->getStartVertex()};
return InputVertex{node->getStartVertex()};
}
}
}

View File

@ -81,12 +81,14 @@ static std::shared_ptr<std::unordered_set<RegisterId>> mapSortRegistersToRegiste
return set;
}
SortExecutorInfos::SortExecutorInfos(std::vector<SortRegister> sortRegisters,
std::size_t limit, AqlItemBlockManager& manager,
RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
SortExecutorInfos::SortExecutorInfos(
// cppcheck-suppress passedByValue
std::vector<SortRegister> sortRegisters, std::size_t limit,
AqlItemBlockManager& manager, RegisterId nrInputRegisters, RegisterId nrOutputRegisters,
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToClear,
std::unordered_set<RegisterId> registersToKeep,
transaction::Methods* trx, bool stable)
// cppcheck-suppress passedByValue
std::unordered_set<RegisterId> registersToKeep, transaction::Methods* trx, bool stable)
: ExecutorInfos(mapSortRegistersToRegisterIds(sortRegisters), nullptr,
nrInputRegisters, nrOutputRegisters,
std::move(registersToClear), std::move(registersToKeep)),

View File

@ -116,7 +116,22 @@ TraversalExecutor::TraversalExecutor(Fetcher& fetcher, Infos& infos)
_input{CreateInvalidInputRowHint{}},
_rowState(ExecutionState::HASMORE),
_traverser(infos.traverser()) {}
TraversalExecutor::~TraversalExecutor() = default;
TraversalExecutor::~TraversalExecutor() {
auto opts = _traverser.options();
if (opts != nullptr && opts->usesPrune()) {
auto *evaluator = opts->getPruneEvaluator();
if (evaluator != nullptr) {
// The InAndOutRowExpressionContext in the PruneExpressionEvaluator holds
// an InputAqlItemRow. As the Plan holds the PruneExpressionEvaluator and
// is destroyed after the Engine, this must be deleted by
// unPrepareContext() - otherwise, the AqlItemBlockShell referenced by the
// row will return its AqlItemBlock to an already destroyed
// AqlItemBlockManager.
evaluator->unPrepareContext();
}
}
};
// Shutdown query
std::pair<ExecutionState, Result> TraversalExecutor::shutdown(int errorCode) {
@ -163,18 +178,21 @@ std::pair<ExecutionState, TraversalStats> TraversalExecutor::produceRow(OutputAq
} else {
// traverser now has next v, e, p values
if (_infos.useVertexOutput()) {
output.cloneValueInto(_infos.vertexRegister(), _input,
_traverser.lastVertexToAqlValue());
AqlValue vertex = _traverser.lastVertexToAqlValue();
AqlValueGuard guard{vertex, true};
output.moveValueInto(_infos.vertexRegister(), _input, guard);
}
if (_infos.useEdgeOutput()) {
output.cloneValueInto(_infos.edgeRegister(), _input,
_traverser.lastEdgeToAqlValue());
AqlValue edge = _traverser.lastEdgeToAqlValue();
AqlValueGuard guard{edge, true};
output.moveValueInto(_infos.edgeRegister(), _input, guard);
}
if (_infos.usePathOutput()) {
transaction::BuilderLeaser tmp(_traverser.trx());
tmp->clear();
output.cloneValueInto(_infos.pathRegister(), _input,
_traverser.pathToAqlValue(*tmp.builder()));
AqlValue path = _traverser.pathToAqlValue(*tmp.builder());
AqlValueGuard guard{path, true};
output.moveValueInto(_infos.pathRegister(), _input, guard);
}
s.addFiltered(_traverser.getAndResetFilteredPaths());
s.addScannedIndex(_traverser.getAndResetReadDocuments());

View File

@ -206,8 +206,7 @@ arangodb::aql::AqlValue BreadthFirstEnumerator::edgeToAqlValue(size_t index) {
return _opts->cache()->fetchEdgeAqlResult(_schreier[index]->edge);
}
arangodb::aql::AqlValue BreadthFirstEnumerator::pathToIndexToAqlValue(
arangodb::velocypack::Builder& result, size_t index) {
VPackSlice BreadthFirstEnumerator::pathToIndexToSlice(VPackBuilder& result, size_t index) {
// TODO make deque class variable
std::deque<size_t> fullPath;
while (index != 0) {
@ -234,7 +233,13 @@ arangodb::aql::AqlValue BreadthFirstEnumerator::pathToIndexToAqlValue(
}
result.close(); // vertices
result.close();
return arangodb::aql::AqlValue(result.slice());
TRI_ASSERT(result.isClosed());
return result.slice();
}
arangodb::aql::AqlValue BreadthFirstEnumerator::pathToIndexToAqlValue(
arangodb::velocypack::Builder& result, size_t index) {
return arangodb::aql::AqlValue(pathToIndexToSlice(result, index));
}
bool BreadthFirstEnumerator::pathContainsVertex(size_t index,
@ -297,19 +302,33 @@ bool BreadthFirstEnumerator::prepareSearchOnNextDepth() {
bool BreadthFirstEnumerator::shouldPrune() {
if (_opts->usesPrune()) {
// evaluator->evaluate() might access these, so they have to live long enough.
// To make that perfectly clear, I added a scope.
transaction::BuilderLeaser pathBuilder(_opts->trx());
aql::AqlValue vertex, edge;
aql::AqlValueGuard vertexGuard{vertex, true}, edgeGuard{edge, true};
{
auto *evaluator = _opts->getPruneEvaluator();
if (evaluator->needsVertex()) {
evaluator->injectVertex(vertexToAqlValue(_schreierIndex).slice());
// Note: vertexToAqlValue() copies the original vertex into the AqlValue.
// This could be avoided with a function that just returns the slice,
// as it will stay valid long enough.
vertex = vertexToAqlValue(_schreierIndex);
evaluator->injectVertex(vertex.slice());
}
if (evaluator->needsEdge()) {
evaluator->injectEdge(edgeToAqlValue(_schreierIndex).slice());
// Note: edgeToAqlValue() copies the original edge into the AqlValue.
// This could be avoided with a function that just returns the slice,
// as it will stay valid long enough.
edge = edgeToAqlValue(_schreierIndex);
evaluator->injectEdge(edge.slice());
}
transaction::BuilderLeaser builder(_opts->trx());
if (evaluator->needsPath()) {
aql::AqlValue val = pathToIndexToAqlValue(*builder.get(), _schreierIndex);
evaluator->injectPath(val.slice());
VPackSlice path = pathToIndexToSlice(*pathBuilder.get(), _schreierIndex);
evaluator->injectPath(path);
}
return evaluator->evaluate();
}
}
return false;
}

View File

@ -186,6 +186,8 @@ class BreadthFirstEnumerator final : public arangodb::traverser::PathEnumerator
aql::AqlValue pathToIndexToAqlValue(arangodb::velocypack::Builder& result, size_t index);
velocypack::Slice pathToIndexToSlice(arangodb::velocypack::Builder& result, size_t index);
bool shouldPrune();
};
} // namespace graph

View File

@ -194,7 +194,7 @@ arangodb::aql::AqlValue DepthFirstEnumerator::lastEdgeToAqlValue() {
return _opts->cache()->fetchEdgeAqlResult(_enumeratedPath.edges.back());
}
arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(arangodb::velocypack::Builder& result) {
VPackSlice DepthFirstEnumerator::pathToSlice(VPackBuilder& result) {
result.clear();
result.openObject();
result.add(VPackValue("edges"));
@ -207,29 +207,42 @@ arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(arangodb::velocypac
result.add(VPackValue("vertices"));
result.openArray();
for (auto const& it : _enumeratedPath.vertices) {
_traverser->addVertexToVelocyPack(arangodb::velocypack::StringRef(it), result);
_traverser->addVertexToVelocyPack(VPackStringRef(it), result);
}
result.close();
result.close();
return arangodb::aql::AqlValue(result.slice());
TRI_ASSERT(result.isClosed());
return result.slice();
}
arangodb::aql::AqlValue DepthFirstEnumerator::pathToAqlValue(VPackBuilder& result) {
return arangodb::aql::AqlValue(pathToSlice(result));
}
bool DepthFirstEnumerator::shouldPrune() {
// We need to call prune here
if (_opts->usesPrune()) {
auto* evaluator = _opts->getPruneEvaluator();
// evaluator->evaluate() might access these, so they have to live long
// enough. To make that perfectly clear, I added a scope.
transaction::BuilderLeaser pathBuilder(_opts->trx());
aql::AqlValue vertex, edge;
aql::AqlValueGuard vertexGuard{vertex, true}, edgeGuard{edge, true};
{
aql::PruneExpressionEvaluator* evaluator = _opts->getPruneEvaluator();
if (evaluator->needsVertex()) {
evaluator->injectVertex(lastVertexToAqlValue().slice());
vertex = lastVertexToAqlValue();
evaluator->injectVertex(vertex.slice());
}
if (evaluator->needsEdge()) {
evaluator->injectEdge(lastEdgeToAqlValue().slice());
edge = lastEdgeToAqlValue();
evaluator->injectEdge(edge.slice());
}
transaction::BuilderLeaser builder(_opts->trx());
if (evaluator->needsPath()) {
aql::AqlValue val = pathToAqlValue(*builder.get());
evaluator->injectPath(val.slice());
VPackSlice path = pathToSlice(*pathBuilder.get());
evaluator->injectPath(path);
}
return evaluator->evaluate();
}
}
return false;
}

View File

@ -133,6 +133,8 @@ class DepthFirstEnumerator final : public PathEnumerator {
private:
bool shouldPrune();
velocypack::Slice pathToSlice(arangodb::velocypack::Builder& result);
};
} // namespace traverser
} // namespace arangodb