Repository navigation
[RFC]feat(pool): add with_pool() to Arrow builders for real-time memory tracking - #1
Draft
wirybeaver wants to merge 1 commit into
Draft
wirybeaver wants to merge 1 commit into
wirybeaver wants to merge 1 commit into
Conversation
…acking Adds pool-backed memory tracking to PrimitiveBuilder, GenericByteBuilder, and GenericListBuilder so every buffer growth is accounted for in a MemoryPool as it happens, rather than post-hoc via buffer.claim(pool). Key additions: - TrackedVec<T>: Vec<T> wrapper that syncs a MemoryReservation on every capacity change; transfers reservation into MutableBuffer on finish() - MemoryAllocationError + try_reserve()/try_resize() on pool traits for fallible allocation with default infallible impls (backward-compatible) - MutableBuffer::with_pool() and set_reservation() to support reservation transfer across crate boundaries - BooleanBufferBuilder::with_pool() and NullBufferBuilder::with_pool() - WithPool trait for generic pool propagation through GenericListBuilder - try_append_value() on PrimitiveBuilder and GenericByteBuilder for fallible appends that respect pool limits All new APIs are gated under #[cfg(feature = "pool")]; the non-pool code path is unchanged and compiles without overhead.
wirybeaver
force-pushed
the
xuanyili/withpool
branch
from
June 11, 2026 01:23
3e343d6 to
13d8c76
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Arrow builders (
PrimitiveBuilder,GenericByteBuilder,GenericListBuilder) allocate internally viaVec<T>, which is invisible toMemoryPool. Today the only way to associate a pool with an array is:This has two problems:
Vec::push.This PR adds
with_pool()to the key builders so that every internalVecgrowth is tracked (and optionally rejected) through aMemoryPoolin real time.Design
TrackedVec<T>— zero-overheadVecwrapperA new
pub(crate) struct TrackedVec<T>wrapsVec<T>and holds an optionalBox<dyn MemoryReservation>. On every capacity-changing operation it callsreservation.resize(new_bytes). When no pool is attached it is a plainVecwith no overhead.The reservation transfers through
MutableBuffer::set_reservation()(new) →MutableBuffer::into_buffer()(existing) →Bytes::reservation→ freed onBufferdrop.Fallible allocation
MemoryPool::try_reserve()andMemoryReservation::try_resize()are added with default infallible implementations, so existing pool implementations don't need to change. Limit-enforcing pools (like DataFusion'sGreedyMemoryPool) override these to returnErrwhen capacity is exceeded.A new
MemoryAllocationErrortype is defined inarrow-bufferto avoid adding anarrow-schemadependency there.API
PrimitiveBuilderGenericByteBuilder/StringBuilderGenericListBuilderwith child propagationDataFusion Integration Example
DataFusion's
GreedyMemoryPoolenforces hard limits. Here is how it would plug into Arrow builders to get real-time enforcement during sort/aggregate spilling:Files Changed
arrow-buffer/src/pool.rsMemoryAllocationError;try_reserve()onMemoryPool;try_resize()onMemoryReservationarrow-buffer/src/buffer/mutable.rswith_pool(),set_reservation()arrow-buffer/src/builder/boolean.rsBooleanBufferBuilder::with_pool()arrow-buffer/src/builder/null.rsNullBufferBuilder::with_pool()arrow-array/src/builder/tracked_vec.rsTrackedVec<T>arrow-array/src/builder/mod.rsWithPooltraitarrow-array/src/builder/primitive_builder.rswith_pool(),try_append_value()arrow-array/src/builder/generic_bytes_builder.rswith_pool(),try_append_value()arrow-array/src/builder/generic_list_builder.rswith_pool()with child propagationAll new APIs are gated under
#[cfg(feature = "pool")]; the default non-pool build is completely unchanged.