Description:
In arrow-ipc/src/writer.rs, flush() is called unconditionally in:
write_body_buffers
write_continuation
Both functions are part of write_message, which is executed for every record batch and dictionary batch. As a result, each batch write triggers multiple flush() calls.
This places flush() directly in the hot path of IPC writing.
Problem:
flush() is not a cheap operation. For buffered writers (e.g., BufWriter), it:
- forces buffered data to be written immediately
- breaks write coalescing
- increases the number of write syscalls
- introduces additional overhead involving the OS/kernel
This leads to a flow like:
batch 1: write → flush
batch 2: write → flush
batch 3: write → flush
...
instead of allowing batches to be written continuously and flushed only at an explicit boundary:
batch 1: write
batch 2: write
batch 3: write
...
final boundary: flush
That difference is important: the current path forces flush work into every batch write, while the proposed change removes that cost from the per-message path and keeps flushing at the writer boundary where it belongs.
For workloads with many batches (e.g., streaming or high-partition data), the current behavior introduces unnecessary I/O overhead and reduces throughput.
Key point:
These flush() calls are not required for correctness:
-
IPC message boundaries are already explicitly defined
-
no durability guarantees are provided (no fsync/sync_all)
-
explicit flush control already exists via:
FileWriter::finish()
- public
flush() methods on both writers
Proposed change:
Benefit:
- eliminates unnecessary per-message flushes in the hot path
- reduces syscall and kernel overhead
- improves effective buffering and write coalescing without affecting correctness
Description:
In
arrow-ipc/src/writer.rs,flush()is called unconditionally in:write_body_bufferswrite_continuationBoth functions are part of
write_message, which is executed for every record batch and dictionary batch. As a result, each batch write triggers multipleflush()calls.This places
flush()directly in the hot path of IPC writing.Problem:
flush()is not a cheap operation. For buffered writers (e.g.,BufWriter), it:This leads to a flow like:
instead of allowing batches to be written continuously and flushed only at an explicit boundary:
That difference is important: the current path forces flush work into every batch write, while the proposed change removes that cost from the per-message path and keeps flushing at the writer boundary where it belongs.
For workloads with many batches (e.g., streaming or high-partition data), the current behavior introduces unnecessary I/O overhead and reduces throughput.
Key point:
These
flush()calls are not required for correctness:IPC message boundaries are already explicitly defined
no durability guarantees are provided (no
fsync/sync_all)explicit flush control already exists via:
FileWriter::finish()flush()methods on both writersProposed change:
Remove
flush()from:write_body_bufferswrite_continuationKeep flushing at appropriate boundaries:
FileWriter::finish()self.writer.flush()?toStreamWriter::finish()Benefit: