Skip to content

MQE: track output series label copies in binary operations - #17125

Open
fionaliao wants to merge 2 commits into
mainfrom
fl/mqe-binop-untracked-memory
Open

fionaliao wants to merge 2 commits into
mainfrom
fl/mqe-binop-untracked-memory

Conversation

@fionaliao

@fionaliao fionaliao commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

GroupedVectorVectorBinaryOperation and OneToOneVectorVectorBinaryOperation both create temporary maps of output series, with a copy of the series labels being the key. These copied labels are unaccounted for in the memory consumption estimate. This causes the actual memory usage to be higher than the estimate, occasionally leading to OOMs that should be protected against.

This is particularly a problem for GroupedVectorVectorBinaryOperation, because its output series can be a cross join of the two sides. Each "many" side series is paired with every "one" side series in its group that is present at any point in the query time range. The output series map can then be much larger than either input, so the untracked label copies are a large part of the memory used.

This PR counts the copied labels in the estimate while the map exists, and releases them once the output series are returned.

It also makes GroupedVectorVectorBinaryOperation keep the buffer it encodes labels into, as OneToOneVectorVectorBinaryOperation already does. Before, the result of Bytes() was discarded, so the buffer never grew past its initial 1 KB. Every label set larger than that allocated a new temporary buffer, twice for each output series.

@semgrep-code-grafana

This comment was marked as outdated.

@fionaliao
fionaliao force-pushed the fl/mqe-binop-untracked-memory branch 2 times, most recently from 0757f05 to c5bae88 Compare November 2, 2026 19:54
computeOutputSeries called l.Bytes(buf) twice for each new output
series and did not keep the result. For label sets larger than
types.LabelBytesBufferSize, each call allocated a new buffer.

Call Bytes once and assign the result back to buf, as the one-to-one
operator already does. In a local benchmark of SeriesMetadata with
10k output series and labels over the buffer size, this allocated
47% fewer bytes, made 37% fewer allocations and took 35% less time.
Small label sets did not change.
@fionaliao
fionaliao force-pushed the fl/mqe-binop-untracked-memory branch 3 times, most recently from 9bde44d to 0a37008 Compare November 3, 2026 17:35
One-to-one and grouped binary operations key outputSeriesMap by a copy
of each output series' labels. This copy was not included in the
memory consumption estimate. For queries that produce many output
series, such as a range topk on the "one" side of a group_left join,
the copies are a large part of the peak memory use, so the query could
exhaust memory before the per-query limit rejected it.

Count the copies under a new BinaryOperationOutputSeries memory source
while the map exists, and release them when computeOutputSeries
returns.
@fionaliao
fionaliao force-pushed the fl/mqe-binop-untracked-memory branch from 0a37008 to 8ebe742 Compare November 3, 2026 17:38
@fionaliao fionaliao changed the title MQE: track untracked memory in binary operations MQE: track output series label copies in binary operations Nov 3, 2026
@fionaliao
fionaliao marked this pull request as ready for review November 3, 2026 17:53
@fionaliao
fionaliao requested a review from a team as a code owner November 3, 2026 17:53
@56quarters 56quarters self-assigned this Nov 3, 2026

@56quarters 56quarters left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice.


types.SeriesMetadataSlicePool.Put(&outputSeries, memoryConsumptionTracker)
require.NoError(t, o.FinishedReading(ctx))
o.Close()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should we assert that there are zero bytes in use after the operator is closed?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants