1pub mod layout;
4pub mod reader;
5pub mod writer;
6
7use std::path::PathBuf;
8
9use crate::format::frame::FormatError;
10
11#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
13#[repr(transparent)]
14pub struct SegmentId([u8; 16]);
15
16impl SegmentId {
17 #[must_use]
19 pub fn new(timestamp_millis: u64, entropy: [u8; 10]) -> Self {
20 let timestamp = timestamp_millis.to_be_bytes();
21 let mut bytes = [0_u8; 16];
22 if let (Some(destination), Some(source)) = (bytes.get_mut(..6), timestamp.get(2..)) {
23 destination.copy_from_slice(source);
24 }
25 if let Some(destination) = bytes.get_mut(6..) {
26 destination.copy_from_slice(&entropy);
27 }
28 Self(bytes)
29 }
30
31 #[must_use]
33 pub const fn from_bytes(bytes: [u8; 16]) -> Self {
34 Self(bytes)
35 }
36
37 #[must_use]
39 pub const fn as_bytes(&self) -> &[u8; 16] {
40 &self.0
41 }
42
43 #[must_use]
45 pub fn file_name(self) -> String {
46 let mut name = String::with_capacity(8 + 32 + 5);
47 name.push_str("segment-");
48 for byte in self.0 {
49 use std::fmt::Write as _;
50 let _ = write!(name, "{byte:02x}");
51 }
52 name.push_str(".zseg");
53 name
54 }
55}
56
57impl std::fmt::Display for SegmentId {
58 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 for byte in self.0 {
60 write!(formatter, "{byte:02x}")?;
61 }
62 Ok(())
63 }
64}
65
66#[derive(Clone, Debug, Eq, PartialEq)]
68pub struct SegmentMeta {
69 pub id: SegmentId,
71 pub row_count: u32,
73 pub scheme: u16,
75 pub dims: u32,
77 pub file_size: u64,
79 pub epoch_id: Option<crate::epoch::EpochId>,
81 pub clustering_key_range: ClusteringKeyRange,
83}
84
85impl SegmentMeta {
86 pub(crate) fn same_segment_file(&self, other: &Self) -> bool {
87 self.id == other.id
88 && self.row_count == other.row_count
89 && self.scheme == other.scheme
90 && self.dims == other.dims
91 && self.file_size == other.file_size
92 }
93}
94
95#[derive(Clone, Copy, Debug, Eq, PartialEq)]
97pub enum ClusteringKeyRange {
98 Unstamped,
100 Empty,
102 Bounded {
104 min_ts: i64,
106 max_ts: i64,
108 },
109}
110
111#[derive(Debug)]
113pub enum SegmentError {
114 Io {
116 path: PathBuf,
118 source: std::io::Error,
120 },
121 Format(FormatError),
123 WrongObject {
125 artifact: String,
127 expected: SegmentId,
129 actual: SegmentId,
131 },
132 MissingRegion(layout::RegionKind),
134 Geometry(String),
136 Columns(String),
138 Alive(String),
140 MetadataSemantic {
142 detail: String,
144 provenance: MetadataDecodeProvenance,
146 },
147 Graph(crate::graph::block::GraphNodeError),
149 Postings(crate::fts::sealed::SealedSegmentError),
151}
152
153impl SegmentError {
154 pub(crate) fn io(path: impl Into<PathBuf>, source: std::io::Error) -> Self {
155 Self::Io {
156 path: path.into(),
157 source,
158 }
159 }
160}
161
162impl std::fmt::Display for SegmentError {
163 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 match self {
165 Self::Io { path, source } => {
166 write!(formatter, "segment I/O {}: {source}", path.display())
167 }
168 Self::Format(error) => error.fmt(formatter),
169 Self::WrongObject {
170 artifact,
171 expected,
172 actual,
173 } => {
174 write!(
175 formatter,
176 "artifact {artifact} failed object identity: expected {expected}, got {actual}"
177 )
178 }
179 Self::MissingRegion(kind) => write!(formatter, "segment is missing region {kind:?}"),
180 Self::Geometry(detail) => write!(formatter, "segment geometry is invalid: {detail}"),
181 Self::Columns(detail) => write!(formatter, "segment columns are invalid: {detail}"),
182 Self::Alive(detail) => write!(formatter, "segment alive set is invalid: {detail}"),
183 Self::MetadataSemantic { detail, .. } => {
184 write!(formatter, "segment metadata is invalid: {detail}")
185 }
186 Self::Graph(error) => write!(formatter, "segment graph region is invalid: {error}"),
187 Self::Postings(error) => {
188 write!(formatter, "segment postings region is invalid: {error}")
189 }
190 }
191 }
192}
193
194#[derive(Clone, Debug, Eq, PartialEq)]
196pub enum MetadataDecodeProvenance {
197 ColumnsPresenceTail {
199 column_id: u32,
201 row_count: u32,
203 byte_offset: u64,
205 observed_byte: u8,
207 allowed_mask: u8,
209 },
210 ColumnsDictionaryCode {
212 column_id: u32,
214 row: u32,
216 byte_offset: u64,
218 code: u32,
220 dictionary_cardinality: u32,
222 },
223 ColumnsRawStringLength {
225 column_id: u32,
227 row: u32,
229 byte_offset: u64,
231 declared_bytes: u32,
233 available_bytes: u64,
235 },
236 AliveBitmapTruncation {
238 row_count: u32,
240 byte_offset: u64,
242 declared_bytes: u32,
244 observed_bytes: u32,
246 },
247}
248
249impl std::error::Error for SegmentError {
250 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
251 match self {
252 Self::Io { source, .. } => Some(source),
253 Self::Format(error) => Some(error),
254 Self::Graph(error) => Some(error),
255 Self::Postings(error) => Some(error),
256 Self::WrongObject { .. }
257 | Self::MissingRegion(_)
258 | Self::Geometry(_)
259 | Self::Columns(_)
260 | Self::Alive(_)
261 | Self::MetadataSemantic { .. } => None,
262 }
263 }
264}
265
266impl From<FormatError> for SegmentError {
267 fn from(error: FormatError) -> Self {
268 Self::Format(error)
269 }
270}
271
272impl From<crate::graph::block::GraphNodeError> for SegmentError {
273 fn from(error: crate::graph::block::GraphNodeError) -> Self {
274 Self::Graph(error)
275 }
276}
277
278impl From<crate::fts::sealed::SealedSegmentError> for SegmentError {
279 fn from(error: crate::fts::sealed::SealedSegmentError) -> Self {
280 Self::Postings(error)
281 }
282}