Skip to content

perf(packstream): reuse a per-thread scratch buffer in pack#92

Open
freeeve wants to merge 1 commit into
neo4j:6.xfrom
freeeve:perf/packstream-pack-buffer-reuse
Open

perf(packstream): reuse a per-thread scratch buffer in pack#92
freeeve wants to merge 1 commit into
neo4j:6.xfrom
freeeve:perf/packstream-pack-buffer-reuse

Conversation

@freeeve

@freeeve freeeve commented Jun 26, 2026

Copy link
Copy Markdown

pack() allocated and grew a fresh Vec on every call, so each invocation incurred buffer (re)allocations that scale with the encoded size -- the common record/parameter packing path paid 2 to 10 Rust allocations per call.

Hold the encode buffer in a thread-local and reuse it across calls: take it on entry, hand its contents to PyBytes, and clear-and-return it on the way out. After warmup this is 0 Rust allocations per pack operation. Buffers above 64 KiB are dropped instead of pooled so one oversized message cannot pin a large allocation for the life of a thread, and the buffer is parked in a Cell<Option<_>> so a nested pack from a Python dehydration hook safely takes a fresh buffer rather than aliasing.

The throughput my local benchmarks saw from this change was up to ~20% write throughput improvement, with smaller records in the higher end of improvements and bigger records (unwind style bulk) in the lower end.

pack() allocated and grew a fresh Vec on every call, so each invocation
incurred buffer (re)allocations that scale with the encoded size -- the
common record/parameter packing path paid 2 to 10 Rust allocations per
call.

Hold the encode buffer in a thread-local and reuse it across calls: take
it on entry, hand its contents to PyBytes, and clear-and-return it on the
way out. After warmup this is 0 Rust allocations per pack operation.
Buffers above 64 KiB are dropped instead of pooled so one oversized
message cannot pin a large allocation for the life of a thread, and the
buffer is parked in a Cell<Option<_>> so a nested pack from a Python
dehydration hook safely takes a fresh buffer rather than aliasing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant