Skip to content

Conversation

knakatasf
Copy link

Scope & Purpose

Adding resource monitors (specifically ResourceUsageScope) to MERGE and COLLECT methods to throw the exception when their performance exceeds a memory usage limit.

MERGE

  • Added ResourceUsageScope to ExecutorExpressionContext.
  • Added increaseMemoryUsage() logic to mergeParameters() method of ObjectFunctions.cpp.
  • Added testing functions to aql-memory-limit.js
  • Need to investigate how to pass the memory usage that MERGE used to AqlItemBlock.

COLLECT

  • Added ResourceUsageScope to SortedCollectExecutor.

  • Added ResourceUsageScope to one of the Aggregators.

  • Need to add the scope to other aggregators.

  • Need to add testing functions of this functionality.

  • 💩 Bugfix

  • 🍕 New feature

  • 🔥 Performance improvement

  • 🔨 Refactoring/simplification

Checklist

  • Tests
    • Regression tests
    • C++ Unit tests
    • integration tests
    • resilience tests
  • 📖 CHANGELOG entry made
  • 📚 documentation written (release notes, API changes, ...)
  • Backports
    • Backport for 3.12.0: (Please link PR)
    • Backport for 3.11: (Please link PR)
    • Backport for 3.10: (Please link PR)

Related Information

  • Docs PR:
  • Enterprise PR:
  • GitHub issue / Jira ticket:
  • Design document:

@cla-bot cla-bot bot added the cla-signed label Aug 1, 2025
@knakatasf knakatasf force-pushed the feature/merge-resource-monitor branch from 8cc0119 to 64c2c45 Compare August 7, 2025 00:23
@cpjulia cpjulia force-pushed the feature/merge-resource-monitor branch from 64c2c45 to 4f64c8e Compare August 7, 2025 14:31
@knakatasf knakatasf force-pushed the feature/merge-resource-monitor branch from 4f64c8e to 64c2c45 Compare August 7, 2025 16:58
cpjulia and others added 20 commits August 8, 2025 12:28
Copy link
Member

@mchacki mchacki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments and changes, but the review is not yet 100% complete, I will do another one.

@@ -32,6 +32,8 @@
#include "Transaction/Helpers.h"
#include "Transaction/Methods.h"

#include "Logger/LogMacros.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#include "Logger/LogMacros.h"

@@ -28,6 +28,7 @@
#include "Aql/RegisterId.h"
#include "Aql/RegIdFlatSet.h"
#include "Basics/Endian.h"
#include "Basics/ResourceUsage.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed here?
I would prefer to do the import in files that actually require it directly, this way we can save on recompile costs.

@@ -356,7 +360,7 @@ std::unique_ptr<ExecutionBlock> CollectNode::createBlock(
std::move(groupRegisters), collectRegister, expressionRegister,
_expressionVariable, std::move(aggregateTypes),
std::move(inputVariables), std::move(aggregateRegisters),
&_plan->getAst()->query().vpackOptions());
&_plan->getAst()->query().vpackOptions(), std::move(usageScope));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puh, we need to make sure that destruction ordering here is correct.

We reference the usageScope in the aggregators above.
We hand over responsibility into the Infos here.
Now on destructor we need to make sure aggregator vector is always destroyed before the usageScope, otherwise we get into undefined behavior here.

I am thinking:
Instead of handing in one Global scope,
should we instead give a reference to the ResourceMonitor& and then let each struct internally build it's own local scope? The ResourceMonitor is guaranteed to outlive this class.

@@ -101,6 +101,8 @@ std::unique_ptr<ExecutionBlock> IndexCollectNode::createBlockAggregationScan(
infos.groups.reserve(_groups.size());
infos.index = _index;
infos.query = &engine.getQuery();
infos.usageScope = std::make_unique<ResourceUsageScope>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why unique_ptr?
We could probably get away with a ResourceUsageScope directly right?

@@ -394,10 +394,11 @@ void WindowNode::calcAggregateRegisters(
}

void WindowNode::calcAggregateTypes(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am i blind or is there no one calling this function that would have to be adjusted?

@@ -137,6 +138,7 @@ class HashedCollectExecutorInfos {

/// @brief resource manager
arangodb::ResourceMonitor& _resourceMonitor;
std::unique_ptr<ResourceUsageScope> _usageScope;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

puh, i am getting afraid of destruction ordering here again.

I think moving the Scope as member of the aggregator is way safer.

input.getValue(infos.getExpressionRegister())
.toVelocyPack(infos.getVPackOptions(), _builder,
/*allowUnindexed*/ false);
auto val = input.getValue(infos.getExpressionRegister());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be replaced with the Supervised Builder now

@@ -266,16 +281,27 @@ void SortedCollectExecutor::CollectGroup::writeToOutput(
// set the group values
if (infos.getCollectRegister().value() != RegisterId::maxRegisterId) {
TRI_ASSERT(_builder.isOpenArray());
size_t before = _buffer.size();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here let us make this _buffer a SupervisedBuffer

@@ -92,7 +94,8 @@ BaseWindowExecutor::AggregatorList BaseWindowExecutor::createAggregators(
// initialize aggregators
for (auto const& r : infos.getAggregateTypes()) {
auto& factory = Aggregator::factoryFromTypeString(r);
aggregators.emplace_back(factory(infos.getVPackOptions()));
aggregators.emplace_back(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, destruction ordering

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants