You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Epic] Replace OffsetBufferBuilder / BufferBuilder usage with Vec, when possible #10245
Is your feature request related to a problem or challenge?
As @Jefffrey has observed in #10229 (comment), switching from OffsetBufferBuilder / BufferBuilder to use Vec<..> often results in a non trivial speedup.
This is likely because the Rust language has a highly optimized Vec implementation
@mzabaluev@Anakin100100 are either of you currently working on this? Im working on a few other issues so im happy to untake, otherwise Ill push up a PR for this tomorrow
I'd like to take the remaining BufferBuilder usage in arrow-json's MapArrayDecoder and replace it with Vec, following the existing ListArrayDecoder approach.
I'd like to take the remaining BufferBuilder usages in arrow-string and replace them with Vec, split into focused PRs for concat_elements.rs and substring.rs.
Once those two PRs are merged (or otherwise resolved) we can close this epic 🎉
I looked into the remaining nullable try_binary callsite referenced in #10518.
The local patch only replaces BufferBuilder with vec![O::Native::default(); len] and converts the result with .into().
A focused benchmark on base commit showed repeatable regressions in some cases. It calls try_binary directly with checked addition, fixed seeded inputs, and nulls on the left input only. Input generation is outside the timed operation.
Environment: Intel i7-13700H, Linux x86_64, Rust 1.99.1, glibc 2.39, default release settings and system allocator. Both versions were pinned to the same CPU core, with the powersave governor unchanged. Each case was measured six times per version, alternating execution order and shuffling case order between rounds, using 100 Criterion samples and a 2-second measurement target per run.
Selected results below are average execution times across the six runs:
For Decimal256 with 50% nulls, the corresponding changes at those three batch sizes were +10.3%, +6.5%, and +0.8%. Larger Int32 cases were generally close to unchanged.
The Decimal256 regressions at 8,192 and 65,536 rows occurred in all six comparisons. At one million rows, the differences were much smaller. One unchanged no-null Decimal256 control also showed an approximately 10% swing in one comparison, so I would treat small differences cautiously.
These results are limited to this machine, toolchain, and workload. The nullable benchmark mentioned in #10518 was not included in that PR, so I cannot compare the two setups directly or explain its reported gains conclusively.
Would it make sense to keep BufferBuilder at this callsite for now, pending results from other environments or a replacement with more consistent benefits? I have retained the focused benchmark and raw results locally and can share them for reproduction.
Would it make sense to keep BufferBuilder at this callsite for now, pending results from other environments or a replacement with more consistent benefits? I have retained the focused benchmark and raw results locally and can share them for reproduction.
Activity
comphead commentedon Jun 30, 2026
Thanks @alamb adding apache/datafusion#23195 as the reference where
VecreplacesOffsetBufferBuilderRich-T-kid commentedon Jul 15, 2026
take
Rich-T-kid commentedon Aug 4, 2026
@mzabaluev @Anakin100100 are either of you currently working on this? Im working on a few other issues so im happy to untake, otherwise Ill push up a PR for this tomorrow
mzabaluev commentedon Aug 4, 2026
@Rich-T-kid I don't have anything pending on this, working on other things now.
cakeni commentedon Aug 11, 2026
I'd like to take the remaining BufferBuilder usage in arrow-json's MapArrayDecoder and replace it with Vec, following the existing ListArrayDecoder approach.
cakeni commentedon Aug 11, 2026
I'd like to take the remaining BufferBuilder usage in arrow-ord/src/sort.rs and replace it with Vec.
cakeni commentedon Aug 11, 2026
I'd like to take the two BufferBuilder usages in arrow-select/src/take.rs's run-end encoded take path and replace them with Vec.
cakeni commentedon Aug 11, 2026
I'd like to take the remaining BufferBuilder usages in arrow-string and replace them with Vec, split into focused PRs for concat_elements.rs and substring.rs.
Rich-T-kid commentedon Aug 11, 2026
nice, i took a look at the existing PR's
Replace substring BufferBuilders with Vec (#10634)
Replace BufferBuilder with Vec in MapArrayDecoder (#10629)
Replace BufferBuilder with Vec in sort_run_downcasted (#10630)
69 remaining items
Replace BufferBuilder with Vec in UnionBuilder's FieldDataValues (apa…
Replace OffsetBufferBuilder with Vec in scalar byte-array zip (apache…
Replace substring BufferBuilders with Vec (apache#10634)
Replace BufferBuilder with Vec in MapArrayDecoder (apache#10629)
Replace BufferBuilder with Vec in sort_run_downcasted (apache#10630)
Replace take_run BufferBuilders with Vec (apache#10631)
Replace concat_elements_bytes BufferBuilders with Vec (apache#10632)
Replace concat_elements_utf8_many BufferBuilders with Vec (apache#10633)
Replace BufferBuilder with Vec in fixed-size binary take (apache#10773)
Use Vec for primitive array unary operations (apache#10783)
Replace BufferBuilder with Vec in decode_binary (apache#10851)
Replace BufferBuilder with Vec in cast_byte_container (apache#10867)
WaterWhisperer commentedon Nov 7, 2026
I looked into the remaining nullable
try_binarycallsite referenced in #10518.The local patch only replaces
BufferBuilderwithvec![O::Native::default(); len]and converts the result with.into().A focused benchmark on base commit showed repeatable regressions in some cases. It calls
try_binarydirectly with checked addition, fixed seeded inputs, and nulls on the left input only. Input generation is outside the timed operation.Environment: Intel i7-13700H, Linux x86_64, Rust 1.99.1, glibc 2.39, default release settings and system allocator. Both versions were pinned to the same CPU core, with the powersave governor unchanged. Each case was measured six times per version, alternating execution order and shuffling case order between rounds, using 100 Criterion samples and a 2-second measurement target per run.
Selected results below are average execution times across the six runs:
For Decimal256 with 50% nulls, the corresponding changes at those three batch sizes were +10.3%, +6.5%, and +0.8%. Larger Int32 cases were generally close to unchanged.
The Decimal256 regressions at 8,192 and 65,536 rows occurred in all six comparisons. At one million rows, the differences were much smaller. One unchanged no-null Decimal256 control also showed an approximately 10% swing in one comparison, so I would treat small differences cautiously.
These results are limited to this machine, toolchain, and workload. The nullable benchmark mentioned in #10518 was not included in that PR, so I cannot compare the two setups directly or explain its reported gains conclusively.
Would it make sense to keep
BufferBuilderat this callsite for now, pending results from other environments or a replacement with more consistent benefits? I have retained the focused benchmark and raw results locally and can share them for reproduction.alamb commentedon Nov 7, 2026
Yes I agree -- thank you @WaterWhisperer
Let's call this done for now