Conversation
Merging this PR will regress 2 benchmarks
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ❌ | Simulation | decompress[u64, (4000, 1024)] |
71.2 µs | 86.6 µs | -17.82% |
| ❌ | WallTime | mul_u32_nonnull_avx512 |
5.6 µs | 6.3 µs | -11% |
| ⚡ | WallTime | dbp_assemble_kernel_avx512[(I256, 8192)] |
20.3 µs | 13 µs | +56.23% |
| ⚡ | WallTime | dbp_assemble_kernel_narrow_msp_avx512[(I256, 8192)] |
17 µs | 14.4 µs | +18.44% |
| ⚡ | WallTime | mul_i32_nonnull_avx512 |
7.9 µs | 7.1 µs | +11.17% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing mk/compressor-serialized-ids (29fe244) with mk/dbp-v2-feature (35adc87)
Footnotes
-
176 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
-
1 benchmark was run, but is now archived. If it was deleted in another branch, consider rebasing to remove it from the report. Instead if it was added back, click here to restore it. ↩
85990c2 to
a49c384
Compare
| .with_btrblocks_builder( | ||
| BtrBlocksCompressorBuilder::default() | ||
| .retain_allowed_encodings(&allowed_array_encodings), | ||
| .retain_allowed_encodings(&allowed_array_encodings) |
There was a problem hiding this comment.
I think this has to be serialised ids
There was a problem hiding this comment.
I think we should somehow unify these 2 functions
There was a problem hiding this comment.
I guess we can enable a scheme if at least one of associated serialized ids is enabled?
There was a problem hiding this comment.
Ah actually I think this needs to be separate since there's a diff bw what ids MUST be allowed for a scheme to proc (all) vs what is optional (at least one).
FSST for example requires VarBin and FSST to be enabled. DBP requires at least one of v1 or v2.
|
Do you have an example of this being used? |
f5b732f to
c27a6d6
Compare
| fn default() -> Self { | ||
| Self { | ||
| schemes: ALL_SCHEMES.to_vec(), | ||
| allowed_serialized_ids: None, |
There was a problem hiding this comment.
All allowed (e.g. editions not enforced)
| #[derive(Debug, Clone)] | ||
| pub struct BtrBlocksCompressorBuilder { | ||
| schemes: Vec<&'static dyn Scheme>, | ||
| allowed_serialized_ids: Option<HashSet<ArrayId>>, |
There was a problem hiding this comment.
Make this none optional
94ab744 to
8129237
Compare
8129237 to
b28f0b6
Compare
b28f0b6 to
7accd56
Compare
03a13f8 to
72f2396
Compare
ece1fe2 to
bf0a90f
Compare
72f2396 to
d846ec7
Compare
bf0a90f to
d228008
Compare
d846ec7 to
46de82a
Compare
d228008 to
61b5492
Compare
61b5492 to
f5a94a0
Compare
bbd1a50 to
ac1f5a0
Compare
ac1f5a0 to
c787611
Compare
) ## Summary Compression schemes are filtered against the IDs a writer may emit. Today that filter mixes two ID spaces. Schemes declare their in-memory encoding ID, while most callers pass the serialized IDs from their enabled editions. The two only line up because every encoding currently uses the same string for both. `DecimalByteParts` stops doing that in #9834. Its in-memory ID becomes `vortex.decimal_byte_parts.v2` while the frozen wire ID stays `vortex.decimal_byte_parts`. With the current filter, every caller that passes edition IDs would silently drop the decimal scheme and write decimals canonical. This PR makes the contract explicit. Schemes declare the serialized IDs they write, and every caller filters with serialized IDs. ## Changes - The file writer no longer maps permitted serialized IDs through the registry to plugin in-memory IDs before filtering schemes. `new_array_context` returns only the array context, which is seeded with exactly the permitted IDs, and the writer reads them back with `to_ids` into a named set for the compressor builder. This matches the Python, TUI, CUDA, bench, and golden-test callers, which already pass serialized IDs. ## Behavior No scheme changes behavior. In-memory and wire IDs coincide for every scheme on develop, so the same schemes are retained from the same inputs and no snapshot changes. ## Follow-ups - #9834 declares `vortex.decimal_byte_parts` from the decimal scheme on top of this. - #9770 builds on this with a permitted-ID snapshot in `CompressorContext`, so a scheme can choose a wire format when it compresses. If the method names should say serialized IDs, renaming `produced_encodings` and `retain_allowed_encodings` together belongs there. --------- Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Signed-off-by: "Matt Katz" <mhkatz97@gmail.com> Signed-off-by: Matt Katz <mhkatz97@gmail.com>
`DecimalBytePartsArray` previously stored the entire unscaled decimal value in one signed integer child, limiting it to values that fit in 64 bits. It now supports wide decimals by representing each value as integer parts that can be compressed independently, while preserving the decimal's logical precision, scale, and nullability. The array has a signed most significant part (MSP) and up to three unsigned 64-bit lower parts, ordered most significant first. Splitting canonical decimal storage produces: | Decimal storage | Children | | --- | --- | | `i8` / `i16` / `i32` / `i64` | Signed MSP only; shares the original value buffer | | `i128` | `i64` MSP + one `u64` lower part | | `i256` | `i64` MSP + three `u64` lower parts | Only the MSP carries validity. Every lower part must be a non-nullable `u64` array with the same length, and splitting wide decimals zeroes the parts at null positions. All children remain `ArrayRef`s, so their individual encodings are independent of the decimal representation. `execute::<DecimalArray>` reassembles a `DecimalArray` from the MSP and lower parts children. `take` with nullable indices is not yet supported by the DecimalByteParts kernel for arrays with lower parts; it falls back to canonical execution. Taking each part directly would make the lower parts nullable, violating the representation's invariant. The frozen serializer also continues to reject arrays with lower parts. This PR also refines the splitting and assembly modules. * Assembly takes `ArrayRef`s instead of `PrimitiveArray`s so that in the future, we can add special fast paths for constant arrays * Assembly casts lower parts to `u64`s, allowing for assembly of narrowed lower parts. * Assembly loop is optimized such that it vectorizes for `i256` assembly on local runs. --------- Signed-off-by: Matt Katz <mhkatz97@gmail.com>
…mat (#9810) Add serialization for `DecimalBytePartsArray` with lower parts while preserving the frozen v1 file format. `DecimalBytePartsPlugin` owns both formats and selects the serialized ID from the array's layout: | Array layout | Serialized ID | | --- | --- | | Signed most significant part (MSP) only | `vortex.decimal_byte_parts` | | Signed MSP plus one to three unsigned lower parts | `vortex.decimal_byte_parts_v2` | Both formats deserialize into the same in-memory array representation. Each lower part represents a 64-bit window, but its storage dtype may be narrowed to `u8`, `u16`, or `u32` when its values fit. - Record the MSP's physical integer type, lower-part count, and each lower part's physical integer type in metadata. Deserialization validates these types and restores each child with its recorded dtype. - Keep the frozen format restricted to zero lower parts and require at least one for v2. Frozen metadata remains byte-identical. - Make DBP's VTable `serialize` and `deserialize` methods return errors directing callers to `DecimalBytePartsPlugin`. Keep DBP metadata and serde helpers in `plugin.rs` so the dedicated plugin owns both formats. - Add a separate v2 compatibility fixture covering positive and negative wide `i128` values and nullable `i256` values. The frozen fixture is unchanged. **Breaking:** directly registering `DecimalByteParts`, or calling its VTable serde methods, now errors for both serialization and deserialization, including the frozen v1 format. Replace: ```rust session.arrays().register(DecimalByteParts); ``` with: ```rust session.arrays().register(DecimalBytePartsPlugin); ``` `vortex_decimal_byte_parts::initialize(&session)` already registers the plugin. Existing v1 files remain readable through it; no file migration is required. --------- Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Signed-off-by: Matt Katz <mhkatz97@gmail.com>
c787611 to
c5ea5c5
Compare
Signed-off-by: Matt Katz <mhkatz97@gmail.com>
CascadingCompressor carries the snapshot of serialized IDs the writer may emit, filled by the file writer from the enabled editions through BtrBlocksCompressorBuilder::allow_serialized_ids. A scheme whose encoding has more than one wire format picks its compression mode from it with allows_serialized_id, the newest permitted one; without a restriction every ID is allowed. No scheme consults the set yet. This is the mechanism docs/specs/editions.md describes under compression with replacement encodings (#9779). Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Scheme::produced_encodings now names the serialized IDs a scheme may write its output under, oldest first. BtrBlocksCompressorBuilder::allow_serialized_ids replaces retain_allowed_encodings: it keeps a scheme when at least one of those IDs is permitted and hands the set to the compressor, so the writer makes one call from the serialized IDs its editions permit instead of mapping them back to in-memory encodings, which could not tell two wire formats of one encoding apart. Signed-off-by: Matt Katz <mhkatz97@gmail.com>
The compressor seeds each root CompressorContext with its permitted serialized IDs and every descent inherits them, so a scheme asks compress_ctx.allows_serialized_id both while estimating and while compressing and picks the same mode in both. The per-compressor accessor goes; allowed_serialized_ids remains for inspection. Signed-off-by: Matt Katz <mhkatz97@gmail.com>
…ed ids Signed-off-by: Matt Katz <mhkatz97@gmail.com>
Restore produced_encodings in feature-gated schemes and fix stale trait links. Document scheme ID resolution for Clippy. Signed-off-by: Matt Katz <mhkatz97@gmail.com>
… unstable_encodings gate Signed-off-by: Matt Katz <mhkatz97@gmail.com>
f5a94a0 to
29fe244
Compare
35adc87 to
026bb26
Compare
Filtering compression schemes by in-memory encoding cannot distinguish multiple wire formats of the same encoding. In order to support encodings like
DecimalBytePartswith multiple wire formats, the compressor must know which wire formats are enabled and must be able to select the appropriate schemes.The writer now passes its permitted serialized IDs to compressor configuration, which selects the newest compatible version of each scheme before matching, generating statistics, estimating, or compressing.
Scheme::produced_encodingsdeclares the serialized IDs that a scheme directly introduces. Every declared ID must be allowed.Alternative versions are represented by
Scheme::predecessor: register only the newest version, fall back through its predecessor chain when its IDs are unavailable, and remove the chain when no version is eligible. Historical versions do not compete with their replacements during compression.BtrBlocksCompressorBuilder::allow_serialized_idsreplacesretain_allowed_encodingsand applies restrictions at build time, including to schemes added after the restriction. Both it andCascadingCompressor::with_allowed_serialized_idsintersect repeated restrictions. Registration order is preserved, and scheme IDs in a predecessor chain resolve to the selected version for exclusions andhas_schemechecks. Cycles and overlapping chains are rejected.The default file writer uses the serialized IDs of its enabled editions, or every registered serialized ID when edition enforcement is disabled. Custom write strategies retain their own configuration. Serialization still chooses the oldest wire form the resulting array fits and validates it against the writer's allowed IDs.
Existing production schemes have no predecessors, so this prepares version selection for consumers such as bitpacking (#9754) and decimal byte parts (#9759). The related edition specification is discussed in #9779.
Tests cover version selection before estimation, required output IDs, repeated restrictions, schemes added after restrictions, registration order, exclusions across versions, invalid predecessor chains, and writer round trips with unavailable encodings.