Skip to content

Zstd: append values in bulk and harden the frame metadata reads - #9099

Open
robert3005 wants to merge 1 commit into
rk/dict-gather-into-builderfrom
rk/zstd-append-to-builder
Open

Zstd: append values in bulk and harden the frame metadata reads#9099
robert3005 wants to merge 1 commit into
rk/dict-gather-into-builderfrom
rk/zstd-append-to-builder

Conversation

@robert3005

@robert3005 robert3005 commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Write zstd values directly into the builder without additional copy

`append_to_builder` walked the decompressed frames one value at a time,
appending each through a single-value call and interleaving null runs by hand.
It now derives the value byte range from the slice's own metadata and hands the
whole region to `append_value_slices`, which sizes the offsets, byte storage and
validity once — one offset store plus one `memcpy` per value.

Adds a `VarBinViewBuilder` path as well: the frames already hold the values
contiguously, so the views can reference them in place instead of going through
the canonical array and rewriting every view a second time to rebase its buffer
index. `reconstruct_views` therefore takes the buffer index the views should
start at.

Frame metadata comes straight off disk, so the arithmetic it drives is now
checked and surfaced as errors rather than panics or wrapped lengths: value
counts, frame sizes, length prefixes and the offsets they walk to. The missing
`n_values` fallback no longer reads a byte count as a value count for
variable-width values, where that mis-attributes values to frames — it is
accepted only for the single-frame case that is still recoverable. Decompression
also writes through `WriteBuf` into uninitialized spare capacity rather than a
`&mut [u8]` over memory nothing has written yet.

Signed-off-by: Robert Kruszewski <robert@spiraldb.com>
row = valid_index + 1;
// Null rows carry an empty view, so scatter the stored values into their rows.
let mut views = BufferMut::<BinaryView>::zeroed(slice.n_rows);
for (view, index) in valid_views.into_iter().zip_eq(valid_indices) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should use for_each_valid_index if possible

Comment on lines 293 to 298
array
.array()
.clone()
.execute::<Canonical>(ctx)?
.into_array()
.append_to_builder(builder, ctx)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this shouldn't be necessary

@robert3005 robert3005 added the changelog/chore A trivial change label Jul 31, 2026
@robert3005
robert3005 marked this pull request as ready for review July 31, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/chore A trivial change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant