Conversation
Resolve allowed and forbidden serialized IDs when building the compressor, select compatible Decimal modes, and compress wide decimal parts independently. Default to Decimal v2 while keeping the CUDA preset restricted to v1. Signed-off-by: "Matt Katz" <mhkatz97@gmail.com>
Replace produced_encodings with Scheme::configure and store owned AllowedSerializedIds in the BtrBlocks builder. Configure schemes in one pass, select decimal v2 whenever permitted, and preserve CUDA restrictions. Signed-off-by: "Matt Katz" <mhkatz97@gmail.com>
Restore produced_encodings and add an optional try_upgrade hook. Default decimals to v1, upgrade only with an explicit allowlist, and keep CUDA exclusions effective. Use static decimal instances and cover default writer compatibility. Signed-off-by: "Matt Katz" <mhkatz97@gmail.com>
Merging this PR will improve performance by 55.09%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ⚡ | Simulation | take_fsl_u32_random[128, 100] |
137.9 µs | 77.1 µs | +78.76% |
| ⚡ | Simulation | take_fsl_u64_random[64, 10] |
54 µs | 30.9 µs | +74.86% |
| ⚡ | Simulation | take_fsl_f16_random[256, 100] |
141.7 µs | 88.2 µs | +60.72% |
| ⚡ | Simulation | take_fsl_random[64, 100] |
144.5 µs | 125.4 µs | +15.17% |
| Simulation | fixed_16_advancing_ptr_safe[100] |
< 1 ns | < 1 ns | N/A | |
| Simulation | preverify_advancing_ptr_unchecked[1000] |
< 1 ns | < 1 ns | N/A | |
| Simulation | preverify_advancing_ptr_unchecked[10000] |
< 1 ns | < 1 ns | N/A |
Tip
Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.
Comparing mk/filter-schemes-on-serialized-ids (0c415a7) with develop (1eb5b43)
Footnotes
-
287 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. ↩
Accept serialized IDs when constructing BtrBlocks builders and derive default permissions from the default core edition. Replace permission variants with a set, preserve CUDA exclusions, and migrate writer and benchmark callers to constructor-based permissions. Signed-off-by: "Matt Katz" <mhkatz97@gmail.com>
Resolve static edition array IDs in vortex-edition and document how builder permissions filter schemes registered later. Explicitly permit Delta in the scheme selection and trace tests while preserving their assertions. Fix the decimal upgrade lint, redundant qualifications, and formatting. Signed-off-by: "Matt Katz" <mhkatz97@gmail.com>
| use vortex_session::VortexSession; | ||
|
|
||
| /// The `core` edition enabled for writing by the default Vortex session. | ||
| pub const DEFAULT_CORE_EDITION: EditionId = CORE_2026_08_3; |
There was a problem hiding this comment.
This should be kept here but vortex depends on btrblocks, so import cycle
Make empty() start without registered schemes or serialized ID permissions. Allow callers to set or extend permissions before build, while keeping the default core edition permissions in default(). Update callers and cover final permission filtering, decimal upgrades, and CUDA preset ordering. Signed-off-by: "Matt Katz" <mhkatz97@gmail.com>
| &binary::VarBinScheme, | ||
| // Decimal schemes. | ||
| &decimal::DecimalScheme, | ||
| // Use v1 by default and let builder upgrade to v2 if permitted by edition. |
There was a problem hiding this comment.
if permitted by the allow encodings (editions are not a framework concern)
| /// `None` keeps the original scheme. An upgrade must preserve the [`SchemeId`] and must not | ||
| /// downgrade the registered configuration. The caller checks the selected scheme's | ||
| /// [`produced_encodings`](Self::produced_encodings) before using it. | ||
| fn try_upgrade(&self, _allowed_serialized_ids: &AllowedSerializedIds) -> Option<&dyn Scheme> { |
There was a problem hiding this comment.
why can we not check this on construction of the compressor
| vortex-compressor = { workspace = true } | ||
| vortex-datetime-parts = { workspace = true } | ||
| vortex-decimal-byte-parts = { workspace = true } | ||
| vortex-edition = { workspace = true } |
There was a problem hiding this comment.
Can we avoid this? Ideally you pass id on construction.
Compressor shouldn't need to know about edition just allowed ids
There was a problem hiding this comment.
I think this is because of Default impl. I think you can construct the compressor and then only filter it in the write strategy
There was a problem hiding this comment.
Yeah this is because of Default, which I thought we didn't want to completely break.
In order to avoid this we either need to:
- Remove
Defaultand have compressor constructors always take a permitted id list. - No ID is permitted to default compressor, and you set them later
- A subset of the IDs in ALL_SCHEMES are permitted in default compressor via a default allowlist.
I prefer 1 because 2 is effectively a hard break and 3 requires more bookkeeping
There was a problem hiding this comment.
I think you can have unfiltered list here that needs to have ids supplied during construction?
There was a problem hiding this comment.
that would not solve the delta problem we had though iiuc
There was a problem hiding this comment.
Delta is not in any edition so it would get removed from the supported strategies
There was a problem hiding this comment.
it might be good to split out this change into a pr stack
| /// This list is order-sensitive: the builder preserves this order when constructing | ||
| /// the final scheme list, so that tie-breaking is deterministic. | ||
| /// | ||
| /// If a scheme can be configured to support different editions like |
There was a problem hiding this comment.
I think in general (like what Joe said below) we want to be very, very intentional with our wording wrt editions, versions, allowed wire IDs, etc, because this can easily become confusing and counterintuitive. That was one of the things I was trying to do on the versioning docs (still a PR, probably can still be improved)
| /// An empty set permits no serialized IDs. Upgrades and filtering are deferred until | ||
| /// [`Self::build`], including for schemes registered later. Schemes are never downgraded. |
There was a problem hiding this comment.
yeah I think it would be good to merge the versioning PR and then have comments that reference that because in a vacuum this can be very confusing
| /// The serialized IDs permitted for compression schemes. | ||
| pub type AllowedSerializedIds = HashSet<ArrayId>; |
There was a problem hiding this comment.
shouldn't this be opaque? so that we can have both the allow and forbidden list in here?
There was a problem hiding this comment.
Since we always supply ids now, we just need the allowlist
There was a problem hiding this comment.
I generally like types being opaque (so you can add methods to it) but I'll let you decide whats best
| /// Uses the default core edition's serialized array IDs. Use [`Self::allow_encodings`] to | ||
| /// permit additional encodings; otherwise, schemes requiring them are omitted at build. | ||
| fn default() -> Self { | ||
| Self::new(array_ids_for_edition(&DEFAULT_CORE_EDITION).collect()) | ||
| } | ||
| } |
There was a problem hiding this comment.
I think it should be fine to break this (remove it) so that vortex-btrblocks doesn't have to depend on vortex-edition
Summary
Configure BtrBlocks compression schemes from the serialized array IDs the writer is allowed to emit. The builder uses those permissions to select compatible scheme versions and filter unsupported schemes once, when
build()is called.The two main changes are defaulting to the default core edition's encodings and adding
Scheme::try_upgradefor optional upgrades such as decimal v1 to v2.Defaults use the default core edition
BtrBlocksCompressorBuilder::default()now takes its permitted serialized IDs fromDEFAULT_CORE_EDITION, including encodings inherited from earlier core editions.BtrBlocksCompressor::default()inherits this behavior.The current default core edition permits decimal v1, so these defaults keep decimal compression in v1 mode. A caller that creates a default write strategy just to customize layout therefore retains decimal output compatible with the default edition.
DEFAULT_CORE_EDITIONmust live invortex-editionto avoid a dependency cycle. The newarray_ids_for_edition()helper resolves static edition membership in that crate, keeping edition traversal out of the compressor builder.Scheme upgrades with
try_upgradeScheme::produced_encodings()remains the required declaration of the serialized IDs a scheme can emit. The new optional hook lets a scheme offer a newer configuration when the supplied permissions support it:The default implementation returns
None. Duringbuild(), the builder makes one ordered pass over all registered schemes:try_upgradewith the permitted serialized IDs.None.produced_encodings()is permitted.Returning
Nonemeans there is no upgrade; the original scheme still goes through filtering. An upgrade preserves the scheme'sSchemeIdand must not downgrade its configuration. Selection order is preserved, and the same rules apply to schemes added throughwith_new_scheme().Only the decimal scheme overrides this hook. Other schemes continue to declare their outputs and use the default implementation.
Decimal v1 and v2
DecimalScheme::default()and the default scheme list use v1. The upgrade hook returns a static v2 scheme when both decimal v1 and v2 serialized IDs are permitted.i64in canonical form.i128andi256values into a signed most significant part and unsigned lower parts, compressing each part independently.V2 requires both IDs because single-part arrays still serialize as v1. An explicitly registered v2 scheme is filtered out if either ID is missing; it is never downgraded to v1.
only_cuda_compatible()removes the v2 ID from the permitted set because CUDA does not support lower decimal parts. This prevents v1-to-v2 upgrades and filters explicit v2 schemes, including those registered after applying the preset. Apply the preset after permission changes, sinceset_allowed_encodingsandallow_encodingscan re-enable v2.Builder and writer integration
Permissions can be supplied at construction or updated before
build(), replacingretain_allowed_encodings().AllowedSerializedIdsis aHashSet<ArrayId>alias:new(ids)starts with the default schemes and the supplied permissions.empty()starts with no schemes and no permitted serialized IDs.default()starts with the default schemes and the default core edition's permissions.set_allowed_encodings(ids)replaces the permitted IDs.allow_encodings(ids)adds permitted IDs while preserving the existing set.Both permission methods accept an iterator of serialized IDs and return the builder for chaining. Upgrades and filtering use the final permissions when
build()is called.Schemes whose outputs are not permitted are silently omitted at build time. To use an encoding outside the default core edition, supply its serialized ID through
new(ids)orallow_encodings(ids)as well as registering its scheme. For example, start fromempty().allow_encodings(ids)when configuring schemes individually.When no explicit write strategy is supplied, the file writer constructs the compressor using registered serialized IDs permitted by the session's enabled editions. With edition enforcement disabled, it uses all registered IDs, which can enable decimal v2. Explicit write strategies retain their supplied configuration; callers targeting older or custom editions must supply matching permissions.