@@ -50,10 +50,10 @@ use vortex_layout::layouts::compressed::CompressingStrategy;
5050use vortex_layout:: layouts:: compressed:: CompressorPlugin ;
5151use vortex_layout:: layouts:: dict:: writer:: DictStrategy ;
5252use vortex_layout:: layouts:: flat:: writer:: FlatLayoutStrategy ;
53- use vortex_layout:: layouts:: list:: writer:: ListLayoutStrategy ;
5453use vortex_layout:: layouts:: repartition:: RepartitionStrategy ;
5554use vortex_layout:: layouts:: repartition:: RepartitionWriterOptions ;
5655use vortex_layout:: layouts:: table:: TableStrategy ;
56+ use vortex_layout:: layouts:: table:: use_experimental_list_layout;
5757use vortex_layout:: layouts:: zoned:: writer:: ZonedLayoutOptions ;
5858use vortex_layout:: layouts:: zoned:: writer:: ZonedStrategy ;
5959#[ cfg( feature = "unstable_encodings" ) ]
@@ -157,6 +157,10 @@ pub struct WriteStrategyBuilder {
157157 field_writers : HashMap < FieldPath , Arc < dyn LayoutStrategy > > ,
158158 allow_encodings : Option < HashSet < ArrayId > > ,
159159 flat_strategy : Option < Arc < dyn LayoutStrategy > > ,
160+ /// Force list-column decomposition on, overriding the
161+ /// [`use_experimental_list_layout`](vortex_layout::layouts::table::use_experimental_list_layout)
162+ /// env-var default of off.
163+ list_layout : bool ,
160164}
161165
162166impl Default for WriteStrategyBuilder {
@@ -169,6 +173,7 @@ impl Default for WriteStrategyBuilder {
169173 field_writers : HashMap :: new ( ) ,
170174 allow_encodings : Some ( ALLOWED_ENCODINGS . clone ( ) ) ,
171175 flat_strategy : None ,
176+ list_layout : false ,
172177 }
173178 }
174179}
@@ -183,6 +188,14 @@ impl WriteStrategyBuilder {
183188 self
184189 }
185190
191+ /// Enable list-column decomposition, overriding the env-var default of off. When enabled, list
192+ /// columns are written as a `ListLayout` (independently compressed/chunked
193+ /// elements/offsets/validity) rather than as flat arrays.
194+ pub fn with_list_layout ( mut self ) -> Self {
195+ self . list_layout = true ;
196+ self
197+ }
198+
186199 /// Override the write layout for a specific field somewhere in the nested schema tree.
187200 ///
188201 /// The field path is matched after the root struct is split into columns. This is useful when a
@@ -243,20 +256,10 @@ impl WriteStrategyBuilder {
243256 Arc :: new ( FlatLayoutStrategy :: default ( ) )
244257 } ;
245258
246- // 7. for each chunk create a layout. List-typed chunks route through
247- // `ListLayoutStrategy` (separately-addressable elements/offsets/validity sub-layouts;
248- // non-list chunks fall through its built-in fallback to `flat`).
249- let leaf: Arc < dyn LayoutStrategy > = Arc :: new (
250- // Thread the configured `flat` (which carries `allow_encodings` / any custom flat
251- // override) through every child.
252- ListLayoutStrategy :: default ( )
253- . with_elements ( Arc :: clone ( & flat) )
254- . with_offsets ( Arc :: clone ( & flat) )
255- . with_validity ( Arc :: clone ( & flat) )
256- . with_fallback ( Arc :: clone ( & flat) ) ,
257- ) ;
258-
259- let chunked = ChunkedLayoutStrategy :: new ( leaf) ;
259+ // 7. for each chunk create a flat layout. List columns are decomposed above this point by
260+ // the `TableStrategy` dispatcher (into independently-compressed elements/offsets/validity
261+ // sub-columns), so the per-chunk leaf only ever sees flat, non-list chunks.
262+ let chunked = ChunkedLayoutStrategy :: new ( Arc :: clone ( & flat) ) ;
260263 // 6. buffer chunks so they end up with closer segment ids physically
261264 let buffered = BufferedStrategy :: new ( chunked, 2 * ONE_MEG ) ; // 2MB
262265
@@ -334,8 +337,14 @@ impl WriteStrategyBuilder {
334337 let validity_strategy = CollectStrategy :: new ( compress_then_flat) ;
335338
336339 // Take any field overrides from the builder and apply them to the final strategy.
337- let table_strategy = TableStrategy :: new ( Arc :: new ( validity_strategy) , Arc :: new ( repartition) )
338- . with_field_writers ( self . field_writers ) ;
340+ let mut table_strategy =
341+ TableStrategy :: new ( Arc :: new ( validity_strategy) , Arc :: new ( repartition) )
342+ . with_field_writers ( self . field_writers ) ;
343+ // List decomposition is experimental: enabled by an explicit builder opt-in or the
344+ // `VORTEX_EXPERIMENTAL_LIST_LAYOUT` env var; off otherwise.
345+ if self . list_layout || use_experimental_list_layout ( ) {
346+ table_strategy = table_strategy. with_list_layout ( ) ;
347+ }
339348
340349 Arc :: new ( table_strategy)
341350 }
0 commit comments