perf(parquet): splice buffered pages with write_all instead of io::copy (adapts #10052)#10353
perf(parquet): splice buffered pages with write_all instead of io::copy (adapts #10052)#10353adriangb wants to merge 2 commits into
write_all instead of io::copy (adapts #10052)#10353Conversation
Adapts the idea from apache#10052 to the PageStore splice path: drain each page blob from the store and write it straight to the output with a single write_all, instead of pumping every byte through std::io::copy's fixed 8 KiB buffer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sd8JjF3qQMkn7htofu8bF3
|
run benchmark arrow_writer |
|
run benchmark parquet_round_trip |
|
🤖 Arrow criterion benchmark running (GKE) | trigger CPU Details (lscpu)Comparing append-column-from-pages (f77bf2f) to ee30b61 (merge-base) diff File an issue against this benchmark runner |
|
🤖 Arrow criterion benchmark running (GKE) | trigger CPU Details (lscpu)Comparing append-column-from-pages (f77bf2f) to ee30b61 (merge-base) diff File an issue against this benchmark runner |
|
🤖 Arrow criterion benchmark completed (GKE) | trigger Instance: CPU Details (lscpu)Details
Resource Usagebase (merge-base)
branch
File an issue against this benchmark runner |
|
🤖 Arrow criterion benchmark completed (GKE) | trigger Instance: CPU Details (lscpu)Details
Resource Usagebase (merge-base)
branch
File an issue against this benchmark runner |
|
run benchmark arrow_writer |
|
🤖 Arrow criterion benchmark running (GKE) | trigger CPU Details (lscpu)Comparing append-column-from-pages (f77bf2f) to ee30b61 (merge-base) diff File an issue against this benchmark runner |
|
🤖 Arrow criterion benchmark completed (GKE) | trigger Instance: CPU Details (lscpu)Details
Resource Usagebase (merge-base)
branch
File an issue against this benchmark runner |
Its only caller is the arrow writer; without the feature the parquet_derive clippy job (-D warnings) flags it as dead code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sd8JjF3qQMkn7htofu8bF3
|
Thanks fore the quick review! I can't merge so I'll wait for you or Andrew to do it. |
Which issue does this PR close?
SerializedRowGroupWriter#10052 (by @alamb) to the currentPageStore-based writer. That PR predates Pluggable page spilling API for the Parquet ArrowWriter (PageStore) #10020 / [Parquet] route dictionary page through the PageStore #10142 and no longer applies cleanly; this PR carries its idea forward. Closes Avoid an extra copy inSerializedRowGroupWriter#10052's use case.Rationale for this change
When the
ArrowWriterflushes a row group, each column chunk's buffered pages are spliced into the output throughStreamingColumnChunkReader(aRead) driven bystd::io::copy. Every byte is copied twice — once intoio::copy's fixed 8 KiB buffer, then again intoTrackedWrite'sBufWriter— in ~len / 8 KiBwrite calls.The page blobs are already contiguous owned
Bytessitting in thePageStore; we can write each one straight to the sink with a singlewrite_all(large writes bypass theBufWriterbuffer entirely).#10052 did exactly this, but its
IntoIterator<Item = Bytes>signature can't express the fallible, one-page-at-a-time drain of a (possibly spilling)PageStore, and it assumed the pre-#10020Vec<Bytes>chunk representation.What changes are included in this PR?
StreamingColumnChunkReader(Readimpl) becomesStreamingColumnChunkPages, anIterator<Item = Result<Bytes>>thattake()s each page out of thePageStoreas it is consumed — preserving the one-page-in-memory bound for spilling backends.pub(crate) SerializedRowGroupWriter::append_column_from_pages, which writes each page blob with a singlewrite_all.begin_appended_column/finish_appended_column(same refactor as Avoid an extra copy inSerializedRowGroupWriter#10052), also used by the existingRead-based path that still backs the publicappend_column.Are these changes tested?
Covered by existing tests. Also verified that the output files are byte-for-byte identical to main for multi-row-group writes with int / string / dictionary columns under both default and small-page properties.
Local benchmark results (
arrow_writerbench, Apple Silicon), reproducing the wins from #10052's benchmark run without itslarge_string_non_nullregression:string_dictionary/defaultlist_primitive/defaultlarge_string_non_null/defaultAre there any user-facing changes?
No.
append_column_from_pagesis keptpub(crate)for now; it could be made public in a follow-up if theResult<Bytes>iterator contract is deemed a good public API (#10052 proposed a public variant).🤖 Generated with Claude Code
https://claude.ai/code/session_01Sd8JjF3qQMkn7htofu8bF3