jayzhan211 opened a new pull request, #26728:
URL: https://github.com/apache/datafusion/pull/26728

   ## Which issue does this PR close?
   
   - Part of #25650.
   
   ## Rationale for this change
   
   DataFusion limits only the memory that operators reserve in the 
`MemoryPool`. When an operator holds memory without reserving it, the pool 
thinks there is room, nothing spills, and the process can run out of memory 
even with a memory limit set. No test catches this today: 
`memory_limit_validation` compares RSS with hand-picked bounds for sort and two 
joins, and the drift logging in sqllogictest (#25651) never fails a test.
   
   Not all unreserved memory is a bug. The `MemoryPool` docs let batches that 
are passing between operators go unreserved, which is why #22626, which 
compared allocations with reservations directly, was reverted (#22723). What 
the docs do require is that memory which grows with the input is reserved.
   
   This PR tests that rule. `memory_limit_validation` already runs every query 
twice, on 10% of the data and on all of it. Batches in flight are the same size 
in both runs. So if unreserved memory (bytes allocated minus bytes reserved) 
grows between the two runs, some operator is holding memory in proportion to 
its input without reserving it.
   
   ## What changes are included in this PR?
   
   This PR builds on #26694, which gives `memory_limit_validation` its own test 
binary, so the counting allocator below affects only these tests. The first two 
commits are from #26694; please review the last two.
   
   **1. Share sqllogictest's counting allocator.** It moves from 
`datafusion-sqllogictest` to `test-utils` unchanged, so both suites use one 
copy. sqllogictest behaves as before: the runner now passes the allocated-bytes 
function to `enable_memory_drift_logging`, and `datafusion-sqllogictest` no 
longer exports `CountingAllocator` and `flush_thread_allocations`. The 
allocator keeps counting per thread, because one shared counter made a full 
sqllogictest run about 40% slower on a 12-core laptop.
   
   **2. The check.** Every case now also fails if unreserved memory, at its 
peak, grows by 16 MB or more from the 10% run to the full run. The existing RSS 
bounds stay. Queries are drained batch by batch instead of collected, so the 
test no longer counts its own copy of the output.
   
   New cases run on 10M rows with an integer column `v` and a short string 
column `s`. They use 4 threads, because some of these problems only show up 
when inputs run ahead on other threads.
   
   | Query | Growth of unreserved memory on `main` | Status |
   |---|---|---|
   | `ORDER BY s DESC LIMIT 10` | < 1 MB | passes |
   | `GROUP BY v % 10` | < 1 MB | passes |
   | hash join, `Partitioned` and `CollectLeft` | < 1 MB | passes |
   | `ORDER BY s DESC` | 150–300 MB | ignored, #26411 |
   | `median(v)` | 120–140 MB | ignored, #26705 |
   | `array_agg(s) ... GROUP BY v % 10` | 450–590 MB | ignored, #26705 |
   | the same on one partition | ~380 MB | ignored, #26701 |
   | `SELECT DISTINCT s` | ~320 MB | ignored, #25606 |
   | `sum(v) OVER ()` | 205–230 MB | ignored, #26707 |
   
   The existing sort, sort-merge join and nested loop join cases pass the new 
check, with growth of 3 MB or less.
   
   When one of these issues is fixed, removing its `#[ignore]` turns the case 
into a regression test. A failure looks like this:
   
   ```
   Unreserved memory grew with the input by 120.2 MB, more than 16.0 MB. Memory 
proportional to the input must be reserved, see the `MemoryPool` docs
   ```
   
   ## What is the testing strategy for this PR?
   
   - `cargo test --profile ci -p datafusion --test memory_limit_validation 
--features extended_tests`: 35 passed, 7 ignored.
   - Each ignored case fails on the new check when run on its own, and its RSS 
stays within its bound. To run one:
     ```
     DATAFUSION_TEST_MEM_LIMIT_VALIDATION=1 cargo test --profile ci -p 
datafusion --test memory_limit_validation --features extended_tests -- 
aggregate_mem_validation::median --exact --include-ignored --nocapture
     ```
   - A full sqllogictest run passes and still prints its peak drift line.
   - `cargo publish --workspace --dry-run` passes with the new path-only 
dev-dependency on `test-utils`, as it does for `datafusion`.
   
   ## Are there any user-facing changes?
   
   No, these are test changes. `datafusion-sqllogictest` no longer exports 
`CountingAllocator` and `flush_thread_allocations`, which were added after the 
last release.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to