lance_encoding/format/metadata.rs
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright The Lance Authors
3
4//! Execution metadata for shared structural engines. Page descriptors are not
5//! wire messages. Stable protobufs are converted at the file boundary; current
6//! compression descriptors are shared with the independent 2.3 grammar.
7
8use prost::Message;
9
10pub use super::pb23::{
11 BufferCompression, ByteStreamSplit, CompressionScheme, CompressiveEncoding, Constant, Delta,
12 Dictionary, FixedSizeList, Flat, Fsst, General, InlineBitpacking, OutOfLineBitpacking,
13 PackedStruct, Range, RepDefLayer, Rle, Variable, VariablePackedStruct, compressive_encoding,
14 variable_packed_struct,
15};
16
17/// A structural engine's execution description, independent of its wire envelope.
18#[derive(Clone, Debug, Default, PartialEq)]
19pub struct PageLayout {
20 /// The selected engine. Missing layouts are rejected before execution.
21 pub layout: Option<page_layout::Layout>,
22}
23
24/// Structural engine choices.
25pub mod page_layout {
26 use super::*;
27 /// Physical engines shared by stable and planar pages.
28 #[derive(Clone, Debug, PartialEq)]
29 pub enum Layout {
30 /// Independently compressed chunks, with optional levels and dictionary.
31 MiniBlockLayout(MiniBlockLayout),
32 /// Individually addressable values interleaved with optional control words.
33 FullZipLayout(FullZipLayout),
34 /// An inline scalar or no materialized values, with optional level buffers.
35 ConstantLayout(ConstantLayout),
36 /// Stable Blob v1 descriptors and their null semantics.
37 BlobLayout(Box<BlobLayout>),
38 }
39}
40
41/// Buffer and row accounting needed by the mini-block engine.
42#[derive(Clone, Debug, Default, PartialEq)]
43pub struct MiniBlockLayout {
44 /// Repetition stream encoding; absent when no repetition buffer exists.
45 pub rep_compression: Option<CompressiveEncoding>,
46 /// Definition stream encoding; absent when no definition buffer exists.
47 pub def_compression: Option<CompressiveEncoding>,
48 /// Value encoding, required for engines that materialize values.
49 pub value_compression: Option<CompressiveEncoding>,
50 /// Page dictionary encoding; absent when chunks do not share a dictionary.
51 pub dictionary: Option<CompressiveEncoding>,
52 /// Number of entries in the page dictionary.
53 pub num_dictionary_items: u64,
54 /// Inner-most to outer-most repetition/definition interpretations.
55 pub layers: Vec<i32>,
56 /// Value buffers per chunk, excluding repetition and definition streams.
57 pub num_buffers: u64,
58 /// Number of list layers represented by the repetition index.
59 pub repetition_index_depth: u32,
60 /// Number of structural events, including invisible entries.
61 pub num_items: u64,
62 /// Selects u32 chunk metadata; false selects the stable u16 representation.
63 pub has_large_chunk: bool,
64}
65
66/// Addressing and level information needed by the zipped engine.
67#[derive(Clone, Debug, Default, PartialEq)]
68pub struct FullZipLayout {
69 /// Repetition bits in each control word.
70 pub bits_rep: u32,
71 /// Definition bits in each control word.
72 pub bits_def: u32,
73 /// Fixed value width or variable length-prefix width; required for zipped values.
74 pub details: Option<full_zip_layout::Details>,
75 /// Number of structural events, including invisible entries.
76 pub num_items: u32,
77 /// Number of leaf slots that are visible to the parent.
78 pub num_visible_items: u32,
79 /// Value encoding, required for engines that materialize values.
80 pub value_compression: Option<CompressiveEncoding>,
81 /// Inner-most to outer-most repetition/definition interpretations.
82 pub layers: Vec<i32>,
83}
84
85/// Zipped value addressing.
86pub mod full_zip_layout {
87 /// How to locate values within the zipped buffer.
88 #[derive(Clone, Debug, PartialEq)]
89 pub enum Details {
90 /// Fixed width of each encoded value, in bits.
91 BitsPerValue(u32),
92 /// Width of each variable-value length prefix, in bits.
93 BitsPerOffset(u32),
94 }
95}
96
97/// Scalar and level information needed by the constant engine.
98#[derive(Clone, Debug, Default, PartialEq)]
99pub struct ConstantLayout {
100 /// Inner-most to outer-most repetition/definition interpretations.
101 pub layers: Vec<i32>,
102 /// Encoded scalar; absent for pages without materialized values.
103 pub inline_value: Option<bytes::Bytes>,
104 /// Repetition stream encoding; absent when no repetition buffer exists.
105 pub rep_compression: Option<CompressiveEncoding>,
106 /// Definition stream encoding; absent when no definition buffer exists.
107 pub def_compression: Option<CompressiveEncoding>,
108 /// Number of entries in the repetition stream.
109 pub num_rep_values: u64,
110 /// Number of entries in the definition stream.
111 pub num_def_values: u64,
112}
113
114/// Frozen Blob v1 execution description used by stable readers and writers.
115#[derive(Clone, Debug, Default, PartialEq)]
116pub struct BlobLayout {
117 /// Descriptor layout, required by the stable Blob v1 engine.
118 pub inner_layout: Option<Box<PageLayout>>,
119 /// Inner-most to outer-most repetition/definition interpretations.
120 pub layers: Vec<i32>,
121}
122
123impl PageLayout {
124 /// Estimate retained metadata size using the same conservative compression
125 /// tree multiplier as the wire-backed page metadata.
126 pub(crate) fn estimated_size(&self) -> usize {
127 let compression =
128 |value: &Option<CompressiveEncoding>| value.as_ref().map_or(0, |v| v.encoded_len() * 4);
129 std::mem::size_of::<Self>()
130 + match &self.layout {
131 Some(page_layout::Layout::MiniBlockLayout(v)) => {
132 v.layers.capacity() * 4
133 + compression(&v.rep_compression)
134 + compression(&v.def_compression)
135 + compression(&v.value_compression)
136 + compression(&v.dictionary)
137 }
138 Some(page_layout::Layout::FullZipLayout(v)) => {
139 v.layers.capacity() * 4 + compression(&v.value_compression)
140 }
141 Some(page_layout::Layout::ConstantLayout(v)) => {
142 v.layers.capacity() * 4
143 + v.inline_value.as_ref().map_or(0, |v| v.len())
144 + compression(&v.rep_compression)
145 + compression(&v.def_compression)
146 }
147 Some(page_layout::Layout::BlobLayout(v)) => {
148 std::mem::size_of::<BlobLayout>()
149 + v.layers.capacity() * 4
150 + v.inner_layout.as_ref().map_or(0, |v| v.estimated_size())
151 }
152 None => 0,
153 }
154 }
155}