fix: enforce fair memory limits across sibling reservations - #25172
Draft
sunchao wants to merge 1 commit into
Draft
fix: enforce fair memory limits across sibling reservations#25172sunchao wants to merge 1 commit into
sunchao wants to merge 1 commit into
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #25172 +/- ##
==========================================
+ Coverage 81.74% 81.92% +0.17%
==========================================
Files 1128 1132 +4
Lines 416782 421114 +4332
Branches 416782 421114 +4332
==========================================
+ Hits 340712 344989 +4277
+ Misses 55999 55792 -207
- Partials 20071 20333 +262 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Which issue does this PR close?
Fixes fair-pool admission for consumers with multiple reservations. Related to the merge-workspace accounting in #24740.
Rationale for this change
A spilling operator should have one memory allowance, regardless of how many buffers it uses. DataFusion represents that operator as a consumer, while each reservation accounts for some of its memory. Today,
FairSpillPoolchecks the reservation making an allocation request without counting its siblings. An operator with a 100 MiB allowance can hold 60 MiB in one reservation and 40 MiB in another, then obtain still more through an empty sibling. Splitting or transferring reservations can expose the same gap.A fair-share check also needs a separate limit on total pool usage. If one consumer fills a 100 MiB pool before another registers, the new consumer's 50 MiB share does not represent free memory. There is no room to admit its growth until existing reservations release space.
Closing these gaps affects aggregate spill replay. To finish an aggregation, DataFusion merges the sorted spill files and feeds the merged rows into an aggregate table. Those two components already share a consumer and run together. Once their reservations correctly count toward one allowance, letting the merge occupy all of it can leave the aggregate table unable to process the rows it receives. The accounting fix therefore needs to give replay room to work.
What changes are included in this PR?
The fair pool now admits growth against the consumer's combined reservations and the pool's remaining capacity. Reservation splitting, transfer, and release preserve that combined accounting, so creating another handle cannot create another allowance.
Aggregate replay uses an advisory consumer allowance to choose how many spill files to merge at once. In all four replay paths, it normally limits merge buffers to half that allowance, leaving room for the aggregate table. This is a planning budget: every allocation must still be accepted by the actual memory pool, whose available capacity can change while the query runs.
The half-share budget must also allow progress with very wide rows. For example, the smallest useful merge may need 60 MiB even though its preferred budget is 50 MiB. If its input rows cannot be split further, the merge may exceed that preference only when the actual pool grants the memory. That retry uses the smallest possible merge to leave room for the aggregate table. Checking an indivisible spill file avoids rewriting it unnecessarily, which matters when the existing files already fill the disk quota. If the actual memory cannot be obtained, execution reports a resource error and releases its resources.
What is the testing strategy for this PR?
PR CI at head
4a5cb8724is green, including extended tests, forced hash-collision tests, Linux and macOS tests, SQL logic suites, Clippy, and documentation checks. The added regressions cover sibling lifetimes, changing fair shares, all four aggregate replay paths, indivisible rows, full disk quota, and cleanup under permanent memory pressure.Local validation on upstream base
ac7b18de6passed 11,298 Rust tests and all 512 SQL logic files, plus Clippy and formatting. That older base retained its original dependency lockfile; the patch also applied cleanly to main1ec9ede5. No targeted performance benchmark was run, and this PR makes no performance claim.Are there any user-facing changes?
Allocations through
try_growcan now fail when a consumer's combined reservations exhaust its allowance or the pool is full. Infalliblegrowretains its existing contract.The additive
MemoryPool::memory_limit_forAPI exposes an advisory allowance for planning. It defaults toUnknown; transparent custom wrappers should forward their inner pool's answer so aggregate replay can use it. The spill-file backend and ownership APIs are unchanged.