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

   ## Which issue does this PR close?
   
   - Closes #27083.
   
   ## Rationale for this change
   
   `RecursiveQueryExec` reserves `get_array_memory_size()` for every batch it 
keeps for the next
   iteration. When the recursive term is a hash join over `Utf8View` columns, 
every output batch
   references the build side's string buffers, so the same buffers get reserved 
once per batch. A
   recursive CTE over Parquet string keys can then fail with a pool many times 
larger than the memory
   it actually uses. The issue has a repro.
   
   ## What changes are included in this PR?
   
   `RecursiveQueryStream` now keeps a `RecordBatchMemoryCounter`, like the hash 
join, asof join and
   symmetric hash join do for their buffered batches. `push_batch` reserves 
only the buffers and array
   objects it hasn't seen yet (`count_batch_with_array_overhead`), and the 
counter starts over when the
   batches move to the work table for the next iteration.
   
   This doesn't make the accounting exact. A buffer can still be counted by 
more than one reservation:
   by the work table and by the next iteration when the recursive term passes 
work-table columns
   through, or by `RecursiveQueryExec` and the hash join that produced it. So 
it's counted once per
   reservation that holds it, instead of once per batch.
   
   ## What is the testing strategy for this PR?
   
   - `recursive_query_reserves_shared_buffers_once_per_iteration`: batches that 
share string buffers
     go through two iterations. The peak reservation has to be at least twice 
the string data (the
     work table and the next iteration both hold it) and below the old 
per-batch sum. It fails with
     the old accounting and without the counter reset.
   - `recursive_query_reserves_array_objects`: `NullArray` batches have no 
buffers, but their array
     objects still have to be reserved.
   - A `cte.slt` case: a recursive walk over Parquet string keys with a 
`CollectLeft` join and a 50 MB
     limit. Without the fix it fails asking for 76.4 MB with nothing reserved 
yet, for about 2.4 MB of
     string data.
   
   ## Are there any user-facing changes?
   
   No API changes. Recursive queries whose buffered batches share buffers need 
much less of the memory
   pool.
   
   ## AI disclosure
   
   I found this while comparing query engines on a benchmark of mine (a 
recursive span-tree query
   failed under a 64 GB memory limit, where DuckDB ran it in 1 GB). Claude Code 
helped write the fix,
   the tests and this description, and Codex did a review pass. I reviewed the 
code and verified it
   myself: the tests above, with and without the fix.
   


-- 
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