Skip to content

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

Merged
robert3005 merged 5 commits into
developfrom
rk/zstd-append-to-builder
Aug 5, 2026
Merged

Zstd: append values in bulk and harden the frame metadata reads#9099
robert3005 merged 5 commits into
developfrom
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

Comment thread encodings/zstd/src/array.rs Outdated
Comment thread encodings/zstd/src/array.rs Outdated
@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
@robert3005
robert3005 force-pushed the rk/zstd-append-to-builder branch from 31c8739 to 1c85ef5 Compare July 31, 2026 18:11
@codspeed-hq

codspeed-hq Bot commented Jul 31, 2026

Copy link
Copy Markdown

Merging this PR will regress 1 benchmark

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

⚡ 1 improved benchmark
❌ 1 regressed benchmark
✅ 1871 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
WallTime cuda/bitpacked_u8/unpack/3bw[100M] 299.4 µs 349.5 µs -14.35%
Simulation fsl_large 253.2 µs 211.2 µs +19.92%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing rk/zstd-append-to-builder (3d42169) with develop (3d0c124)1

Open in CodSpeed

Footnotes

  1. No successful run was found on develop (69661e0) during the generation of this report, so 3d0c124 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@robert3005
robert3005 force-pushed the rk/zstd-append-to-builder branch 2 times, most recently from 3f1ff67 to 7c295ab Compare August 4, 2026 23:14
@robert3005
robert3005 force-pushed the rk/zstd-append-to-builder branch from 7c295ab to ef7a7c1 Compare August 4, 2026 23:15
Comment on lines +798 to +802
let to = if end == self.n_buffered_values {
buffer.len()
} else {
zstd_value_offset(buffer, from, end - start)?
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this optimisation hides a bug. Both end and self.n_buffered_values are coming from metadata or validity, so we are returning buffer.len() without looking at the lengths stored in the buffer. If the zstd buffer is corrupt and ends with a length for example, we would silently treat it as a final empty string instead of raising.

So something like 3cat1 in the zstd buffer would add ["cat", ""] to the builder instead of raising

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.

oof, I think you're right about this

@robert3005
robert3005 force-pushed the rk/zstd-append-to-builder branch from ef7a7c1 to cf0104e Compare August 5, 2026 13:55
@robert3005
robert3005 force-pushed the rk/zstd-append-to-builder branch from cf0104e to bb07315 Compare August 5, 2026 13:56
Base automatically changed from rk/dict-gather-into-builder to develop August 5, 2026 15:02
@robert3005
robert3005 force-pushed the rk/zstd-append-to-builder branch from 1c7229d to bf847fd Compare August 5, 2026 15:02
`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>
Signed-off-by: Robert Kruszewski <github@robertk.io>
Signed-off-by: Robert Kruszewski <github@robertk.io>
Signed-off-by: Robert Kruszewski <github@robertk.io>
@robert3005
robert3005 force-pushed the rk/zstd-append-to-builder branch from bf847fd to 62fd68f Compare August 5, 2026 16:12
I, Robert Kruszewski <github@robertk.io>, hereby add my Signed-off-by to this commit: 9fdbe75

Signed-off-by: Robert Kruszewski <github@robertk.io>
@robert3005
robert3005 merged commit 7ad0d9d into develop Aug 5, 2026
80 of 82 checks passed
@robert3005
robert3005 deleted the rk/zstd-append-to-builder branch August 5, 2026 16:45
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.

2 participants