Skip to content

Commit 55ade84

Browse files
committed
wip
Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
1 parent 7de670a commit 55ade84

12 files changed

Lines changed: 417 additions & 128 deletions

File tree

vortex-edition/src/session.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,8 @@ pub trait EditionSessionExt: SessionExt {
230230

231231
/// Returns the editions enabled for writing.
232232
///
233-
/// Accessing this method installs the enabled-editions session variable if it is absent,
234-
/// opting the session into edition-gated writing with an initially empty selection.
233+
/// Accessing this method installs the enabled-editions session variable if it is absent, with
234+
/// an initially empty selection.
235235
fn enabled_editions(&self) -> SessionGuard<'_, EnabledEditions> {
236236
self.get::<EnabledEditions>()
237237
}
@@ -258,12 +258,11 @@ pub trait EditionSessionExt: SessionExt {
258258

259259
/// Resolve the encodings in all enabled editions.
260260
///
261-
/// Returns `None` when the enabled-editions variable is absent, which is the explicit
262-
/// opt-out used by lower-level sessions. Once the variable is present, an empty enabled
263-
/// set resolves to `Some(Vec::new())` and therefore permits no edition encodings.
261+
/// When the enabled-editions variable is absent or no editions are enabled, this returns an
262+
/// empty vector and therefore permits no edition encodings.
264263
fn enabled_encoding_ids(&self) -> Vec<Id> {
265264
let Some(enabled) = self.get_opt::<EnabledEditions>() else {
266-
vec![]
265+
return vec![];
267266
};
268267
let editions = self.editions();
269268
let mut ids: Vec<Id> = enabled

vortex-edition/src/tests.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::EditionId;
99
use crate::EditionInclusion;
1010
use crate::EditionSession;
1111
use crate::EditionSessionExt;
12+
use crate::EnabledEditions;
1213

1314
const FIRST: EditionId = EditionId::new("test", 2026, 1, 0);
1415
const SECOND: EditionId = EditionId::new("test", 2026, 7, 0);
@@ -126,6 +127,68 @@ fn session_exposes_edition_registry() {
126127
assert!(session.editions().find(&FIRST).is_some());
127128
}
128129

130+
#[test]
131+
fn registered_and_enabled_editions_are_separate() -> Result<(), crate::EditionError> {
132+
let session = VortexSession::empty().with::<EditionSession>();
133+
for declaration in DECLARATIONS {
134+
session.register_edition(declaration)?;
135+
}
136+
137+
assert!(session.enabled_encoding_ids().is_empty());
138+
session.enable_edition(FIRST)?;
139+
assert_eq!(session.enabled_editions().editions(), [FIRST]);
140+
assert_eq!(
141+
session
142+
.enabled_encoding_ids()
143+
.iter()
144+
.map(|id| id.as_str())
145+
.collect::<Vec<_>>(),
146+
["test.alpha", "test.beta"]
147+
);
148+
149+
session.enable_edition(SECOND)?;
150+
assert_eq!(session.enabled_editions().editions(), [SECOND]);
151+
assert_eq!(session.enabled_encoding_ids().len(), 3);
152+
153+
// Selecting an older edition in the same family replaces the newer one and removes
154+
// encodings that joined after it.
155+
session.enable_edition(FIRST)?;
156+
assert_eq!(session.enabled_editions().editions(), [FIRST]);
157+
let enabled = session.enabled_encoding_ids();
158+
assert_eq!(enabled.len(), 2);
159+
assert!(enabled.iter().all(|id| id.as_str() != "test.gamma"));
160+
Ok(())
161+
}
162+
163+
#[test]
164+
fn enabling_requires_registration() {
165+
let session = VortexSession::empty().with::<EnabledEditions>();
166+
assert!(session.enable_edition(FIRST).is_err());
167+
assert!(session.enabled_editions().editions().is_empty());
168+
}
169+
170+
#[test]
171+
fn enabled_editions_are_independent_across_families() -> Result<(), crate::EditionError> {
172+
const OTHER: EditionId = EditionId::new("other", 2026, 4, 0);
173+
static OTHER_DECLARATION: EditionDeclaration = EditionDeclaration {
174+
edition: Edition {
175+
id: OTHER,
176+
min_vortex_version: None,
177+
},
178+
added: &[&"other.delta"],
179+
};
180+
181+
let session = VortexSession::empty().with::<EditionSession>();
182+
session.register_edition(&DECLARATIONS[0])?;
183+
session.register_edition(&OTHER_DECLARATION)?;
184+
session.enable_edition(FIRST)?;
185+
session.enable_edition(OTHER)?;
186+
187+
assert_eq!(session.enabled_editions().editions(), [OTHER, FIRST]);
188+
assert_eq!(session.enabled_encoding_ids().len(), 3);
189+
Ok(())
190+
}
191+
129192
#[test]
130193
fn duplicate_declarations_error() {
131194
let editions = session();

vortex-file/src/footer/field_sizes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ mod tests {
141141
.with::<LayoutSession>()
142142
.with::<RuntimeSession>();
143143
crate::register_default_encodings(&session);
144+
crate::enable_all_registered_array_encodings(&session);
144145
session
145146
});
146147

vortex-file/src/lib.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,37 @@ pub fn register_default_encodings(session: &VortexSession) {
192192
vortex_tensor::initialize(session);
193193
}
194194

195+
#[cfg(test)]
196+
pub(crate) fn enable_all_registered_array_encodings(session: &VortexSession) {
197+
use vortex_edition::Edition;
198+
use vortex_edition::EditionId;
199+
use vortex_edition::EditionInclusion;
200+
use vortex_edition::EditionSessionExt;
201+
use vortex_error::VortexExpect;
202+
use vortex_error::vortex_err;
203+
204+
const TEST_EDITION: EditionId = EditionId::new("test", 2026, 7, 0);
205+
206+
let editions = session.editions();
207+
editions
208+
.declare_edition(Edition {
209+
id: TEST_EDITION,
210+
min_vortex_version: None,
211+
})
212+
.map_err(|error| vortex_err!("{error}"))
213+
.vortex_expect("test edition is valid");
214+
for id in session.arrays().registry().ids() {
215+
editions
216+
.declare_inclusion(EditionInclusion::new(&id, TEST_EDITION))
217+
.map_err(|error| vortex_err!("{error}"))
218+
.vortex_expect("registered array encoding has one test-edition inclusion");
219+
}
220+
session
221+
.enable_edition(TEST_EDITION)
222+
.map_err(|error| vortex_err!("{error}"))
223+
.vortex_expect("test edition is registered");
224+
}
225+
195226
#[cfg(test)]
196227
mod default_encoding_tests {
197228
use vortex_array::VTable as _;
@@ -222,10 +253,4 @@ mod default_encoding_tests {
222253
.has_execute_parent(Filter.id(), OnPair.id())
223254
);
224255
}
225-
226-
#[cfg(not(feature = "unstable_encodings"))]
227-
#[test]
228-
fn default_writer_does_not_allow_onpair() {
229-
assert!(!crate::ALLOWED_ENCODINGS.contains(&OnPair.id()));
230-
}
231256
}

vortex-file/src/open.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ mod tests {
461461
.with::<LayoutSession>()
462462
.with::<RuntimeSession>();
463463
crate::register_default_encodings(&session);
464+
crate::enable_all_registered_array_encodings(&session);
464465
session
465466
}
466467

@@ -517,6 +518,7 @@ mod tests {
517518
.with::<RuntimeSession>();
518519

519520
crate::register_default_encodings(&session);
521+
crate::enable_all_registered_array_encodings(&session);
520522

521523
// Create a large file (> 1MB)
522524
let mut buf = ByteBufferMut::empty();
@@ -578,6 +580,7 @@ mod tests {
578580
.with::<RuntimeSession>();
579581

580582
crate::register_default_encodings(&session);
583+
crate::enable_all_registered_array_encodings(&session);
581584

582585
let mut buf = ByteBufferMut::empty();
583586
let array = Buffer::from((0i32..16_384).collect::<Vec<i32>>()).into_array();

vortex-file/src/strategy.rs

Lines changed: 15 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,13 @@
55
66
use std::num::NonZeroUsize;
77
use std::sync::Arc;
8-
use std::sync::LazyLock;
98

10-
use vortex_alp::ALP;
11-
use vortex_alp::ALPRD;
129
use vortex_array::ArrayId;
13-
use vortex_array::VTable;
14-
use vortex_array::arrays::Bool;
15-
use vortex_array::arrays::Chunked;
16-
use vortex_array::arrays::Constant;
17-
use vortex_array::arrays::Decimal;
18-
use vortex_array::arrays::Dict;
19-
use vortex_array::arrays::Extension;
20-
use vortex_array::arrays::FixedSizeList;
21-
use vortex_array::arrays::List;
22-
use vortex_array::arrays::ListView;
23-
use vortex_array::arrays::Masked;
24-
use vortex_array::arrays::Null;
25-
use vortex_array::arrays::Patched;
26-
use vortex_array::arrays::Primitive;
27-
use vortex_array::arrays::Struct;
28-
use vortex_array::arrays::VarBin;
29-
use vortex_array::arrays::VarBinView;
30-
use vortex_array::arrays::Variant;
31-
use vortex_array::arrays::patched::use_experimental_patches;
3210
use vortex_array::dtype::FieldPath;
3311
use vortex_btrblocks::BtrBlocksCompressorBuilder;
3412
use vortex_btrblocks::SchemeExt;
3513
use vortex_btrblocks::schemes::integer::IntDictScheme;
36-
use vortex_bytebool::ByteBool;
37-
use vortex_datetime_parts::DateTimeParts;
38-
use vortex_decimal_byte_parts::DecimalByteParts;
3914
use vortex_error::VortexExpect;
40-
use vortex_fastlanes::BitPacked;
41-
use vortex_fastlanes::Delta;
42-
use vortex_fastlanes::FoR;
43-
use vortex_fastlanes::RLE;
44-
use vortex_fsst::FSST;
4515
use vortex_layout::LayoutStrategy;
4616
use vortex_layout::LayoutStrategyEncodingValidator;
4717
use vortex_layout::layouts::buffered::BufferedStrategy;
@@ -58,80 +28,11 @@ use vortex_layout::layouts::table::TableStrategy;
5828
use vortex_layout::layouts::table::use_experimental_list_layout;
5929
use vortex_layout::layouts::zoned::writer::ZonedLayoutOptions;
6030
use vortex_layout::layouts::zoned::writer::ZonedStrategy;
61-
#[cfg(feature = "unstable_encodings")]
62-
use vortex_onpair::OnPair;
63-
use vortex_pco::Pco;
64-
use vortex_runend::RunEnd;
65-
use vortex_sequence::Sequence;
66-
use vortex_sparse::Sparse;
6731
use vortex_utils::aliases::hash_map::HashMap;
6832
use vortex_utils::aliases::hash_set::HashSet;
69-
use vortex_zigzag::ZigZag;
70-
#[cfg(feature = "zstd")]
71-
use vortex_zstd::Zstd;
72-
#[cfg(all(feature = "zstd", feature = "unstable_encodings"))]
73-
use vortex_zstd::ZstdBuffers;
7433

7534
const ONE_MEG: u64 = 1 << 20;
7635

77-
/// Static registry of all allowed array encodings for file writing.
78-
///
79-
/// This includes all canonical encodings from vortex-array plus all compressed
80-
/// encodings from the various encoding crates.
81-
pub static ALLOWED_ENCODINGS: LazyLock<HashSet<ArrayId>> = LazyLock::new(|| {
82-
let mut allowed = HashSet::new();
83-
84-
// Canonical encodings from vortex-array
85-
allowed.insert(Null.id());
86-
allowed.insert(Bool.id());
87-
allowed.insert(Primitive.id());
88-
allowed.insert(Decimal.id());
89-
allowed.insert(VarBin.id());
90-
allowed.insert(VarBinView.id());
91-
allowed.insert(List.id());
92-
allowed.insert(ListView.id());
93-
allowed.insert(FixedSizeList.id());
94-
allowed.insert(Struct.id());
95-
allowed.insert(Extension.id());
96-
allowed.insert(Chunked.id());
97-
allowed.insert(Constant.id());
98-
allowed.insert(Masked.id());
99-
allowed.insert(Dict.id());
100-
allowed.insert(Variant.id());
101-
102-
// Compressed encodings from encoding crates
103-
allowed.insert(ALP.id());
104-
allowed.insert(ALPRD.id());
105-
allowed.insert(BitPacked.id());
106-
allowed.insert(ByteBool.id());
107-
allowed.insert(DateTimeParts.id());
108-
allowed.insert(DecimalByteParts.id());
109-
allowed.insert(Delta.id());
110-
allowed.insert(FoR.id());
111-
allowed.insert(FSST.id());
112-
#[cfg(feature = "unstable_encodings")]
113-
allowed.insert(OnPair.id());
114-
allowed.insert(Pco.id());
115-
allowed.insert(RLE.id());
116-
allowed.insert(RunEnd.id());
117-
allowed.insert(Sequence.id());
118-
allowed.insert(Sparse.id());
119-
allowed.insert(ZigZag.id());
120-
121-
// Experimental encodings
122-
123-
if use_experimental_patches() {
124-
allowed.insert(Patched.id());
125-
}
126-
127-
#[cfg(feature = "zstd")]
128-
allowed.insert(Zstd.id());
129-
#[cfg(all(feature = "zstd", feature = "unstable_encodings"))]
130-
allowed.insert(ZstdBuffers.id());
131-
132-
allowed
133-
});
134-
13536
/// How the compressor was configured on [`WriteStrategyBuilder`].
13637
enum CompressorConfig {
13738
/// A [`BtrBlocksCompressorBuilder`] that [`WriteStrategyBuilder::build`] will finalize.
@@ -174,7 +75,7 @@ impl Default for WriteStrategyBuilder {
17475
compressor: CompressorConfig::BtrBlocks(BtrBlocksCompressorBuilder::default()),
17576
row_block_size: 8192,
17677
field_writers: HashMap::new(),
177-
allow_encodings: Some(ALLOWED_ENCODINGS.clone()),
78+
allow_encodings: None,
17879
flat_strategy: None,
17980
probe_compressor: None,
18081
use_list_layout: use_experimental_list_layout(),
@@ -216,11 +117,18 @@ impl WriteStrategyBuilder {
216117
self
217118
}
218119

219-
/// Override the allowed array encodings for normalization.
120+
/// Override the allowed array encodings for file writing.
220121
///
221122
/// The configured flat leaf strategy is wrapped in a [`LayoutStrategyEncodingValidator`]
222-
/// that recursively checks every chunk before passing it to the leaf writer.
123+
/// that recursively checks every chunk before passing it to the leaf writer. A configured
124+
/// BtrBlocks builder is restricted to schemes whose output encodings are all in this set.
223125
pub fn with_allow_encodings(mut self, allow_encodings: HashSet<ArrayId>) -> Self {
126+
self.compressor = match self.compressor {
127+
CompressorConfig::BtrBlocks(builder) => {
128+
CompressorConfig::BtrBlocks(builder.retain_allowed_encodings(&allow_encodings))
129+
}
130+
compressor => compressor,
131+
};
224132
self.allow_encodings = Some(allow_encodings);
225133
self
226134
}
@@ -239,6 +147,11 @@ impl WriteStrategyBuilder {
239147
/// The builder is finalized during [`build`](Self::build), producing two compressors: one for
240148
/// data (with `IntDictScheme` excluded) and one for stats.
241149
pub fn with_btrblocks_builder(mut self, builder: BtrBlocksCompressorBuilder) -> Self {
150+
let builder = if let Some(allow_encodings) = &self.allow_encodings {
151+
builder.retain_allowed_encodings(allow_encodings)
152+
} else {
153+
builder
154+
};
242155
self.compressor = CompressorConfig::BtrBlocks(builder);
243156
self
244157
}

vortex-file/src/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ static SESSION: LazyLock<VortexSession> = LazyLock::new(|| {
8888
.with::<RuntimeSession>();
8989

9090
crate::register_default_encodings(&session);
91+
crate::enable_all_registered_array_encodings(&session);
9192

9293
session
9394
});

0 commit comments

Comments
 (0)