Skip to content

Commit 6991c01

Browse files
committed
layout builder overrides
Signed-off-by: Onur Satici <onur@spiraldb.com>
1 parent d080c1d commit 6991c01

19 files changed

Lines changed: 472 additions & 231 deletions

File tree

vortex-cuda/src/layout.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ impl VTable for CudaFlat {
180180
name: Arc<str>,
181181
segment_source: Arc<dyn SegmentSource>,
182182
session: &VortexSession,
183+
_ctx: &vortex::layout::LayoutReaderContext,
183184
) -> VortexResult<LayoutReaderRef> {
184185
Ok(Arc::new(CudaFlatReader {
185186
layout: layout.clone(),

vortex-layout/public-api.lock

Lines changed: 57 additions & 29 deletions
Large diffs are not rendered by default.

vortex-layout/src/layout.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use vortex_session::registry::Id;
1919

2020
use crate::LayoutEncodingId;
2121
use crate::LayoutEncodingRef;
22+
use crate::LayoutReaderContext;
2223
use crate::LayoutReaderRef;
2324
use crate::VTable;
2425
use crate::display::DisplayLayoutTree;
@@ -63,12 +64,30 @@ pub trait Layout: 'static + Send + Sync + Debug + private::Sealed {
6364
/// Get the segment IDs for this layout.
6465
fn segment_ids(&self) -> Vec<SegmentId>;
6566

66-
fn new_reader(
67+
/// Construct a new reader for this layout, using the given dependency context.
68+
///
69+
/// Implementations check `ctx` for an override registered against this layout's encoding
70+
/// ID before dispatching to the layout's default [`crate::VTable::new_reader`].
71+
fn new_reader_in_ctx(
6772
&self,
6873
name: Arc<str>,
6974
segment_source: Arc<dyn SegmentSource>,
7075
session: &VortexSession,
76+
ctx: &LayoutReaderContext,
7177
) -> VortexResult<LayoutReaderRef>;
78+
79+
/// Convenience: construct a new reader for this layout using a fresh, empty context.
80+
///
81+
/// Top-level callers (file open, tests) typically use this. Recursive calls inside
82+
/// layout implementations should use [`Self::new_reader_in_ctx`] to propagate `ctx`.
83+
fn new_reader(
84+
&self,
85+
name: Arc<str>,
86+
segment_source: Arc<dyn SegmentSource>,
87+
session: &VortexSession,
88+
) -> VortexResult<LayoutReaderRef> {
89+
self.new_reader_in_ctx(name, segment_source, session, &LayoutReaderContext::new())
90+
}
7291
}
7392

7493
pub trait IntoLayout {
@@ -306,13 +325,18 @@ impl<V: VTable> Layout for LayoutAdapter<V> {
306325
V::segment_ids(&self.0)
307326
}
308327

309-
fn new_reader(
328+
fn new_reader_in_ctx(
310329
&self,
311330
name: Arc<str>,
312331
segment_source: Arc<dyn SegmentSource>,
313332
session: &VortexSession,
333+
ctx: &LayoutReaderContext,
314334
) -> VortexResult<LayoutReaderRef> {
315-
V::new_reader(&self.0, name, segment_source, session)
335+
let id = V::encoding(&self.0).id();
336+
if let Some(builder) = ctx.get_override(&id) {
337+
return builder(self, name, segment_source, session, ctx);
338+
}
339+
V::new_reader(&self.0, name, segment_source, session, ctx)
316340
}
317341
}
318342

vortex-layout/src/layouts/array_tree/flat.rs

Lines changed: 28 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

44
use std::sync::Arc;
5-
use std::sync::OnceLock;
65

7-
use vortex_array::DeserializeMetadata;
8-
use vortex_array::SerializeMetadata;
6+
use vortex_array::EmptyMetadata;
97
use vortex_array::dtype::DType;
10-
use vortex_array::dtype::TryFromBytes;
118
use vortex_buffer::ByteBuffer;
12-
use vortex_error::VortexExpect;
139
use vortex_error::VortexResult;
1410
use vortex_error::vortex_bail;
1511
use vortex_error::vortex_panic;
@@ -19,12 +15,11 @@ use vortex_session::registry::ReadContext;
1915
use crate::LayoutChildType;
2016
use crate::LayoutEncodingRef;
2117
use crate::LayoutId;
18+
use crate::LayoutReaderContext;
2219
use crate::LayoutReaderRef;
2320
use crate::LayoutRef;
2421
use crate::VTable;
2522
use crate::children::LayoutChildren;
26-
use crate::layouts::array_tree::ArrayTreesSource;
27-
use crate::layouts::array_tree::reader::ArrayTreeFlatReader;
2823
use crate::layouts::flat::FlatLayout;
2924
use crate::segments::SegmentId;
3025
use crate::segments::SegmentSource;
@@ -36,44 +31,34 @@ vtable!(ArrayTreeFlat);
3631
#[derive(Debug)]
3732
pub struct ArrayTreeFlatLayoutEncoding;
3833

39-
/// A flat layout variant that stores its compact encoding tree separately from the data segment.
34+
/// A flat layout variant that retrieves its compact encoding tree from a sibling layout's
35+
/// VarBin payload rather than from the data segment trailer.
4036
///
4137
/// At write time, the compact flatbuffer (encoding tree + buffer descriptors, no stats) is
42-
/// stored in this layout and later collected by [`super::ArrayTreeLayout`] into a shared VarBin
43-
/// array.
38+
/// attached to this layout in memory and later collected by [`super::ArrayTreeLayout`] into
39+
/// a struct array keyed by segment ID.
4440
///
45-
/// At read time, the compact flatbuffer is retrieved from the shared [`ArrayTreesSource`]
46-
/// (injected by the parent [`super::ArrayTreeLayout`]'s reader-construction walk) rather than
47-
/// being parsed from the data segment. This avoids fetching the segment for decode planning
48-
/// and prevents device-to-host copies for device-resident buffers.
41+
/// At read time, this layout's reader looks up its compact tree in a shared
42+
/// [`super::ArrayTreesSource`] using its own [`SegmentId`]. Construction requires that an
43+
/// ancestor [`super::ArrayTreeLayout`] has registered a reader-builder override against
44+
/// this encoding's ID — this layout has no useful default reader.
4945
#[derive(Clone, Debug)]
5046
pub struct ArrayTreeFlatLayout {
5147
inner: FlatLayout,
52-
chunk_idx: usize,
5348
/// The compact flatbuffer produced at write time. Not persisted — only used to communicate
5449
/// between the leaf strategy and the collector strategy via the layout tree.
5550
compact_tree: Option<ByteBuffer>,
56-
/// Shared source for compact flatbuffers, injected by the parent [`super::ArrayTreeLayout`]
57-
/// during reader construction.
58-
source: OnceLock<Arc<ArrayTreesSource>>,
5951
}
6052

6153
impl ArrayTreeFlatLayout {
6254
/// Creates a new layout at write time with a compact flatbuffer.
63-
pub fn new(inner: FlatLayout, chunk_idx: usize, compact_tree: ByteBuffer) -> Self {
55+
pub fn new(inner: FlatLayout, compact_tree: ByteBuffer) -> Self {
6456
Self {
6557
inner,
66-
chunk_idx,
6758
compact_tree: Some(compact_tree),
68-
source: OnceLock::new(),
6959
}
7060
}
7161

72-
/// Returns the chunk index of this layout in the array trees VarBin.
73-
pub fn chunk_idx(&self) -> usize {
74-
self.chunk_idx
75-
}
76-
7762
/// Returns the compact flatbuffer, if available (write-time only).
7863
pub fn compact_tree(&self) -> Option<&ByteBuffer> {
7964
self.compact_tree.as_ref()
@@ -83,45 +68,12 @@ impl ArrayTreeFlatLayout {
8368
pub fn inner(&self) -> &FlatLayout {
8469
&self.inner
8570
}
86-
87-
/// Sets the shared array trees source. Called by the parent [`super::ArrayTreeLayout`]
88-
/// during the reader-construction injection walk.
89-
pub fn set_source(&self, source: Arc<ArrayTreesSource>) {
90-
// Ignore if already set (e.g., in tests or double-init scenarios).
91-
drop(self.source.set(source));
92-
}
93-
94-
/// Returns the shared array trees source, if set.
95-
pub fn source(&self) -> Option<&Arc<ArrayTreesSource>> {
96-
self.source.get()
97-
}
98-
}
99-
100-
/// Metadata for [`ArrayTreeFlatLayout`]: stores the chunk index.
101-
#[derive(Debug, Clone, PartialEq, Eq)]
102-
pub struct ArrayTreeFlatMetadata {
103-
pub chunk_idx: u32,
104-
}
105-
106-
impl SerializeMetadata for ArrayTreeFlatMetadata {
107-
fn serialize(self) -> Vec<u8> {
108-
self.chunk_idx.to_le_bytes().to_vec()
109-
}
110-
}
111-
112-
impl DeserializeMetadata for ArrayTreeFlatMetadata {
113-
type Output = Self;
114-
115-
fn deserialize(metadata: &[u8]) -> VortexResult<Self::Output> {
116-
let chunk_idx = u32::try_from_le_bytes(&metadata[0..4])?;
117-
Ok(Self { chunk_idx })
118-
}
11971
}
12072

12173
impl VTable for ArrayTreeFlat {
12274
type Layout = ArrayTreeFlatLayout;
12375
type Encoding = ArrayTreeFlatLayoutEncoding;
124-
type Metadata = ArrayTreeFlatMetadata;
76+
type Metadata = EmptyMetadata;
12577

12678
fn id(_encoding: &Self::Encoding) -> LayoutId {
12779
LayoutId::new_static("vortex.array_tree_flat")
@@ -139,10 +91,8 @@ impl VTable for ArrayTreeFlat {
13991
layout.inner.dtype()
14092
}
14193

142-
fn metadata(layout: &Self::Layout) -> Self::Metadata {
143-
ArrayTreeFlatMetadata {
144-
chunk_idx: u32::try_from(layout.chunk_idx).vortex_expect("chunk_idx must fit in u32"),
145-
}
94+
fn metadata(_layout: &Self::Layout) -> Self::Metadata {
95+
EmptyMetadata
14696
}
14797

14898
fn segment_ids(layout: &Self::Layout) -> Vec<SegmentId> {
@@ -162,24 +112,27 @@ impl VTable for ArrayTreeFlat {
162112
}
163113

164114
fn new_reader(
165-
layout: &Self::Layout,
166-
name: Arc<str>,
167-
segment_source: Arc<dyn SegmentSource>,
168-
session: &VortexSession,
115+
_layout: &Self::Layout,
116+
_name: Arc<str>,
117+
_segment_source: Arc<dyn SegmentSource>,
118+
_session: &VortexSession,
119+
_ctx: &LayoutReaderContext,
169120
) -> VortexResult<LayoutReaderRef> {
170-
Ok(Arc::new(ArrayTreeFlatReader::new(
171-
layout.clone(),
172-
name,
173-
segment_source,
174-
session.clone(),
175-
)))
121+
// ArrayTreeFlatLayout has no useful default reader. It exists to be intercepted by an
122+
// ancestor ArrayTreeLayout that registers a reader-builder override carrying the
123+
// shared ArrayTreesSource. If the dispatcher reached this method, no such ancestor
124+
// was present in the layout tree.
125+
vortex_bail!(
126+
"ArrayTreeFlatLayout requires an ancestor ArrayTreeLayout to register a reader \
127+
builder override; this layout cannot be read on its own"
128+
)
176129
}
177130

178131
fn build(
179132
_encoding: &Self::Encoding,
180133
dtype: &DType,
181134
row_count: u64,
182-
metadata: &ArrayTreeFlatMetadata,
135+
_metadata: &EmptyMetadata,
183136
segment_ids: Vec<SegmentId>,
184137
_children: &dyn LayoutChildren,
185138
ctx: &ReadContext,
@@ -189,9 +142,7 @@ impl VTable for ArrayTreeFlat {
189142
}
190143
Ok(ArrayTreeFlatLayout {
191144
inner: FlatLayout::new(row_count, dtype.clone(), segment_ids[0], ctx.clone()),
192-
chunk_idx: metadata.chunk_idx as usize,
193145
compact_tree: None,
194-
source: OnceLock::new(),
195146
})
196147
}
197148
}

0 commit comments

Comments
 (0)