Skip to content

Untracked memory in FilterExec, RepartitionExec, HashJoinExec and AsyncFuncExec and more due to LimitedBatchCoalescer and arrow BatchCoalescer usage #23385

Open

Description

@rluvaton

Describe the bug

According to the datafusion memory model, you need to reserve memory for things you hold on, LimitedBatchCoalescer which hold on the batches to coalesce and hold on batches that not yet polled does not reserve any memory

LimitedBatchCoalescer is used by:

FilterExec:

batch_coalescer: LimitedBatchCoalescer::new(
self.schema(),
self.batch_size,
self.fetch,
),

RepartitionExec:

SharedCoalescer::new(
input.schema(),
context.session_config().batch_size(),
num_input_partitions,
)

struct SharedCoalescer {
inner: Arc<Mutex<LimitedBatchCoalescer>>,
active_senders: Arc<AtomicUsize>,
}

even though RepartitionExec have some memory reservation, it does not count the LimitedBatchCoalescer memory

HashJoinExec:

// Create output buffer with coalescing and optional fetch limit.
let output_buffer =
LimitedBatchCoalescer::new(Arc::clone(&schema), batch_size, fetch);

AsyncFuncExec

let coalesced_input_stream = CoalesceInputStream {
input_stream,
batch_coalescer: LimitedBatchCoalescer::new(
Arc::clone(&self.input.schema()),
config_options_ref.execution.batch_size.get(),
None,
),
};

and more that use arrow BatchCoalescer directly, since it does not expose a way to know which batches hold which result, you have no way to reserve and free memory for them

Like SortMergeJoin:

/// Output buffer. Currently used by filtering as it requires double buffering
/// to avoid small/empty batches. Non-filtered join outputs directly from `staging_output_record_batches.batches`
pub output: BatchCoalescer,

To Reproduce

Looking at the code you can see no reservation, so just create FilterExec for example and see no reservation being made

Expected behavior

everything that hold on memory should reserve for it

Additional context

Ideally CoalesceBatchStream should output small batches when unable to reach the batch size

Activity

  1. added theissue type on Jul 8, 2026
  2. buraksenn commented on Jul 10, 2026

    @buraksenn
    Contributor

    take

  3. rluvaton commented on Jul 14, 2026

    @rluvaton
    MemberAuthor

    I opened a PR in arrow-rs to add size function to the underlying BatchCoalescer so once it is merged and release we can use that here

  4. buraksenn commented on Jul 14, 2026

    @buraksenn
    Contributor

    I opened a PR in arrow-rs to add size function to the underlying BatchCoalescer so once it is merged and release we can use that here

    Thanks @rluvaton , I've explored implementation but was not sure because of this. I can implement these when its landed in arrow upstream as you've said or leave it to you if you prefer that way

  5. rluvaton commented on Jul 14, 2026

    @rluvaton
    MemberAuthor

    Yeah, I was going back and forth with this but decided to just expose memory size of BatchCoalescer in arrow, in any case we need to wait for a merge and release before we can continue here

  6. Rich-T-kid commented on Jul 15, 2026

    @Rich-T-kid
    Contributor

    tagging this issue with #22758 since its related

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions