Skip to main content

zeppelin_embed/segment/
reader.rs

1//! Read-only memory-mapped segment validation and lazy region access.
2
3use std::fs::File;
4#[cfg(unix)]
5use std::os::fd::AsRawFd;
6use std::path::Path;
7#[cfg(any(test, feature = "test-support"))]
8use std::path::PathBuf;
9#[cfg(unix)]
10use std::ptr::NonNull;
11use std::sync::atomic::{AtomicU64, Ordering};
12use std::sync::{Arc, Mutex, OnceLock};
13
14use xxhash_rust::xxh3::xxh3_64;
15
16use crate::format::frame::{
17    FILE_HEADER_LEN, FILE_TRAILER_LEN, FormatCheck, FormatError, decode_header, read_u16, read_u32,
18    read_u64,
19};
20use crate::format::{FormatFamily, FormatRegistry};
21use crate::graph::block::{GraphNodeBlocks, ValidatedGraphNodeBlocks, decode_node_blocks};
22use crate::ingest::{DocId, DocumentVersion, Revision};
23use crate::meta::{AliveSet, ColumnStore};
24use crate::quant::Bit4Factors;
25use crate::vfs::Vfs;
26
27use super::layout::{
28    CHECKSUM_CHUNK_BYTES, Cursor, Int8Factors, REGION_ALIGNMENT, REGION_ENTRY_LEN, RegionEntry,
29    RegionKind, SEGMENT_PREFIX_LEN, VECTOR_HEADER_LEN, align_up, decode_alive, decode_columns,
30    decode_vector_header,
31};
32use super::{SegmentError, SegmentId, SegmentMeta};
33
34const MAX_SEGMENT_HEADER_BYTES: usize = 1024 * 1024;
35
36thread_local! {
37    static DATA_READ_AUDIT: std::cell::RefCell<Option<Arc<AtomicU64>>> = const {
38        std::cell::RefCell::new(None)
39    };
40}
41
42#[cfg(any(test, feature = "test-support"))]
43thread_local! {
44    static SEGMENT_COST_AUDIT: std::cell::RefCell<Option<Arc<SegmentCostCounters>>> = const {
45        std::cell::RefCell::new(None)
46    };
47}
48
49#[cfg(any(test, feature = "test-support"))]
50#[derive(Default)]
51struct SegmentCostCounters {
52    identity_hash_bytes: AtomicU64,
53    rescore_hash_bytes: AtomicU64,
54    int8_factor_decode_bytes: AtomicU64,
55    postings_hash_bytes: AtomicU64,
56    postings_decode_bytes: AtomicU64,
57    columns_hash_bytes: AtomicU64,
58    columns_decode_bytes: AtomicU64,
59    alive_hash_bytes: AtomicU64,
60    alive_decode_bytes: AtomicU64,
61}
62
63/// Test-only deterministic costs observed while reading immutable segments.
64#[cfg(any(test, feature = "test-support"))]
65#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
66pub struct SegmentCostSnapshot {
67    /// Bytes hashed while validating document identities.
68    pub identity_hash_bytes: u64,
69    /// Bytes hashed while validating exact-rescore rows.
70    pub rescore_hash_bytes: u64,
71    /// Int8 factor bytes decoded for scan validation.
72    pub int8_factor_decode_bytes: u64,
73    /// Bytes hashed while validating sealed postings.
74    pub postings_hash_bytes: u64,
75    /// Sealed-postings bytes heap-decoded into query-ready state.
76    pub postings_decode_bytes: u64,
77    /// Bytes hashed while validating typed columns.
78    pub columns_hash_bytes: u64,
79    /// Typed-column bytes heap-decoded into query-ready state.
80    pub columns_decode_bytes: u64,
81    /// Bytes hashed while validating alive state.
82    pub alive_hash_bytes: u64,
83    /// Alive-state bytes heap-decoded into query-ready state.
84    pub alive_decode_bytes: u64,
85}
86
87/// Test-only scoped collector for deterministic segment read-path costs.
88#[cfg(any(test, feature = "test-support"))]
89#[derive(Clone, Default)]
90pub struct SegmentCostAudit {
91    counters: Arc<SegmentCostCounters>,
92}
93
94#[cfg(any(test, feature = "test-support"))]
95struct SegmentCostAuditGuard {
96    previous: Option<Arc<SegmentCostCounters>>,
97}
98
99#[cfg(any(test, feature = "test-support"))]
100impl Drop for SegmentCostAuditGuard {
101    fn drop(&mut self) {
102        let previous = self.previous.take();
103        SEGMENT_COST_AUDIT.with(|slot| {
104            slot.replace(previous);
105        });
106    }
107}
108
109#[cfg(any(test, feature = "test-support"))]
110impl SegmentCostAudit {
111    /// Creates a zeroed cost collector.
112    #[must_use]
113    pub fn new() -> Self {
114        Self::default()
115    }
116
117    /// Runs one operation with this collector installed on the calling thread.
118    pub fn measure<T>(&self, operation: impl FnOnce() -> T) -> T {
119        let previous =
120            SEGMENT_COST_AUDIT.with(|slot| slot.replace(Some(Arc::clone(&self.counters))));
121        let _guard = SegmentCostAuditGuard { previous };
122        operation()
123    }
124
125    /// Returns the exact accumulated byte counters.
126    #[must_use]
127    pub fn snapshot(&self) -> SegmentCostSnapshot {
128        SegmentCostSnapshot {
129            identity_hash_bytes: self.counters.identity_hash_bytes.load(Ordering::Relaxed),
130            rescore_hash_bytes: self.counters.rescore_hash_bytes.load(Ordering::Relaxed),
131            int8_factor_decode_bytes: self
132                .counters
133                .int8_factor_decode_bytes
134                .load(Ordering::Relaxed),
135            postings_hash_bytes: self.counters.postings_hash_bytes.load(Ordering::Relaxed),
136            postings_decode_bytes: self.counters.postings_decode_bytes.load(Ordering::Relaxed),
137            columns_hash_bytes: self.counters.columns_hash_bytes.load(Ordering::Relaxed),
138            columns_decode_bytes: self.counters.columns_decode_bytes.load(Ordering::Relaxed),
139            alive_hash_bytes: self.counters.alive_hash_bytes.load(Ordering::Relaxed),
140            alive_decode_bytes: self.counters.alive_decode_bytes.load(Ordering::Relaxed),
141        }
142    }
143}
144
145#[cfg(any(test, feature = "test-support"))]
146fn account_region_hash(kind: RegionKind, bytes: usize) {
147    let bytes = u64::try_from(bytes).unwrap_or(u64::MAX);
148    SEGMENT_COST_AUDIT.with(|slot| {
149        let Some(counters) = slot.borrow().as_ref().cloned() else {
150            return;
151        };
152        let counter = match kind {
153            RegionKind::DocumentVersions => &counters.identity_hash_bytes,
154            RegionKind::VectorRescore => &counters.rescore_hash_bytes,
155            RegionKind::Postings => &counters.postings_hash_bytes,
156            RegionKind::Columns => &counters.columns_hash_bytes,
157            RegionKind::Alive => &counters.alive_hash_bytes,
158            _ => return,
159        };
160        let _ = counter.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |current| {
161            Some(current.saturating_add(bytes))
162        });
163    });
164}
165
166#[cfg(any(test, feature = "test-support"))]
167fn account_region_decode(kind: RegionKind, bytes: usize) {
168    let bytes = u64::try_from(bytes).unwrap_or(u64::MAX);
169    SEGMENT_COST_AUDIT.with(|slot| {
170        let Some(counters) = slot.borrow().as_ref().cloned() else {
171            return;
172        };
173        let counter = match kind {
174            RegionKind::VectorFactors => &counters.int8_factor_decode_bytes,
175            RegionKind::Postings => &counters.postings_decode_bytes,
176            RegionKind::Columns => &counters.columns_decode_bytes,
177            RegionKind::Alive => &counters.alive_decode_bytes,
178            _ => return,
179        };
180        let _ = counter.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |current| {
181            Some(current.saturating_add(bytes))
182        });
183    });
184}
185
186#[cfg(any(test, feature = "test-support"))]
187pub(crate) fn account_active_postings_decode(bytes: usize) {
188    let bytes = u64::try_from(bytes).unwrap_or(u64::MAX);
189    SEGMENT_COST_AUDIT.with(|slot| {
190        if let Some(counters) = slot.borrow().as_ref() {
191            let _ = counters.postings_decode_bytes.fetch_update(
192                Ordering::Relaxed,
193                Ordering::Relaxed,
194                |current| Some(current.saturating_add(bytes)),
195            );
196        }
197    });
198}
199
200fn region_hash(_kind: RegionKind, bytes: &[u8]) -> u64 {
201    #[cfg(any(test, feature = "test-support"))]
202    account_region_hash(_kind, bytes.len());
203    xxh3_64(bytes)
204}
205
206pub(crate) struct DataReadAuditGuard {
207    previous: Option<Arc<AtomicU64>>,
208}
209
210impl Drop for DataReadAuditGuard {
211    fn drop(&mut self) {
212        let previous = self.previous.take();
213        DATA_READ_AUDIT.with(|slot| {
214            slot.replace(previous);
215        });
216    }
217}
218
219pub(crate) fn install_data_read_audit(counter: Option<Arc<AtomicU64>>) -> DataReadAuditGuard {
220    let previous = DATA_READ_AUDIT.with(|slot| slot.replace(counter));
221    DataReadAuditGuard { previous }
222}
223
224fn account_data_read(bytes: usize) {
225    let bytes = u64::try_from(bytes).unwrap_or(u64::MAX);
226    DATA_READ_AUDIT.with(|slot| {
227        if let Some(counter) = slot.borrow().as_ref() {
228            let _ = counter.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |current| {
229                Some(current.saturating_add(bytes))
230            });
231        }
232    });
233}
234
235#[cfg(unix)]
236struct MappedFile {
237    _file: File,
238    pointer: NonNull<u8>,
239    length: usize,
240}
241
242#[cfg(unix)]
243impl MappedFile {
244    fn open(file: File, path: &Path) -> Result<Self, SegmentError> {
245        let length = usize::try_from(
246            file.metadata()
247                .map_err(|error| SegmentError::io(path, error))?
248                .len(),
249        )
250        .map_err(|_| SegmentError::Geometry("mapped file length exceeds usize".to_owned()))?;
251        if length == 0 {
252            return Err(FormatError::new(
253                path.display().to_string(),
254                FormatCheck::Length,
255                "empty segment file",
256            )
257            .into());
258        }
259        // SAFETY: `file` is an open regular-file descriptor, length is non-zero,
260        // and the mapping is read-only/private. The mapping owns its lifetime and
261        // is released exactly once in `Drop`; closing the descriptor is permitted.
262        let mapped = unsafe {
263            libc::mmap(
264                std::ptr::null_mut(),
265                length,
266                libc::PROT_READ,
267                libc::MAP_PRIVATE,
268                file.as_raw_fd(),
269                0,
270            )
271        };
272        if mapped == libc::MAP_FAILED {
273            return Err(SegmentError::io(path, std::io::Error::last_os_error()));
274        }
275        let pointer = NonNull::new(mapped.cast::<u8>()).ok_or_else(|| {
276            SegmentError::Geometry("mmap returned a null non-failure pointer".to_owned())
277        })?;
278        Ok(Self {
279            _file: file,
280            pointer,
281            length,
282        })
283    }
284
285    fn as_bytes(&self) -> &[u8] {
286        // SAFETY: the read-only mapping is valid for `length` bytes and remains
287        // alive for the returned borrow through `&self`.
288        unsafe { std::slice::from_raw_parts(self.pointer.as_ptr(), self.length) }
289    }
290
291    /// Exact virtual byte length of this mapping. Never a residency figure.
292    const fn length(&self) -> usize {
293        self.length
294    }
295
296    /// Bytes of this mapping whose intersecting pages are actually resident.
297    fn resident_bytes(&self) -> std::io::Result<u64> {
298        crate::sys::memory::mincore_resident_bytes(self.as_bytes())
299    }
300
301    /// Flips `mask` into one byte of the private mapping through copy-on-write,
302    /// leaving the file untouched. Test support only: it models bit rot under a
303    /// reader that already validated the page, deterministically on every
304    /// platform (a file write is not visible through a private mapping on
305    /// macOS). `&mut self` proves no `as_bytes` borrow is live during the write.
306    #[cfg(any(test, feature = "test-support"))]
307    fn corrupt_byte(&mut self, offset: usize, mask: u8) -> std::io::Result<()> {
308        if offset >= self.length {
309            return Err(std::io::Error::other(
310                "corruption offset is outside the mapping",
311            ));
312        }
313        let page_size_raw = unsafe {
314            // SAFETY: `_SC_PAGESIZE` takes no pointer arguments and has no preconditions.
315            libc::sysconf(libc::_SC_PAGESIZE)
316        };
317        let page_size = usize::try_from(page_size_raw)
318            .ok()
319            .filter(|size| *size != 0)
320            .ok_or_else(|| std::io::Error::other("sysconf returned an invalid page size"))?;
321        let page_offset = offset - offset % page_size;
322        let page = self
323            .pointer
324            .as_ptr()
325            .wrapping_add(page_offset)
326            .cast::<libc::c_void>();
327        // SAFETY: `page` is the page-aligned start of a page inside this live
328        // private mapping, so the kernel may grant copy-on-write access to it.
329        if unsafe { libc::mprotect(page, page_size, libc::PROT_READ | libc::PROT_WRITE) } != 0 {
330            return Err(std::io::Error::last_os_error());
331        }
332        // SAFETY: `offset < length` keeps the byte inside the mapping, the page
333        // is writable, and `&mut self` guarantees no shared view of the bytes.
334        unsafe {
335            let byte = self.pointer.as_ptr().add(offset);
336            byte.write(byte.read() ^ mask);
337        }
338        // SAFETY: the same page range as above, returned to read-only.
339        if unsafe { libc::mprotect(page, page_size, libc::PROT_READ) } != 0 {
340            return Err(std::io::Error::last_os_error());
341        }
342        Ok(())
343    }
344}
345
346#[cfg(unix)]
347impl Drop for MappedFile {
348    fn drop(&mut self) {
349        // SAFETY: this is the exact pointer/length pair returned by successful
350        // `mmap`, and `Drop` runs once for the sole mapping owner.
351        let _ = unsafe { libc::munmap(self.pointer.as_ptr().cast(), self.length) };
352    }
353}
354
355// SAFETY: the mapping is immutable for its entire lifetime.
356#[cfg(unix)]
357unsafe impl Send for MappedFile {}
358// SAFETY: all shared access exposes read-only slices.
359#[cfg(unix)]
360unsafe impl Sync for MappedFile {}
361
362/// Windows read-only mapping, delegating to the platform boundary.
363///
364/// The engine's algorithms never see a Win32 handle: `sys::windows` owns the
365/// view, section and file, and releases them in that order. The `File` the VFS
366/// supplied is taken rather than reopened, so crash and fault filesystems keep
367/// controlling what is mapped, and a retired path cannot be re-resolved to a
368/// different file underneath a reader.
369#[cfg(windows)]
370struct MappedFile {
371    inner: crate::sys::windows::FileMapping,
372}
373
374#[cfg(windows)]
375impl MappedFile {
376    fn open(file: File, path: &Path) -> Result<Self, SegmentError> {
377        let length = file
378            .metadata()
379            .map_err(|error| SegmentError::io(path, error))?
380            .len();
381        if length == 0 {
382            return Err(FormatError::new(
383                path.display().to_string(),
384                FormatCheck::Length,
385                "empty segment file",
386            )
387            .into());
388        }
389        let inner = crate::sys::windows::FileMapping::from_file(file, length)
390            .map_err(|error| SegmentError::io(path, error))?;
391        Ok(Self { inner })
392    }
393
394    fn as_bytes(&self) -> &[u8] {
395        self.inner.as_bytes()
396    }
397
398    /// Exact virtual byte length of this mapping. Never a residency figure.
399    const fn length(&self) -> usize {
400        self.inner.length()
401    }
402
403    /// Bytes of this mapping whose intersecting pages are actually resident,
404    /// per `QueryWorkingSetEx`.
405    fn resident_bytes(&self) -> std::io::Result<u64> {
406        self.inner.resident_bytes()
407    }
408
409    /// Flips `mask` into one byte of the private view through copy-on-write,
410    /// leaving the segment file untouched. Test support only.
411    #[cfg(any(test, feature = "test-support"))]
412    fn corrupt_byte(&mut self, offset: usize, mask: u8) -> std::io::Result<()> {
413        self.inner.corrupt_byte(offset, mask)
414    }
415}
416
417impl crate::graph::search::RescoreValidator for SegmentReader {
418    fn validate_rows(&self, rows: &[u32]) -> Result<(), String> {
419        self.validate_rescore_rows(rows).map_err(|source| {
420            format!(
421                "exact scores unavailable for segment {}: {source}",
422                self.meta.id
423            )
424        })
425    }
426}
427
428struct ParsedHeader {
429    meta: SegmentMeta,
430    header_length: usize,
431    entries: Vec<RegionEntry>,
432}
433
434/// Validated read-only memory mapping with lazy region checksum verification.
435pub struct SegmentReader {
436    mapping: MappedFile,
437    meta: SegmentMeta,
438    #[cfg(any(test, feature = "test-support"))]
439    storage_store_directory: PathBuf,
440    header_length: usize,
441    entries: Vec<RegionEntry>,
442    document_versions_validation: OnceLock<Result<(), DocumentVersionValidationError>>,
443    // Set by the query path once the stored-text region has passed its checksum
444    // and every row offset has been walked; the public `stored_text` never
445    // consults it and verifies on every call.
446    stored_text_validated: OnceLock<()>,
447    // Set only by the get path after the stored-metadata region has passed its
448    // checksum and full row-offset walk.
449    stored_metadata_validated: OnceLock<()>,
450    vector_codes_validated: OnceLock<()>,
451    vector_factors_validated: OnceLock<()>,
452    rescore_valid_chunks: Mutex<Box<[u64]>>,
453    query_accounting: Option<Arc<crate::lifecycle::stats::Accounting>>,
454    int8_factors_cache: OnceLock<CachedQueryValue<Arc<Vec<crate::scan::Int8Factors>>>>,
455    postings_cache: OnceLock<CachedQueryValue<Arc<crate::fts::sealed::SealedSegment>>>,
456    columns_cache: OnceLock<CachedQueryValue<Arc<ColumnStore>>>,
457    alive_cache: OnceLock<CachedQueryValue<Arc<AliveSet>>>,
458    // Sealed rows ordered by persisted document identity so an exact revision
459    // resolves by binary search instead of a full row scan.
460    document_version_index_cache: OnceLock<CachedQueryValue<Arc<Box<[u32]>>>>,
461    // Inline cached graph metadata is covered by this reader's exactly
462    // accounted snapshot slot; its heap-backed scratch is charged to Cache.
463    pub(crate) graph_search_cache: crate::lifecycle::graph_cache::SegmentGraphSearchCache,
464    // Query-independent half of the fusion vector ceiling. The enclosure is a
465    // property of this sealed segment's immutable factor or rescore bytes, so
466    // it is walked once per reader and folded with each query's norm after.
467    // Two f64 held inline, covered by the accounted snapshot slot.
468    vector_ceiling_norm_range: OnceLock<crate::graph::search::GraphSegmentNormRange>,
469}
470
471struct CachedQueryValue<T> {
472    value: T,
473    _accounting: Option<crate::lifecycle::stats::AccountedCounter>,
474}
475
476#[derive(Clone, Debug)]
477enum DocumentVersionValidationError {
478    Geometry(String),
479    Checksum,
480}
481
482impl DocumentVersionValidationError {
483    fn into_segment_error(self, segment_id: SegmentId) -> SegmentError {
484        match self {
485            Self::Geometry(detail) => SegmentError::Geometry(detail),
486            Self::Checksum => FormatError::new(
487                format!("segment:{segment_id}:document-versions"),
488                FormatCheck::BlockChecksum,
489                "document-version region checksum mismatch",
490            )
491            .into(),
492        }
493    }
494}
495
496/// Validated mmap-backed opaque metadata rows.
497#[derive(Clone, Copy, Debug)]
498pub struct StoredMetadataRows<'a> {
499    offsets: &'a [u8],
500    bytes: &'a [u8],
501    row_count: usize,
502}
503
504impl<'a> StoredMetadataRows<'a> {
505    /// Returns the number of dense metadata rows.
506    #[must_use]
507    pub const fn row_count(self) -> usize {
508        self.row_count
509    }
510
511    /// Returns one row's original opaque bytes.
512    #[must_use]
513    pub fn row(self, row: usize) -> Option<&'a [u8]> {
514        if row >= self.row_count {
515            return None;
516        }
517        let start_index = row.checked_mul(8)?;
518        let end_index = row.checked_add(1)?.checked_mul(8)?;
519        let start = self
520            .offsets
521            .get(start_index..start_index.checked_add(8)?)?
522            .try_into()
523            .ok()
524            .map(u64::from_le_bytes)
525            .and_then(|value| usize::try_from(value).ok())?;
526        let end = self
527            .offsets
528            .get(end_index..end_index.checked_add(8)?)?
529            .try_into()
530            .ok()
531            .map(u64::from_le_bytes)
532            .and_then(|value| usize::try_from(value).ok())?;
533        self.bytes.get(start..end)
534    }
535}
536
537/// Validated mmap-backed optional UTF-8 source rows.
538#[derive(Clone, Copy, Debug)]
539pub struct StoredTextRows<'a> {
540    present: &'a [u8],
541    offsets: &'a [u8],
542    bytes: &'a [u8],
543    row_count: usize,
544}
545
546impl<'a> StoredTextRows<'a> {
547    /// Returns the number of dense text rows.
548    #[must_use]
549    pub const fn row_count(self) -> usize {
550        self.row_count
551    }
552
553    /// Returns `None` for an invalid row, `Some(None)` for an absent field,
554    /// and `Some(Some(text))` for a present UTF-8 field (including empty text).
555    #[must_use]
556    pub fn row(self, row: usize) -> Option<Option<&'a str>> {
557        if row >= self.row_count {
558            return None;
559        }
560        let end_index = row.checked_mul(8)?;
561        let end = self
562            .offsets
563            .get(end_index..end_index.checked_add(8)?)?
564            .try_into()
565            .ok()
566            .map(u64::from_le_bytes)
567            .and_then(|value| usize::try_from(value).ok())?;
568        let start = if row == 0 {
569            0
570        } else {
571            let start_index = row.checked_sub(1)?.checked_mul(8)?;
572            self.offsets
573                .get(start_index..start_index.checked_add(8)?)?
574                .try_into()
575                .ok()
576                .map(u64::from_le_bytes)
577                .and_then(|value| usize::try_from(value).ok())?
578        };
579        let byte = *self.present.get(row / 8)?;
580        if byte & (1 << (row % 8)) == 0 {
581            return (start == end).then_some(None);
582        }
583        let text = std::str::from_utf8(self.bytes.get(start..end)?).ok()?;
584        Some(Some(text))
585    }
586}
587
588/// Tri-state cache for query-path checksum verification: 0 unset,
589/// 1 disabled, 2 enabled. Read from `ZE_VERIFY_QUERY_CHECKSUMS` once.
590static QUERY_CHECKSUMS: std::sync::atomic::AtomicU8 = std::sync::atomic::AtomicU8::new(0);
591
592/// Forces query-path checksum verification on or off.
593///
594/// Verification is opt-in and off by default, so a test that asserts the
595/// verifying behaviour must turn it on rather than assume it.
596#[cfg(any(test, feature = "test-support"))]
597pub fn set_query_checksum_verification(enabled: bool) {
598    QUERY_CHECKSUMS.store(
599        if enabled { 2 } else { 1 },
600        std::sync::atomic::Ordering::Relaxed,
601    );
602}
603
604impl SegmentReader {
605    /// Memory-maps a segment and validates only its bounded header/directory.
606    pub fn open(vfs: &dyn Vfs, path: &Path, expected_id: SegmentId) -> Result<Self, SegmentError> {
607        let file = vfs
608            .open_for_map(path)
609            .map_err(|error| SegmentError::io(path, error))?;
610        let mapping = MappedFile::open(file, path)?;
611        let artifact = path.display().to_string();
612        let parsed = parse_segment_header(
613            &artifact,
614            mapping.as_bytes(),
615            mapping.length() as u64,
616            expected_id,
617        )?;
618        let rescore_valid_chunks = rescore_validation_words(&parsed.entries)?;
619        Ok(Self {
620            mapping,
621            meta: parsed.meta,
622            #[cfg(any(test, feature = "test-support"))]
623            storage_store_directory: path.parent().unwrap_or(Path::new("")).to_path_buf(),
624            header_length: parsed.header_length,
625            entries: parsed.entries,
626            document_versions_validation: OnceLock::new(),
627            stored_text_validated: OnceLock::new(),
628            stored_metadata_validated: OnceLock::new(),
629            vector_codes_validated: OnceLock::new(),
630            vector_factors_validated: OnceLock::new(),
631            rescore_valid_chunks: Mutex::new(vec![0_u64; rescore_valid_chunks].into_boxed_slice()),
632            query_accounting: None,
633            int8_factors_cache: OnceLock::new(),
634            postings_cache: OnceLock::new(),
635            columns_cache: OnceLock::new(),
636            alive_cache: OnceLock::new(),
637            document_version_index_cache: OnceLock::new(),
638            graph_search_cache: crate::lifecycle::graph_cache::SegmentGraphSearchCache::new(),
639            vector_ceiling_norm_range: OnceLock::new(),
640        })
641    }
642
643    pub(crate) fn open_accounted(
644        vfs: &dyn Vfs,
645        path: &Path,
646        expected: &SegmentMeta,
647        accounting: &Arc<crate::lifecycle::stats::Accounting>,
648        mut before_reader_allocation: impl FnMut(usize) -> Result<(), crate::lifecycle::StoreError>,
649    ) -> Result<Self, crate::lifecycle::StoreError> {
650        let file = vfs
651            .open_for_map(path)
652            .map_err(|error| SegmentError::io(path, error))
653            .map_err(crate::lifecycle::StoreError::Segment)?;
654        let mapping =
655            MappedFile::open(file, path).map_err(crate::lifecycle::StoreError::Segment)?;
656        let artifact = path.display().to_string();
657        let region_count =
658            preflight_region_count(&artifact, mapping.as_bytes(), mapping.length() as u64)
659                .map_err(crate::lifecycle::StoreError::Segment)?;
660        let directory_bytes = region_count
661            .checked_mul(std::mem::size_of::<RegionEntry>())
662            .ok_or(crate::lifecycle::StoreError::BudgetExceeded {
663                needed: u64::MAX,
664                budget: u64::MAX,
665                component: "snapshot",
666            })?;
667        before_reader_allocation(directory_bytes)?;
668        let parsed = parse_segment_header(
669            &artifact,
670            mapping.as_bytes(),
671            mapping.length() as u64,
672            expected.id,
673        )
674        .map_err(crate::lifecycle::StoreError::Segment)?;
675        if !parsed.meta.same_segment_file(expected) {
676            return Err(crate::lifecycle::StoreError::Segment(
677                SegmentError::Geometry(format!(
678                    "manifest metadata {expected:?}, mapped header metadata {:?}",
679                    parsed.meta
680                )),
681            ));
682        }
683        let rescore_valid_chunks = rescore_validation_words(&parsed.entries)
684            .map_err(crate::lifecycle::StoreError::Segment)?;
685        let validation_bytes = rescore_valid_chunks
686            .checked_mul(std::mem::size_of::<u64>())
687            .ok_or(crate::lifecycle::StoreError::BudgetExceeded {
688                needed: u64::MAX,
689                budget: u64::MAX,
690                component: "snapshot",
691            })?;
692        before_reader_allocation(validation_bytes)?;
693        Ok(Self {
694            mapping,
695            meta: expected.clone(),
696            #[cfg(any(test, feature = "test-support"))]
697            storage_store_directory: path.parent().unwrap_or(Path::new("")).to_path_buf(),
698            header_length: parsed.header_length,
699            entries: parsed.entries,
700            document_versions_validation: OnceLock::new(),
701            stored_text_validated: OnceLock::new(),
702            stored_metadata_validated: OnceLock::new(),
703            vector_codes_validated: OnceLock::new(),
704            vector_factors_validated: OnceLock::new(),
705            rescore_valid_chunks: Mutex::new(vec![0_u64; rescore_valid_chunks].into_boxed_slice()),
706            query_accounting: Some(Arc::clone(accounting)),
707            int8_factors_cache: OnceLock::new(),
708            postings_cache: OnceLock::new(),
709            columns_cache: OnceLock::new(),
710            alive_cache: OnceLock::new(),
711            document_version_index_cache: OnceLock::new(),
712            graph_search_cache: crate::lifecycle::graph_cache::SegmentGraphSearchCache::new(),
713            vector_ceiling_norm_range: OnceLock::new(),
714        })
715    }
716
717    /// Returns immutable manifest-visible metadata decoded from the header.
718    #[must_use]
719    pub const fn meta(&self) -> &SegmentMeta {
720        &self.meta
721    }
722
723    /// Returns exact header bytes touched by an O(manifest) open.
724    #[must_use]
725    pub const fn header_length(&self) -> usize {
726        self.header_length
727    }
728
729    /// Returns the exact virtual byte length of this immutable file mapping.
730    #[must_use]
731    pub(crate) const fn mapped_bytes(&self) -> usize {
732        self.mapping.length()
733    }
734
735    /// Returns mapped bytes whose intersecting pages are resident per `mincore`.
736    pub(crate) fn mapped_resident_bytes(&self) -> std::io::Result<u64> {
737        self.mapping.resident_bytes()
738    }
739
740    #[cfg(test)]
741    pub(crate) fn retained_validation_bytes(&self) -> usize {
742        self.rescore_valid_chunks
743            .lock()
744            .map_or(0, |words| std::mem::size_of_val(words.as_ref()))
745    }
746
747    /// Flips `mask` into one mapped byte through copy-on-write, leaving the
748    /// segment file untouched, so a test can corrupt what an already-validated
749    /// reader sees. `&mut self` guarantees no region view is live meanwhile.
750    #[cfg(any(test, feature = "test-support"))]
751    #[doc(hidden)]
752    pub fn corrupt_mapped_byte_for_test(&mut self, offset: usize, mask: u8) -> std::io::Result<()> {
753        self.mapping.corrupt_byte(offset, mask)
754    }
755
756    #[cfg(any(test, feature = "test-support"))]
757    #[doc(hidden)]
758    pub fn retained_query_view_bytes(&self) -> u64 {
759        let int8_factors = self.int8_factors_cache.get().and_then(|cached| {
760            cached
761                .value
762                .capacity()
763                .checked_mul(std::mem::size_of::<crate::scan::Int8Factors>())
764                .and_then(arc_resident_bytes::<Vec<crate::scan::Int8Factors>>)
765        });
766        let postings = self.postings_cache.get().and_then(|cached| {
767            cached
768                .value
769                .resident_bytes()
770                .ok()
771                .and_then(arc_resident_bytes::<crate::fts::sealed::SealedSegment>)
772        });
773        let columns = self.columns_cache.get().and_then(|cached| {
774            cached
775                .value
776                .resident_bytes()
777                .and_then(arc_resident_bytes::<ColumnStore>)
778        });
779        let alive = self.alive_cache.get().and_then(|cached| {
780            cached
781                .value
782                .resident_bytes()
783                .and_then(arc_resident_bytes::<AliveSet>)
784        });
785        let document_version_index = self.document_version_index_cache.get().and_then(|cached| {
786            cached
787                .value
788                .len()
789                .checked_mul(std::mem::size_of::<u32>())
790                .and_then(arc_resident_bytes::<Box<[u32]>>)
791        });
792        int8_factors
793            .into_iter()
794            .chain(postings)
795            .chain(columns)
796            .chain(alive)
797            .chain(document_version_index)
798            .fold(0_u64, |total, bytes| {
799                total.saturating_add(u64::try_from(bytes).unwrap_or(u64::MAX))
800            })
801    }
802
803    /// Returns the validated region directory, including unknown skippable kinds.
804    #[must_use]
805    pub fn directory(&self) -> &[RegionEntry] {
806        &self.entries
807    }
808
809    /// Returns unknown region ids without treating them as corruption.
810    #[must_use]
811    pub fn unknown_region_ids(&self) -> Vec<u16> {
812        self.entries
813            .iter()
814            .filter_map(|entry| {
815                RegionKind::from_id(entry.kind)
816                    .is_none()
817                    .then_some(entry.kind)
818            })
819            .collect()
820    }
821
822    /// Validates a complete region and returns its original mmap-backed bytes.
823    pub fn region(&self, kind: RegionKind) -> Result<&[u8], SegmentError> {
824        let entry = self.entry(kind)?;
825        let bytes = self.region_slice(entry)?;
826        let actual = region_hash(kind, bytes);
827        if actual != entry.checksum {
828            #[cfg(any(test, feature = "test-support"))]
829            crate::lifecycle::record_storage_segment_checksum_fault(
830                &self.storage_store_directory,
831                self.meta.id,
832                kind,
833                0,
834                entry.checksum,
835                actual,
836            );
837            return Err(FormatError::checksum_mismatch(
838                format!("segment:{}:{kind:?}", self.meta.id),
839                FormatCheck::BlockChecksum,
840                entry.checksum,
841                actual,
842            )
843            .into());
844        }
845        Ok(bytes)
846    }
847
848    /// Validates and returns one source region by its numeric directory kind.
849    pub(crate) fn region_by_id(&self, kind: u16) -> Result<&[u8], SegmentError> {
850        let entry = self
851            .entries
852            .iter()
853            .find(|entry| entry.kind == kind)
854            .ok_or_else(|| {
855                SegmentError::Geometry(format!("segment is missing region kind {kind}"))
856            })?;
857        let bytes = self.region_slice(entry)?;
858        let actual = xxh3_64(bytes);
859        if actual != entry.checksum {
860            return Err(FormatError::checksum_mismatch(
861                format!("segment:{}:region-{kind}", self.meta.id),
862                FormatCheck::BlockChecksum,
863                entry.checksum,
864                actual,
865            )
866            .into());
867        }
868        Ok(bytes)
869    }
870
871    /// Validates one 64-KB chunk and returns only that mmap-backed chunk.
872    pub fn region_chunk(&self, kind: RegionKind, chunk_index: u32) -> Result<&[u8], SegmentError> {
873        let entry = self.entry(kind)?;
874        let region = self.region_slice(entry)?;
875        let start = (chunk_index as usize)
876            .checked_mul(CHECKSUM_CHUNK_BYTES)
877            .ok_or_else(|| SegmentError::Geometry("chunk offset overflow".to_owned()))?;
878        let end = start.saturating_add(CHECKSUM_CHUNK_BYTES).min(region.len());
879        let chunk = region.get(start..end).ok_or_else(|| {
880            SegmentError::Geometry(format!("chunk {chunk_index} is outside {kind:?}"))
881        })?;
882        if chunk.is_empty() {
883            return Err(SegmentError::Geometry(format!(
884                "chunk {chunk_index} is outside {kind:?}"
885            )));
886        }
887        let expected = self.chunk_checksum(kind, chunk_index)?;
888        let actual = region_hash(kind, chunk);
889        if actual != expected {
890            #[cfg(any(test, feature = "test-support"))]
891            crate::lifecycle::record_storage_segment_checksum_fault(
892                &self.storage_store_directory,
893                self.meta.id,
894                kind,
895                chunk_index,
896                expected,
897                actual,
898            );
899            return Err(FormatError::checksum_mismatch(
900                format!("segment:{}:{kind:?}:chunk-{chunk_index}", self.meta.id),
901                FormatCheck::BlockChecksum,
902                expected,
903                actual,
904            )
905            .into());
906        }
907        Ok(chunk)
908    }
909
910    /// Returns packed Bit4 code bytes exactly as passed to the batch kernel.
911    pub fn bit4_codes(&self) -> Result<&[u8], SegmentError> {
912        let (header, payload) = self.vector_payload(RegionKind::VectorCodes)?;
913        self.bit4_codes_from(header, payload)
914    }
915
916    fn bit4_codes_unchecked(&self) -> Result<&[u8], SegmentError> {
917        let (header, payload) = self.vector_payload_unchecked(RegionKind::VectorCodes)?;
918        self.bit4_codes_from(header, payload)
919    }
920
921    fn bit4_codes_from<'a>(
922        &'a self,
923        header: super::layout::VectorHeader,
924        payload: &'a [u8],
925    ) -> Result<&'a [u8], SegmentError> {
926        if self.meta.scheme != 4 {
927            return Err(SegmentError::Geometry(format!(
928                "Bit4 codes requested for scheme {}",
929                self.meta.scheme
930            )));
931        }
932        let expected = (self.meta.dims as usize)
933            .div_ceil(2)
934            .checked_mul(self.meta.row_count as usize)
935            .ok_or_else(|| SegmentError::Geometry("Bit4 code length overflow".to_owned()))?;
936        if header.row_stride_bytes as usize != (self.meta.dims as usize).div_ceil(2)
937            || payload.len() != expected
938        {
939            return Err(SegmentError::Geometry(format!(
940                "Bit4 code stride/length {}/{}, expected {}/{}",
941                header.row_stride_bytes,
942                payload.len(),
943                (self.meta.dims as usize).div_ceil(2),
944                expected
945            )));
946        }
947        Ok(payload)
948    }
949
950    /// Casts validated full-precision code rows directly from the mapping.
951    pub fn f32_codes(&self) -> Result<&[f32], SegmentError> {
952        let (header, payload) = self.vector_payload(RegionKind::VectorCodes)?;
953        self.f32_codes_from(header, payload)
954    }
955
956    /// Validate-once twin of [`Self::f32_codes`].
957    pub(crate) fn query_f32_codes(&self) -> Result<&[f32], SegmentError> {
958        self.validate_vector_region_once(RegionKind::VectorCodes, &self.vector_codes_validated)?;
959        let (header, payload) = self.vector_payload_unchecked(RegionKind::VectorCodes)?;
960        self.f32_codes_from(header, payload)
961    }
962
963    fn f32_codes_from<'a>(
964        &'a self,
965        header: super::layout::VectorHeader,
966        payload: &'a [u8],
967    ) -> Result<&'a [f32], SegmentError> {
968        if self.meta.scheme != 0 {
969            return Err(SegmentError::Geometry(format!(
970                "F32 codes requested for scheme {}",
971                self.meta.scheme
972            )));
973        }
974        let expected = (self.meta.dims as usize)
975            .checked_mul(self.meta.row_count as usize)
976            .ok_or_else(|| SegmentError::Geometry("F32 code length overflow".to_owned()))?;
977        let expected_bytes = expected
978            .checked_mul(std::mem::size_of::<f32>())
979            .ok_or_else(|| SegmentError::Geometry("F32 code byte length overflow".to_owned()))?;
980        let expected_stride = (self.meta.dims as usize)
981            .checked_mul(std::mem::size_of::<f32>())
982            .ok_or_else(|| SegmentError::Geometry("F32 code stride overflow".to_owned()))?;
983        if header.row_stride_bytes as usize != expected_stride || payload.len() != expected_bytes {
984            return Err(SegmentError::Geometry(format!(
985                "F32 code stride/length {}/{}, expected {expected_stride}/{expected_bytes}",
986                header.row_stride_bytes,
987                payload.len()
988            )));
989        }
990        cast_slice::<f32>(payload, expected, "F32 codes")
991    }
992
993    /// Casts signed-byte vector codes directly from the validated mmap region.
994    pub fn int8_codes(&self) -> Result<&[i8], SegmentError> {
995        let (header, payload) = self.vector_payload(RegionKind::VectorCodes)?;
996        self.int8_codes_from(header, payload)
997    }
998
999    fn int8_codes_unchecked(&self) -> Result<&[i8], SegmentError> {
1000        let (header, payload) = self.vector_payload_unchecked(RegionKind::VectorCodes)?;
1001        self.int8_codes_from(header, payload)
1002    }
1003
1004    fn int8_codes_from<'a>(
1005        &'a self,
1006        header: super::layout::VectorHeader,
1007        payload: &'a [u8],
1008    ) -> Result<&'a [i8], SegmentError> {
1009        if self.meta.scheme != 2 {
1010            return Err(SegmentError::Geometry(format!(
1011                "Int8 codes requested for scheme {}",
1012                self.meta.scheme
1013            )));
1014        }
1015        let expected = (self.meta.dims as usize)
1016            .checked_mul(self.meta.row_count as usize)
1017            .ok_or_else(|| SegmentError::Geometry("Int8 code length overflow".to_owned()))?;
1018        if header.row_stride_bytes as usize != self.meta.dims as usize || payload.len() != expected
1019        {
1020            return Err(SegmentError::Geometry(format!(
1021                "Int8 code stride/length {}/{}, expected {}/{}",
1022                header.row_stride_bytes,
1023                payload.len(),
1024                self.meta.dims,
1025                expected
1026            )));
1027        }
1028        cast_slice::<i8>(payload, expected, "Int8 codes")
1029    }
1030
1031    /// Casts the validated factor region directly to permanent Bit4 records.
1032    pub fn bit4_factors(&self) -> Result<&[Bit4Factors], SegmentError> {
1033        let (header, payload) = self.vector_payload(RegionKind::VectorFactors)?;
1034        self.bit4_factors_from(header, payload)
1035    }
1036
1037    fn bit4_factors_unchecked(&self) -> Result<&[Bit4Factors], SegmentError> {
1038        let (header, payload) = self.vector_payload_unchecked(RegionKind::VectorFactors)?;
1039        self.bit4_factors_from(header, payload)
1040    }
1041
1042    fn bit4_factors_from<'a>(
1043        &'a self,
1044        header: super::layout::VectorHeader,
1045        payload: &'a [u8],
1046    ) -> Result<&'a [Bit4Factors], SegmentError> {
1047        if self.meta.scheme != 4 {
1048            return Err(SegmentError::Geometry(format!(
1049                "Bit4 factors requested for scheme {}",
1050                self.meta.scheme
1051            )));
1052        }
1053        if header.factor_stride_bytes != 12 {
1054            return Err(SegmentError::Geometry(format!(
1055                "Bit4 factor stride {}, expected 12",
1056                header.factor_stride_bytes
1057            )));
1058        }
1059        cast_slice::<Bit4Factors>(payload, self.meta.row_count as usize, "Bit4 factors")
1060    }
1061
1062    /// Casts a validated Int8 factor region directly to permanent records.
1063    pub fn int8_factors(&self) -> Result<&[Int8Factors], SegmentError> {
1064        let (header, payload) = self.vector_payload(RegionKind::VectorFactors)?;
1065        self.int8_factors_from(header, payload)
1066    }
1067
1068    fn int8_factors_unchecked(&self) -> Result<&[Int8Factors], SegmentError> {
1069        let (header, payload) = self.vector_payload_unchecked(RegionKind::VectorFactors)?;
1070        self.int8_factors_from(header, payload)
1071    }
1072
1073    fn int8_factors_from<'a>(
1074        &'a self,
1075        header: super::layout::VectorHeader,
1076        payload: &'a [u8],
1077    ) -> Result<&'a [Int8Factors], SegmentError> {
1078        if self.meta.scheme != 2 {
1079            return Err(SegmentError::Geometry(format!(
1080                "Int8 factors requested for scheme {}",
1081                self.meta.scheme
1082            )));
1083        }
1084        if header.factor_stride_bytes != 8 {
1085            return Err(SegmentError::Geometry(format!(
1086                "Int8 factor stride {}, expected 8",
1087                header.factor_stride_bytes
1088            )));
1089        }
1090        #[cfg(any(test, feature = "test-support"))]
1091        account_region_decode(RegionKind::VectorFactors, payload.len());
1092        cast_slice::<Int8Factors>(payload, self.meta.row_count as usize, "Int8 factors")
1093    }
1094
1095    /// Reports whether query paths verify region checksums at all.
1096    ///
1097    /// Owner decision 2026-09-04: verification is opt-in and off by
1098    /// default. A sealed segment is immutable and its checksums are
1099    /// written and verified at seal; re-verifying at query time defends
1100    /// only against on-disk corruption after publication, which is what
1101    /// `Store::health()` and the diagnostics paths are for. Those paths
1102    /// still verify unconditionally. Set `ZE_VERIFY_QUERY_CHECKSUMS=1`
1103    /// to restore per-reader verification on the query path.
1104    fn query_checksums_enabled() -> bool {
1105        match QUERY_CHECKSUMS.load(std::sync::atomic::Ordering::Relaxed) {
1106            0 => {
1107                let enabled =
1108                    std::env::var_os("ZE_VERIFY_QUERY_CHECKSUMS").is_some_and(|value| value != "0");
1109                QUERY_CHECKSUMS.store(
1110                    if enabled { 2 } else { 1 },
1111                    std::sync::atomic::Ordering::Relaxed,
1112                );
1113                enabled
1114            }
1115            1 => false,
1116            _ => true,
1117        }
1118    }
1119
1120    /// Verifies a vector region's checksum once per reader, then serves it
1121    /// from the mapping without re-hashing.
1122    ///
1123    /// The verifying accessors re-hash the whole region on every call. On
1124    /// a query path that is ruinous: hybrid cross-fill called the
1125    /// verifying rescore accessor once per cross-filled document and
1126    /// spent 219 ms of a 221 ms query re-hashing 181 MB. Query paths use
1127    /// these twins; validation, diagnostics and maintenance keep the
1128    /// verifying accessors.
1129    fn validate_vector_region_once(
1130        &self,
1131        kind: RegionKind,
1132        gate: &OnceLock<()>,
1133    ) -> Result<(), SegmentError> {
1134        if gate.get().is_some() || !Self::query_checksums_enabled() {
1135            return Ok(());
1136        }
1137        let _ = self.region(kind)?;
1138        let _ = gate.set(());
1139        Ok(())
1140    }
1141
1142    /// Validate-once twin of [`Self::bit4_codes`].
1143    pub(crate) fn query_bit4_codes(&self) -> Result<&[u8], SegmentError> {
1144        self.validate_vector_region_once(RegionKind::VectorCodes, &self.vector_codes_validated)?;
1145        self.bit4_codes_unchecked()
1146    }
1147
1148    /// Validate-once twin of [`Self::int8_codes`].
1149    pub(crate) fn query_int8_codes(&self) -> Result<&[i8], SegmentError> {
1150        self.validate_vector_region_once(RegionKind::VectorCodes, &self.vector_codes_validated)?;
1151        self.int8_codes_unchecked()
1152    }
1153
1154    /// Validate-once twin of [`Self::int8_factors`] returning the raw slice.
1155    pub(crate) fn query_int8_factors_slice(&self) -> Result<&[Int8Factors], SegmentError> {
1156        self.validate_vector_region_once(
1157            RegionKind::VectorFactors,
1158            &self.vector_factors_validated,
1159        )?;
1160        self.int8_factors_unchecked()
1161    }
1162
1163    /// Returns this reader's remembered query-independent norm enclosure.
1164    ///
1165    /// `None` means no query has walked the region yet. The enclosure is
1166    /// derived only from immutable sealed bytes, so a remembered value is the
1167    /// same value any later walk would produce.
1168    pub(crate) fn cached_vector_ceiling_norm_range(
1169        &self,
1170    ) -> Option<crate::graph::search::GraphSegmentNormRange> {
1171        self.vector_ceiling_norm_range.get().copied()
1172    }
1173
1174    /// Remembers the enclosure a query walked out of this segment's bytes.
1175    pub(crate) fn remember_vector_ceiling_norm_range(
1176        &self,
1177        range: crate::graph::search::GraphSegmentNormRange,
1178    ) {
1179        if self.vector_ceiling_norm_range.set(range).is_err() {
1180            // A concurrent walk won. It read the same immutable bytes with the
1181            // same arithmetic, so its enclosure is this enclosure.
1182        }
1183    }
1184
1185    /// Validate-once twin of [`Self::bit4_factors`].
1186    pub(crate) fn query_bit4_factors(&self) -> Result<&[Bit4Factors], SegmentError> {
1187        self.validate_vector_region_once(
1188            RegionKind::VectorFactors,
1189            &self.vector_factors_validated,
1190        )?;
1191        self.bit4_factors_unchecked()
1192    }
1193
1194    pub(crate) fn query_int8_factors(
1195        &self,
1196    ) -> Result<Arc<Vec<crate::scan::Int8Factors>>, crate::lifecycle::StoreError> {
1197        if let Some(cached) = self.int8_factors_cache.get() {
1198            return Ok(Arc::clone(&cached.value));
1199        }
1200        let factors = self
1201            .int8_factors()
1202            .map_err(crate::lifecycle::StoreError::Segment)?
1203            .iter()
1204            .map(|factor| crate::scan::Int8Factors::new(factor.scale, factor.offset))
1205            .collect::<Result<Vec<_>, _>>()
1206            .map_err(|_| {
1207                crate::lifecycle::StoreError::Segment(SegmentError::Geometry(
1208                    "Int8 factor is not finite and non-negative".to_owned(),
1209                ))
1210            })?;
1211        let resident_bytes = factors
1212            .capacity()
1213            .checked_mul(std::mem::size_of::<crate::scan::Int8Factors>())
1214            .and_then(arc_resident_bytes::<Vec<crate::scan::Int8Factors>>)
1215            .ok_or(crate::lifecycle::StoreError::BudgetExceeded {
1216                needed: u64::MAX,
1217                budget: u64::MAX,
1218                component: "snapshot",
1219            })?;
1220        let cached = CachedQueryValue {
1221            value: Arc::new(factors),
1222            _accounting: self.account_query_cache(resident_bytes)?,
1223        };
1224        if self.int8_factors_cache.set(cached).is_err() {
1225            // A concurrent initializer won. Its value and reservation are authoritative.
1226        }
1227        self.int8_factors_cache
1228            .get()
1229            .map(|cached| Arc::clone(&cached.value))
1230            .ok_or(crate::lifecycle::StoreError::Synchronization {
1231                component: "Int8 factors query cache",
1232            })
1233    }
1234
1235    /// Casts validated f32 exact-rescore rows directly from the mmap.
1236    pub fn rescore_f32(&self) -> Result<&[f32], SegmentError> {
1237        let (header, payload) = self.vector_payload(RegionKind::VectorRescore)?;
1238        if header.scheme != 0 {
1239            return Err(SegmentError::Geometry(format!(
1240                "v1 rescore scheme must be F32/0, got {}",
1241                header.scheme
1242            )));
1243        }
1244        let count = (self.meta.row_count as usize)
1245            .checked_mul(self.meta.dims as usize)
1246            .ok_or_else(|| SegmentError::Geometry("rescore count overflow".to_owned()))?;
1247        cast_slice::<f32>(payload, count, "f32 rescore")
1248    }
1249
1250    pub(crate) fn query_rescore_f32(&self) -> Result<&[f32], SegmentError> {
1251        self.validate_rescore_byte_range(0, VECTOR_HEADER_LEN)?;
1252        let (header, payload) = self.vector_payload_unchecked(RegionKind::VectorRescore)?;
1253        if header.scheme != 0 {
1254            return Err(SegmentError::Geometry(format!(
1255                "v1 rescore scheme must be F32/0, got {}",
1256                header.scheme
1257            )));
1258        }
1259        let count = (self.meta.row_count as usize)
1260            .checked_mul(self.meta.dims as usize)
1261            .ok_or_else(|| SegmentError::Geometry("rescore count overflow".to_owned()))?;
1262        cast_slice::<f32>(payload, count, "f32 rescore")
1263    }
1264
1265    pub(crate) fn validate_rescore_rows(&self, rows: &[u32]) -> Result<(), SegmentError> {
1266        let row_bytes = (self.meta.dims as usize)
1267            .checked_mul(std::mem::size_of::<f32>())
1268            .ok_or_else(|| SegmentError::Geometry("rescore row byte length overflow".to_owned()))?;
1269        for row in rows {
1270            if *row >= self.meta.row_count {
1271                return Err(SegmentError::Geometry(format!(
1272                    "rescore row {row} is outside {} rows",
1273                    self.meta.row_count
1274                )));
1275            }
1276            let start = (*row as usize)
1277                .checked_mul(row_bytes)
1278                .and_then(|offset| offset.checked_add(VECTOR_HEADER_LEN))
1279                .ok_or_else(|| SegmentError::Geometry("rescore row offset overflow".to_owned()))?;
1280            self.validate_rescore_byte_range(start, row_bytes)?;
1281        }
1282        Ok(())
1283    }
1284
1285    /// Decodes the checksummed metadata region into typed column arrays.
1286    pub fn columns(&self) -> Result<ColumnStore, SegmentError> {
1287        let region = self.region(RegionKind::Columns)?;
1288        #[cfg(any(test, feature = "test-support"))]
1289        account_region_decode(RegionKind::Columns, region.len());
1290        let columns = decode_columns(region)?;
1291        if columns.row_count() != self.meta.row_count {
1292            return Err(SegmentError::Geometry(format!(
1293                "column rows {}, header rows {}",
1294                columns.row_count(),
1295                self.meta.row_count
1296            )));
1297        }
1298        Ok(columns)
1299    }
1300
1301    pub(crate) fn query_columns(&self) -> Result<Arc<ColumnStore>, crate::lifecycle::StoreError> {
1302        if let Some(cached) = self.columns_cache.get() {
1303            return Ok(Arc::clone(&cached.value));
1304        }
1305        let region = self
1306            .region(RegionKind::Columns)
1307            .map_err(crate::lifecycle::StoreError::Segment)?;
1308        #[cfg(any(test, feature = "test-support"))]
1309        account_region_decode(RegionKind::Columns, region.len());
1310        let mut columns = decode_columns(region).map_err(crate::lifecycle::StoreError::Segment)?;
1311        if columns.row_count() != self.meta.row_count {
1312            return Err(crate::lifecycle::StoreError::Segment(
1313                SegmentError::Geometry(format!(
1314                    "column rows {}, header rows {}",
1315                    columns.row_count(),
1316                    self.meta.row_count
1317                )),
1318            ));
1319        }
1320        columns.compact_for_cache();
1321        let resident_bytes = columns
1322            .resident_bytes()
1323            .and_then(arc_resident_bytes::<ColumnStore>)
1324            .ok_or(crate::lifecycle::StoreError::BudgetExceeded {
1325                needed: u64::MAX,
1326                budget: u64::MAX,
1327                component: "snapshot",
1328            })?;
1329        let cached = CachedQueryValue {
1330            value: Arc::new(columns),
1331            _accounting: self.account_query_cache(resident_bytes)?,
1332        };
1333        if self.columns_cache.set(cached).is_err() {
1334            // A concurrent initializer won. Its value and reservation are authoritative.
1335        }
1336        self.columns_cache
1337            .get()
1338            .map(|cached| Arc::clone(&cached.value))
1339            .ok_or(crate::lifecycle::StoreError::Synchronization {
1340                component: "columns query cache",
1341            })
1342    }
1343
1344    /// Decodes the optional whole-segment lexical region.
1345    pub fn postings(&self) -> Result<Option<crate::fts::sealed::SealedSegment>, SegmentError> {
1346        if !self
1347            .entries
1348            .iter()
1349            .any(|entry| entry.kind == RegionKind::Postings.id())
1350        {
1351            return Ok(None);
1352        }
1353        let region = self.region(RegionKind::Postings)?;
1354        #[cfg(any(test, feature = "test-support"))]
1355        account_region_decode(RegionKind::Postings, region.len());
1356        let postings = crate::fts::sealed::SealedSegment::decode_region(region)?;
1357        if postings.row_count() != self.meta.row_count {
1358            return Err(SegmentError::Geometry(format!(
1359                "postings rows {}, header rows {}",
1360                postings.row_count(),
1361                self.meta.row_count
1362            )));
1363        }
1364        Ok(Some(postings))
1365    }
1366
1367    /// Directory identity for already verified lexical payloads. A remapped
1368    /// reader may reuse statistics only after its normal postings validation.
1369    pub(crate) fn lexical_postings_identity(&self) -> Result<(u64, u64), SegmentError> {
1370        let entry = self.entry(RegionKind::Postings)?;
1371        Ok((entry.length, entry.checksum))
1372    }
1373
1374    pub(crate) fn query_postings(
1375        &self,
1376    ) -> Result<Option<Arc<crate::fts::sealed::SealedSegment>>, crate::lifecycle::StoreError> {
1377        if !self
1378            .entries
1379            .iter()
1380            .any(|entry| entry.kind == RegionKind::Postings.id())
1381        {
1382            return Ok(None);
1383        }
1384        if let Some(cached) = self.postings_cache.get() {
1385            return Ok(Some(Arc::clone(&cached.value)));
1386        }
1387        let region = self
1388            .region(RegionKind::Postings)
1389            .map_err(crate::lifecycle::StoreError::Segment)?;
1390        #[cfg(any(test, feature = "test-support"))]
1391        account_region_decode(RegionKind::Postings, region.len());
1392        let postings = crate::fts::sealed::SealedSegment::decode_region(region)
1393            .map_err(SegmentError::from)
1394            .map_err(crate::lifecycle::StoreError::Segment)?;
1395        if postings.row_count() != self.meta.row_count {
1396            return Err(crate::lifecycle::StoreError::Segment(
1397                SegmentError::Geometry(format!(
1398                    "postings rows {}, header rows {}",
1399                    postings.row_count(),
1400                    self.meta.row_count
1401                )),
1402            ));
1403        }
1404        let resident_bytes = postings
1405            .resident_bytes()
1406            .map_err(SegmentError::from)
1407            .map_err(crate::lifecycle::StoreError::Segment)?
1408            .checked_add(std::mem::size_of::<crate::fts::sealed::SealedSegment>())
1409            .and_then(|bytes| bytes.checked_add(2 * std::mem::size_of::<usize>()))
1410            .ok_or(crate::lifecycle::StoreError::BudgetExceeded {
1411                needed: u64::MAX,
1412                budget: u64::MAX,
1413                component: "snapshot",
1414            })?;
1415        let mut cache_accounting = self
1416            .query_accounting
1417            .as_ref()
1418            .map(|accounting| {
1419                crate::lifecycle::stats::AccountedCounter::new(
1420                    accounting,
1421                    crate::lifecycle::stats::AllocationComponent::Snapshot,
1422                )
1423            })
1424            .transpose()?;
1425        if let Some(counter) = cache_accounting.as_mut() {
1426            counter.set(resident_bytes)?;
1427        }
1428        let cached = CachedQueryValue {
1429            value: Arc::new(postings),
1430            _accounting: cache_accounting,
1431        };
1432        if self.postings_cache.set(cached).is_err() {
1433            // A concurrent initializer won. Its value and reservation are authoritative.
1434        }
1435        self.postings_cache
1436            .get()
1437            .map(|cached| Some(Arc::clone(&cached.value)))
1438            .ok_or(crate::lifecycle::StoreError::Synchronization {
1439                component: "postings query cache",
1440            })
1441    }
1442
1443    /// Decodes the checksummed alive/tombstone region.
1444    pub fn alive(&self) -> Result<AliveSet, SegmentError> {
1445        let region = self.region(RegionKind::Alive)?;
1446        #[cfg(any(test, feature = "test-support"))]
1447        account_region_decode(RegionKind::Alive, region.len());
1448        let alive = decode_alive(region)?;
1449        if alive.row_count() != self.meta.row_count {
1450            return Err(SegmentError::Geometry(format!(
1451                "alive rows {}, header rows {}",
1452                alive.row_count(),
1453                self.meta.row_count
1454            )));
1455        }
1456        Ok(alive)
1457    }
1458
1459    pub(crate) fn query_alive(&self) -> Result<Arc<AliveSet>, crate::lifecycle::StoreError> {
1460        if let Some(cached) = self.alive_cache.get() {
1461            return Ok(Arc::clone(&cached.value));
1462        }
1463        let region = self
1464            .region(RegionKind::Alive)
1465            .map_err(crate::lifecycle::StoreError::Segment)?;
1466        #[cfg(any(test, feature = "test-support"))]
1467        account_region_decode(RegionKind::Alive, region.len());
1468        let mut alive = decode_alive(region).map_err(crate::lifecycle::StoreError::Segment)?;
1469        if alive.row_count() != self.meta.row_count {
1470            return Err(crate::lifecycle::StoreError::Segment(
1471                SegmentError::Geometry(format!(
1472                    "alive rows {}, header rows {}",
1473                    alive.row_count(),
1474                    self.meta.row_count
1475                )),
1476            ));
1477        }
1478        alive.compact_for_cache();
1479        let resident_bytes = alive
1480            .resident_bytes()
1481            .and_then(arc_resident_bytes::<AliveSet>)
1482            .ok_or(crate::lifecycle::StoreError::BudgetExceeded {
1483                needed: u64::MAX,
1484                budget: u64::MAX,
1485                component: "snapshot",
1486            })?;
1487        let cached = CachedQueryValue {
1488            value: Arc::new(alive),
1489            _accounting: self.account_query_cache(resident_bytes)?,
1490        };
1491        if self.alive_cache.set(cached).is_err() {
1492            // A concurrent initializer won. Its value and reservation are authoritative.
1493        }
1494        self.alive_cache
1495            .get()
1496            .map(|cached| Arc::clone(&cached.value))
1497            .ok_or(crate::lifecycle::StoreError::Synchronization {
1498                component: "alive query cache",
1499            })
1500    }
1501
1502    /// Resolves the checksum-validated document-version region once, or
1503    /// `None` for segments sealed before the region existed.
1504    fn document_versions_region(&self) -> Result<Option<&[u8]>, SegmentError> {
1505        let Some(entry) = self
1506            .entries
1507            .iter()
1508            .find(|entry| entry.kind == RegionKind::DocumentVersions.id())
1509        else {
1510            return Ok(None);
1511        };
1512        let validation = self.document_versions_validation.get_or_init(|| {
1513            let bytes = self
1514                .region_slice(entry)
1515                .map_err(|error| DocumentVersionValidationError::Geometry(error.to_string()))?;
1516            if region_hash(RegionKind::DocumentVersions, bytes) != entry.checksum {
1517                return Err(DocumentVersionValidationError::Checksum);
1518            }
1519            let expected = (self.meta.row_count as usize)
1520                .checked_mul(24)
1521                .ok_or_else(|| {
1522                    DocumentVersionValidationError::Geometry(
1523                        "document-version length overflow".to_owned(),
1524                    )
1525                })?;
1526            if bytes.len() != expected {
1527                return Err(DocumentVersionValidationError::Geometry(format!(
1528                    "document-version bytes {}, expected {expected}",
1529                    bytes.len()
1530                )));
1531            }
1532            Ok(())
1533        });
1534        if let Err(error) = validation {
1535            return Err(error.clone().into_segment_error(self.meta.id));
1536        }
1537        self.region_slice_unaccounted(entry).map(Some)
1538    }
1539
1540    /// Decodes one optional sealed-row document identity directly from the mapping.
1541    pub fn document_version(&self, row: usize) -> Result<Option<DocumentVersion>, SegmentError> {
1542        let Some(bytes) = self.document_versions_region()? else {
1543            return Ok(None);
1544        };
1545        let start = row
1546            .checked_mul(24)
1547            .ok_or_else(|| SegmentError::Geometry("document-version row overflow".to_owned()))?;
1548        let doc_end = start
1549            .checked_add(16)
1550            .ok_or_else(|| SegmentError::Geometry("document id end overflow".to_owned()))?;
1551        let revision_end = doc_end
1552            .checked_add(8)
1553            .ok_or_else(|| SegmentError::Geometry("revision end overflow".to_owned()))?;
1554        let doc_id = bytes
1555            .get(start..doc_end)
1556            .and_then(|value| value.try_into().ok())
1557            .map(u128::from_le_bytes)
1558            .ok_or_else(|| SegmentError::Geometry(format!("document id row {row} is missing")))?;
1559        let revision = bytes
1560            .get(doc_end..revision_end)
1561            .and_then(|value| value.try_into().ok())
1562            .map(u64::from_le_bytes)
1563            .ok_or_else(|| SegmentError::Geometry(format!("revision row {row} is missing")))?;
1564        Ok(Some(DocumentVersion::new(
1565            DocId::new(doc_id),
1566            Revision::new(revision),
1567        )))
1568    }
1569
1570    /// Finds the sealed row that holds exactly `version`.
1571    ///
1572    /// `None` means the segment predates document versions or holds no row
1573    /// with that exact document id and revision.
1574    pub fn row_for_document_version(
1575        &self,
1576        version: DocumentVersion,
1577    ) -> Result<Option<usize>, SegmentError> {
1578        let Some(bytes) = self.document_versions_region()? else {
1579            return Ok(None);
1580        };
1581        let needle = encode_document_version(version);
1582        Ok(bytes
1583            .chunks_exact(DOCUMENT_VERSION_BYTES)
1584            .position(|entry| entry == needle))
1585    }
1586
1587    /// Finds the sealed row that holds exactly `version` through the cached
1588    /// identity-ordered row permutation, building it on first use.
1589    ///
1590    /// Equal identities resolve to the lowest row, matching a forward scan.
1591    pub(crate) fn query_row_for_document_version(
1592        &self,
1593        version: DocumentVersion,
1594    ) -> Result<Option<usize>, crate::lifecycle::StoreError> {
1595        let Some(bytes) = self
1596            .document_versions_region()
1597            .map_err(crate::lifecycle::StoreError::Segment)?
1598        else {
1599            return Ok(None);
1600        };
1601        let Some(index) = self.query_document_version_index(bytes)? else {
1602            return Ok(None);
1603        };
1604        let needle = encode_document_version(version);
1605        let position =
1606            index.partition_point(|&row| document_version_entry(bytes, row) < needle.as_slice());
1607        Ok(index
1608            .get(position)
1609            .copied()
1610            .filter(|&row| document_version_entry(bytes, row) == needle)
1611            .map(|row| row as usize))
1612    }
1613
1614    /// Finds every live sealed row for `doc_id` through the cached
1615    /// identity-ordered row permutation, building it on first use.
1616    pub(crate) fn query_rows_for_doc_id(
1617        &self,
1618        doc_id: DocId,
1619    ) -> Result<Vec<usize>, crate::lifecycle::StoreError> {
1620        let Some(bytes) = self
1621            .document_versions_region()
1622            .map_err(crate::lifecycle::StoreError::Segment)?
1623        else {
1624            return Ok(Vec::new());
1625        };
1626        let Some(index) = self.query_document_version_index(bytes)? else {
1627            return Ok(Vec::new());
1628        };
1629        let needle = doc_id.get().to_le_bytes();
1630        let start = index.partition_point(|&row| document_id_entry(bytes, row) < needle.as_slice());
1631        let end = index.partition_point(|&row| document_id_entry(bytes, row) <= needle.as_slice());
1632        let matching = index.get(start..end).ok_or_else(|| {
1633            crate::lifecycle::StoreError::Segment(SegmentError::Geometry(
1634                "document-id index range is invalid".to_owned(),
1635            ))
1636        })?;
1637        let alive = self.query_alive()?;
1638        let mut rows = Vec::new();
1639        rows.try_reserve_exact(matching.len()).map_err(|_| {
1640            crate::lifecycle::StoreError::AllocationFailed {
1641                needed: matching
1642                    .len()
1643                    .checked_mul(std::mem::size_of::<usize>())
1644                    .and_then(|bytes| u64::try_from(bytes).ok())
1645                    .unwrap_or(u64::MAX),
1646                component: "document-id rows",
1647            }
1648        })?;
1649        for row in matching {
1650            if alive.is_alive(*row) {
1651                rows.push(*row as usize);
1652            }
1653        }
1654        Ok(rows)
1655    }
1656
1657    fn query_document_version_index(
1658        &self,
1659        bytes: &[u8],
1660    ) -> Result<Option<Arc<Box<[u32]>>>, crate::lifecycle::StoreError> {
1661        if let Some(cached) = self.document_version_index_cache.get() {
1662            return Ok(Some(Arc::clone(&cached.value)));
1663        }
1664        let mut rows: Vec<u32> = (0..self.meta.row_count).collect();
1665        rows.sort_unstable_by(|&left, &right| {
1666            document_version_entry(bytes, left)
1667                .cmp(document_version_entry(bytes, right))
1668                .then(left.cmp(&right))
1669        });
1670        let index = rows.into_boxed_slice();
1671        let resident_bytes = index
1672            .len()
1673            .checked_mul(std::mem::size_of::<u32>())
1674            .and_then(arc_resident_bytes::<Box<[u32]>>)
1675            .ok_or(crate::lifecycle::StoreError::BudgetExceeded {
1676                needed: u64::MAX,
1677                budget: u64::MAX,
1678                component: "snapshot",
1679            })?;
1680        let cached = CachedQueryValue {
1681            value: Arc::new(index),
1682            _accounting: self.account_query_cache(resident_bytes)?,
1683        };
1684        if self.document_version_index_cache.set(cached).is_err() {
1685            // A concurrent initializer won. Its value and reservation are authoritative.
1686        }
1687        self.document_version_index_cache
1688            .get()
1689            .map(|cached| Some(Arc::clone(&cached.value)))
1690            .ok_or(crate::lifecycle::StoreError::Synchronization {
1691                component: "document-version index cache",
1692            })
1693    }
1694
1695    /// Returns validated opaque metadata rows, or `None` for older segments.
1696    pub fn stored_metadata(&self) -> Result<Option<StoredMetadataRows<'_>>, SegmentError> {
1697        let Some(entry) = self
1698            .entries
1699            .iter()
1700            .find(|entry| entry.kind == RegionKind::StoredMetadata.id())
1701        else {
1702            return Ok(None);
1703        };
1704        let region = self.region(RegionKind::StoredMetadata)?;
1705        let declared_rows = region
1706            .get(..4)
1707            .and_then(|value| value.try_into().ok())
1708            .map(u32::from_le_bytes)
1709            .ok_or_else(|| {
1710                SegmentError::Geometry("stored-metadata header is truncated".to_owned())
1711            })?;
1712        let reserved = region
1713            .get(4..8)
1714            .and_then(|value| value.try_into().ok())
1715            .map(u32::from_le_bytes)
1716            .ok_or_else(|| {
1717                SegmentError::Geometry("stored-metadata reserved field is truncated".to_owned())
1718            })?;
1719        if declared_rows != self.meta.row_count || reserved != 0 {
1720            return Err(SegmentError::Geometry(format!(
1721                "stored-metadata rows/reserved {declared_rows}/{reserved}, expected {}/0",
1722                self.meta.row_count
1723            )));
1724        }
1725        let row_count = declared_rows as usize;
1726        let offset_bytes = row_count
1727            .checked_add(1)
1728            .and_then(|count| count.checked_mul(8))
1729            .ok_or_else(|| SegmentError::Geometry("stored-metadata offsets overflow".to_owned()))?;
1730        let offsets_end = 8_usize.checked_add(offset_bytes).ok_or_else(|| {
1731            SegmentError::Geometry("stored-metadata offset end overflow".to_owned())
1732        })?;
1733        let offsets = region.get(8..offsets_end).ok_or_else(|| {
1734            SegmentError::Geometry("stored-metadata offsets are truncated".to_owned())
1735        })?;
1736        let bytes = region.get(offsets_end..).ok_or_else(|| {
1737            SegmentError::Geometry("stored-metadata payload is truncated".to_owned())
1738        })?;
1739        let view = StoredMetadataRows {
1740            offsets,
1741            bytes,
1742            row_count,
1743        };
1744        let first = view
1745            .offsets
1746            .get(..8)
1747            .and_then(|value| value.try_into().ok())
1748            .map(u64::from_le_bytes)
1749            .ok_or_else(|| {
1750                SegmentError::Geometry("stored-metadata first offset is missing".to_owned())
1751            })?;
1752        if first != 0 {
1753            return Err(SegmentError::Geometry(format!(
1754                "stored-metadata first offset is {first}, expected zero"
1755            )));
1756        }
1757        let mut previous = 0_usize;
1758        for row in 0..row_count {
1759            let value = view.row(row).ok_or_else(|| {
1760                SegmentError::Geometry(format!("stored-metadata row {row} is invalid"))
1761            })?;
1762            previous = previous.checked_add(value.len()).ok_or_else(|| {
1763                SegmentError::Geometry("stored-metadata length overflow".to_owned())
1764            })?;
1765        }
1766        if previous != bytes.len() {
1767            return Err(SegmentError::Geometry(format!(
1768                "stored-metadata final offset {previous}, bytes {}",
1769                bytes.len()
1770            )));
1771        }
1772        let _ = entry;
1773        Ok(Some(view))
1774    }
1775
1776    /// Returns validated optional UTF-8 source rows, or `None` for older segments.
1777    ///
1778    /// Every call verifies the region checksum and walks every row offset.
1779    pub fn stored_text(&self) -> Result<Option<StoredTextRows<'_>>, SegmentError> {
1780        let Some(_) = self
1781            .entries
1782            .iter()
1783            .find(|entry| entry.kind == RegionKind::StoredText.id())
1784        else {
1785            return Ok(None);
1786        };
1787        let region = self.region(RegionKind::StoredText)?;
1788        let view = stored_text_view(region, self.meta.row_count)?;
1789        let StoredTextRows {
1790            offsets,
1791            bytes,
1792            row_count,
1793            ..
1794        } = view;
1795        let mut previous = 0_usize;
1796        for row in 0..row_count {
1797            let value = view.row(row).ok_or_else(|| {
1798                SegmentError::Geometry(format!("stored-text row {row} is invalid"))
1799            })?;
1800            let end_index = row.checked_mul(8).ok_or_else(|| {
1801                SegmentError::Geometry("stored-text offset index overflow".to_owned())
1802            })?;
1803            let end = offsets
1804                .get(end_index..end_index + 8)
1805                .and_then(|value| value.try_into().ok())
1806                .map(u64::from_le_bytes)
1807                .and_then(|value| usize::try_from(value).ok())
1808                .ok_or_else(|| {
1809                    SegmentError::Geometry(format!("stored-text offset row {row} is invalid"))
1810                })?;
1811            if end < previous || end > bytes.len() {
1812                return Err(SegmentError::Geometry(format!(
1813                    "stored-text offset row {row} is outside {previous}..={} bytes",
1814                    bytes.len()
1815                )));
1816            }
1817            if value.is_none() && end != previous {
1818                return Err(SegmentError::Geometry(format!(
1819                    "stored-text absent row {row} owns bytes {previous}..{end}"
1820                )));
1821            }
1822            previous = end;
1823        }
1824        if previous != bytes.len() {
1825            return Err(SegmentError::Geometry(format!(
1826                "stored-text final offset {previous}, bytes {}",
1827                bytes.len()
1828            )));
1829        }
1830        Ok(Some(view))
1831    }
1832
1833    /// Query-path twin of [`Self::stored_text`]: the checksum and the full
1834    /// row-offset walk run once per reader, and later calls rebuild the view
1835    /// from the fixed header geometry alone. Like the document-version region,
1836    /// later reads come from the mapping without re-verification. Nothing is
1837    /// retained beyond the validation fact, so there is nothing to account.
1838    pub(crate) fn query_stored_text(&self) -> Result<Option<StoredTextRows<'_>>, SegmentError> {
1839        if self.stored_text_validated.get().is_some() || !Self::query_checksums_enabled() {
1840            let Some(entry) = self
1841                .entries
1842                .iter()
1843                .find(|entry| entry.kind == RegionKind::StoredText.id())
1844            else {
1845                return Ok(None);
1846            };
1847            let region = self.region_slice(entry)?;
1848            return stored_text_view(region, self.meta.row_count).map(Some);
1849        }
1850        let view = self.stored_text()?;
1851        if view.is_some() {
1852            // A concurrent validator may have set this first; same fact either way.
1853            let _ = self.stored_text_validated.set(());
1854        }
1855        Ok(view)
1856    }
1857
1858    /// Query-path twin of [`Self::stored_metadata`]: checksum and row-offset
1859    /// validation run once per reader, then later calls rebuild only the view.
1860    pub(crate) fn query_stored_metadata(
1861        &self,
1862    ) -> Result<Option<StoredMetadataRows<'_>>, SegmentError> {
1863        if self.stored_metadata_validated.get().is_some() || !Self::query_checksums_enabled() {
1864            let Some(entry) = self
1865                .entries
1866                .iter()
1867                .find(|entry| entry.kind == RegionKind::StoredMetadata.id())
1868            else {
1869                return Ok(None);
1870            };
1871            let region = self.region_slice(entry)?;
1872            return stored_metadata_view(region, self.meta.row_count).map(Some);
1873        }
1874        let view = self.stored_metadata()?;
1875        if view.is_some() {
1876            let _ = self.stored_metadata_validated.set(());
1877        }
1878        Ok(view)
1879    }
1880}
1881
1882fn stored_metadata_view(
1883    region: &[u8],
1884    header_rows: u32,
1885) -> Result<StoredMetadataRows<'_>, SegmentError> {
1886    let declared_rows = region
1887        .get(..4)
1888        .and_then(|value| value.try_into().ok())
1889        .map(u32::from_le_bytes)
1890        .ok_or_else(|| SegmentError::Geometry("stored-metadata header is truncated".to_owned()))?;
1891    let reserved = region
1892        .get(4..8)
1893        .and_then(|value| value.try_into().ok())
1894        .map(u32::from_le_bytes)
1895        .ok_or_else(|| {
1896            SegmentError::Geometry("stored-metadata reserved field is truncated".to_owned())
1897        })?;
1898    if declared_rows != header_rows || reserved != 0 {
1899        return Err(SegmentError::Geometry(format!(
1900            "stored-metadata rows/reserved {declared_rows}/{reserved}, expected {header_rows}/0"
1901        )));
1902    }
1903    let row_count = declared_rows as usize;
1904    let offset_bytes = row_count
1905        .checked_add(1)
1906        .and_then(|count| count.checked_mul(8))
1907        .ok_or_else(|| SegmentError::Geometry("stored-metadata offsets overflow".to_owned()))?;
1908    let offsets_end = 8_usize
1909        .checked_add(offset_bytes)
1910        .ok_or_else(|| SegmentError::Geometry("stored-metadata offset end overflow".to_owned()))?;
1911    let offsets = region.get(8..offsets_end).ok_or_else(|| {
1912        SegmentError::Geometry("stored-metadata offsets are truncated".to_owned())
1913    })?;
1914    let bytes = region
1915        .get(offsets_end..)
1916        .ok_or_else(|| SegmentError::Geometry("stored-metadata payload is truncated".to_owned()))?;
1917    Ok(StoredMetadataRows {
1918        offsets,
1919        bytes,
1920        row_count,
1921    })
1922}
1923
1924/// Parses the stored-text header geometry into a row view without walking rows.
1925fn stored_text_view(region: &[u8], header_rows: u32) -> Result<StoredTextRows<'_>, SegmentError> {
1926    {
1927        let declared_rows = region
1928            .get(..4)
1929            .and_then(|value| value.try_into().ok())
1930            .map(u32::from_le_bytes)
1931            .ok_or_else(|| SegmentError::Geometry("stored-text header is truncated".to_owned()))?;
1932        let reserved = region
1933            .get(4..8)
1934            .and_then(|value| value.try_into().ok())
1935            .map(u32::from_le_bytes)
1936            .ok_or_else(|| {
1937                SegmentError::Geometry("stored-text reserved field is truncated".to_owned())
1938            })?;
1939        if declared_rows != header_rows || reserved != 0 {
1940            return Err(SegmentError::Geometry(format!(
1941                "stored-text rows/reserved {declared_rows}/{reserved}, expected {header_rows}/0"
1942            )));
1943        }
1944        let row_count = declared_rows as usize;
1945        let bitmap_len = row_count.div_ceil(8);
1946        let bitmap_end = 8_usize
1947            .checked_add(bitmap_len)
1948            .ok_or_else(|| SegmentError::Geometry("stored-text bitmap overflow".to_owned()))?;
1949        let offsets_len = row_count
1950            .checked_mul(8)
1951            .ok_or_else(|| SegmentError::Geometry("stored-text offsets overflow".to_owned()))?;
1952        let offsets_end = bitmap_end
1953            .checked_add(offsets_len)
1954            .ok_or_else(|| SegmentError::Geometry("stored-text offset end overflow".to_owned()))?;
1955        let present = region.get(8..bitmap_end).ok_or_else(|| {
1956            SegmentError::Geometry("stored-text presence bitmap is truncated".to_owned())
1957        })?;
1958        let offsets = region.get(bitmap_end..offsets_end).ok_or_else(|| {
1959            SegmentError::Geometry("stored-text offsets are truncated".to_owned())
1960        })?;
1961        let bytes = region
1962            .get(offsets_end..)
1963            .ok_or_else(|| SegmentError::Geometry("stored-text payload is truncated".to_owned()))?;
1964        if !row_count.is_multiple_of(8) {
1965            let used = row_count % 8;
1966            let padding_mask = !((1_u8 << used) - 1);
1967            if present.last().is_some_and(|byte| byte & padding_mask != 0) {
1968                return Err(SegmentError::Geometry(
1969                    "stored-text presence padding bits are nonzero".to_owned(),
1970                ));
1971            }
1972        }
1973        Ok(StoredTextRows {
1974            present,
1975            offsets,
1976            bytes,
1977            row_count,
1978        })
1979    }
1980}
1981
1982impl SegmentReader {
1983    /// Returns the validated, mmap-backed fixed-stride graph node-block region.
1984    pub fn graph_node_blocks(&self) -> Result<GraphNodeBlocks<'_>, SegmentError> {
1985        let blocks = decode_node_blocks(self.region(RegionKind::GraphNodeBlocks)?)?;
1986        if blocks.layout().dims() != self.meta.dims {
1987            return Err(SegmentError::Geometry(format!(
1988                "graph dimensions {}, segment dimensions {}",
1989                blocks.layout().dims(),
1990                self.meta.dims
1991            )));
1992        }
1993        if blocks.node_count() != self.meta.row_count {
1994            return Err(SegmentError::Geometry(format!(
1995                "graph nodes {}, segment rows {}",
1996                blocks.node_count(),
1997                self.meta.row_count
1998            )));
1999        }
2000        Ok(blocks)
2001    }
2002
2003    pub(crate) fn bind_validated_graph_node_blocks(
2004        &self,
2005        descriptor: ValidatedGraphNodeBlocks,
2006    ) -> Result<GraphNodeBlocks<'_>, SegmentError> {
2007        let entry = self.entry(RegionKind::GraphNodeBlocks)?;
2008        let bytes = self.region_slice(entry)?;
2009        descriptor.bind(bytes).map_err(SegmentError::Graph)
2010    }
2011
2012    /// Validates every region, alignment padding, and the whole-file trailer.
2013    pub fn validate_all(&self) -> Result<(), SegmentError> {
2014        for entry in &self.entries {
2015            let bytes = self.region_slice(entry)?;
2016            let actual = xxh3_64(bytes);
2017            if actual != entry.checksum {
2018                return Err(FormatError::new(
2019                    format!("segment:{}:region-{}", self.meta.id, entry.kind),
2020                    FormatCheck::BlockChecksum,
2021                    format!("expected {:#018x}, computed {actual:#018x}", entry.checksum),
2022                )
2023                .into());
2024            }
2025        }
2026        let bytes = self.mapping.as_bytes();
2027        let trailer_start = bytes.len().checked_sub(FILE_TRAILER_LEN).ok_or_else(|| {
2028            FormatError::new(
2029                format!("segment: {}", self.meta.id),
2030                FormatCheck::Length,
2031                "missing file trailer",
2032            )
2033        })?;
2034        let expected = read_u64("segment", bytes, trailer_start)?;
2035        let checksummed = bytes.get(..trailer_start).ok_or_else(|| {
2036            FormatError::new("segment", FormatCheck::Length, "invalid trailer position")
2037        })?;
2038        let actual = xxh3_64(checksummed);
2039        if actual != expected {
2040            return Err(FormatError::new(
2041                format!("segment: {}", self.meta.id),
2042                FormatCheck::FileChecksum,
2043                format!("expected {expected:#018x}, computed {actual:#018x}"),
2044            )
2045            .into());
2046        }
2047        Ok(())
2048    }
2049
2050    fn vector_payload(
2051        &self,
2052        kind: RegionKind,
2053    ) -> Result<(super::layout::VectorHeader, &[u8]), SegmentError> {
2054        let region = self.region(kind)?;
2055        let header_bytes = region.get(..VECTOR_HEADER_LEN).ok_or_else(|| {
2056            SegmentError::Geometry(format!("{kind:?} is shorter than vector header"))
2057        })?;
2058        let header = decode_vector_header(header_bytes)?;
2059        if header.dims != self.meta.dims
2060            || header.row_count != self.meta.row_count
2061            || (kind != RegionKind::VectorRescore && header.scheme != self.meta.scheme)
2062        {
2063            return Err(SegmentError::Geometry(format!(
2064                "{kind:?} header scheme/dims/rows {}/{}/{}, segment {}/{}/{}",
2065                header.scheme,
2066                header.dims,
2067                header.row_count,
2068                self.meta.scheme,
2069                self.meta.dims,
2070                self.meta.row_count
2071            )));
2072        }
2073        let payload = region
2074            .get(VECTOR_HEADER_LEN..)
2075            .ok_or_else(|| SegmentError::Geometry(format!("{kind:?} payload offset is invalid")))?;
2076        Ok((header, payload))
2077    }
2078
2079    fn vector_payload_unchecked(
2080        &self,
2081        kind: RegionKind,
2082    ) -> Result<(super::layout::VectorHeader, &[u8]), SegmentError> {
2083        let entry = self.entry(kind)?;
2084        let region = self.region_slice_unaccounted(entry)?;
2085        let header_bytes = region.get(..VECTOR_HEADER_LEN).ok_or_else(|| {
2086            SegmentError::Geometry(format!("{kind:?} is shorter than vector header"))
2087        })?;
2088        let header = decode_vector_header(header_bytes)?;
2089        if header.dims != self.meta.dims
2090            || header.row_count != self.meta.row_count
2091            || (kind != RegionKind::VectorRescore && header.scheme != self.meta.scheme)
2092        {
2093            return Err(SegmentError::Geometry(format!(
2094                "{kind:?} header scheme/dims/rows {}/{}/{}, segment {}/{}/{}",
2095                header.scheme,
2096                header.dims,
2097                header.row_count,
2098                self.meta.scheme,
2099                self.meta.dims,
2100                self.meta.row_count
2101            )));
2102        }
2103        let payload = region
2104            .get(VECTOR_HEADER_LEN..)
2105            .ok_or_else(|| SegmentError::Geometry(format!("{kind:?} payload offset is invalid")))?;
2106        Ok((header, payload))
2107    }
2108
2109    fn validate_rescore_byte_range(&self, start: usize, length: usize) -> Result<(), SegmentError> {
2110        let entry = self.entry(RegionKind::VectorRescore)?;
2111        let region_length = usize::try_from(entry.length).map_err(|_| {
2112            SegmentError::Geometry("rescore region length exceeds usize".to_owned())
2113        })?;
2114        let end = start
2115            .checked_add(length)
2116            .ok_or_else(|| SegmentError::Geometry("rescore byte range overflow".to_owned()))?;
2117        if end > region_length {
2118            return Err(SegmentError::Geometry(format!(
2119                "rescore byte range {start}..{end} exceeds {region_length}"
2120            )));
2121        }
2122        if length == 0 || !Self::query_checksums_enabled() {
2123            return Ok(());
2124        }
2125        let first_chunk = start / CHECKSUM_CHUNK_BYTES;
2126        let last_chunk = end.saturating_sub(1) / CHECKSUM_CHUNK_BYTES;
2127        let mut validated = self.rescore_valid_chunks.lock().map_err(|_| {
2128            SegmentError::Geometry("rescore validation state is poisoned".to_owned())
2129        })?;
2130        for chunk in first_chunk..=last_chunk {
2131            let word = chunk / u64::BITS as usize;
2132            let bit = chunk % u64::BITS as usize;
2133            let mask = 1_u64 << bit;
2134            let state = validated.get_mut(word).ok_or_else(|| {
2135                SegmentError::Geometry(format!("rescore checksum chunk {chunk} is untracked"))
2136            })?;
2137            if *state & mask != 0 {
2138                continue;
2139            }
2140            let chunk_index = u32::try_from(chunk).map_err(|_| {
2141                SegmentError::Geometry("rescore checksum chunk exceeds u32".to_owned())
2142            })?;
2143            self.region_chunk(RegionKind::VectorRescore, chunk_index)?;
2144            *state |= mask;
2145        }
2146        Ok(())
2147    }
2148
2149    fn account_query_cache(
2150        &self,
2151        bytes: usize,
2152    ) -> Result<Option<crate::lifecycle::stats::AccountedCounter>, crate::lifecycle::StoreError>
2153    {
2154        let Some(accounting) = &self.query_accounting else {
2155            return Ok(None);
2156        };
2157        let mut counter = crate::lifecycle::stats::AccountedCounter::new(
2158            accounting,
2159            crate::lifecycle::stats::AllocationComponent::Snapshot,
2160        )?;
2161        counter.set(bytes)?;
2162        Ok(Some(counter))
2163    }
2164
2165    fn entry(&self, kind: RegionKind) -> Result<&RegionEntry, SegmentError> {
2166        self.entries
2167            .iter()
2168            .find(|entry| entry.kind == kind.id())
2169            .ok_or(SegmentError::MissingRegion(kind))
2170    }
2171
2172    fn region_slice(&self, entry: &RegionEntry) -> Result<&[u8], SegmentError> {
2173        let bytes = self.region_slice_unaccounted(entry)?;
2174        account_data_read(bytes.len());
2175        Ok(bytes)
2176    }
2177
2178    fn region_slice_unaccounted(&self, entry: &RegionEntry) -> Result<&[u8], SegmentError> {
2179        let start = usize::try_from(entry.offset)
2180            .map_err(|_| SegmentError::Geometry("region offset exceeds usize".to_owned()))?;
2181        let length = usize::try_from(entry.length)
2182            .map_err(|_| SegmentError::Geometry("region length exceeds usize".to_owned()))?;
2183        let end = start
2184            .checked_add(length)
2185            .ok_or_else(|| SegmentError::Geometry("region end overflow".to_owned()))?;
2186        let bytes = self.mapping.as_bytes().get(start..end).ok_or_else(|| {
2187            SegmentError::Geometry(format!(
2188                "region {} range {start}..{end} exceeds file {}",
2189                entry.kind,
2190                self.mapping.length()
2191            ))
2192        })?;
2193        Ok(bytes)
2194    }
2195
2196    fn chunk_checksum(&self, kind: RegionKind, chunk_index: u32) -> Result<u64, SegmentError> {
2197        let table = self.region(RegionKind::ChecksumTable)?;
2198        let mut cursor = Cursor::new("checksum-table", table);
2199        let count = cursor.u32()?;
2200        let chunk_size = cursor.u32()?;
2201        if chunk_size as usize != CHECKSUM_CHUNK_BYTES {
2202            return Err(SegmentError::Geometry(format!(
2203                "checksum chunk size {chunk_size}, expected {CHECKSUM_CHUNK_BYTES}"
2204            )));
2205        }
2206        let mut found = None;
2207        for _ in 0..count {
2208            let entry_kind = cursor.u16()?;
2209            let reserved = cursor.u16()?;
2210            let entry_chunk = cursor.u32()?;
2211            let checksum = cursor.u64()?;
2212            if reserved != 0 {
2213                return Err(SegmentError::Geometry(
2214                    "checksum-table reserved field is non-zero".to_owned(),
2215                ));
2216            }
2217            if entry_kind == kind.id() && entry_chunk == chunk_index {
2218                found = Some(checksum);
2219            }
2220        }
2221        cursor.finish().map_err(SegmentError::Geometry)?;
2222        found.ok_or_else(|| {
2223            SegmentError::Geometry(format!(
2224                "checksum table has no {kind:?} chunk {chunk_index}"
2225            ))
2226        })
2227    }
2228}
2229
2230/// Persisted width of one document-version row: a little-endian `u128`
2231/// document id followed by a little-endian `u64` revision.
2232const DOCUMENT_VERSION_BYTES: usize = 24;
2233
2234fn encode_document_version(version: DocumentVersion) -> [u8; DOCUMENT_VERSION_BYTES] {
2235    let doc_id = version.doc_id().get().to_le_bytes();
2236    let revision = version.revision().get().to_le_bytes();
2237    let mut bytes = [0_u8; DOCUMENT_VERSION_BYTES];
2238    for (slot, byte) in bytes.iter_mut().zip(doc_id.into_iter().chain(revision)) {
2239        *slot = byte;
2240    }
2241    bytes
2242}
2243
2244/// Returns the persisted identity bytes of one sealed row. The region length
2245/// is validated as exactly `row_count * 24` before any caller reaches this,
2246/// so the empty fallback is unreachable and sorts consistently if it were not.
2247fn document_version_entry(bytes: &[u8], row: u32) -> &[u8] {
2248    (row as usize)
2249        .checked_mul(DOCUMENT_VERSION_BYTES)
2250        .and_then(|start| bytes.get(start..start.checked_add(DOCUMENT_VERSION_BYTES)?))
2251        .unwrap_or(&[])
2252}
2253
2254fn document_id_entry(bytes: &[u8], row: u32) -> &[u8] {
2255    document_version_entry(bytes, row)
2256        .get(..std::mem::size_of::<u128>())
2257        .unwrap_or(&[])
2258}
2259
2260fn arc_resident_bytes<T>(deep_bytes: usize) -> Option<usize> {
2261    deep_bytes
2262        .checked_add(std::mem::size_of::<T>())?
2263        .checked_add(2 * std::mem::size_of::<usize>())
2264}
2265
2266fn rescore_validation_words(entries: &[RegionEntry]) -> Result<usize, SegmentError> {
2267    let Some(entry) = entries
2268        .iter()
2269        .find(|entry| entry.kind == RegionKind::VectorRescore.id())
2270    else {
2271        return Ok(0);
2272    };
2273    let length = usize::try_from(entry.length)
2274        .map_err(|_| SegmentError::Geometry("rescore region length exceeds usize".to_owned()))?;
2275    let chunks = length.div_ceil(CHECKSUM_CHUNK_BYTES);
2276    Ok(chunks.div_ceil(u64::BITS as usize))
2277}
2278
2279/// Reads and validates only one bounded segment header through a VFS decorator.
2280pub fn validate_header_with_vfs(
2281    vfs: &dyn Vfs,
2282    path: &Path,
2283    expected: &SegmentMeta,
2284) -> Result<usize, SegmentError> {
2285    let actual_length = vfs
2286        .open(path)
2287        .map_err(|error| SegmentError::io(path, error))?;
2288    let mut header_bytes = vfs
2289        .read_range(path, 0, FILE_HEADER_LEN)
2290        .map_err(|error| SegmentError::io(path, error))?;
2291    let artifact = path.display().to_string();
2292    #[cfg(any(test, feature = "test-support"))]
2293    let actual_family = header_bytes
2294        .get(8..10)
2295        .and_then(|family| <[u8; 2]>::try_from(family).ok())
2296        .map(u16::from_le_bytes);
2297    let fixed =
2298        decode_header(&artifact, FormatFamily::Segment, &header_bytes).map_err(|error| {
2299            #[cfg(any(test, feature = "test-support"))]
2300            crate::lifecycle::record_storage_segment_format_fault(
2301                &error,
2302                actual_family,
2303                expected.id,
2304            );
2305            SegmentError::from(error)
2306        })?;
2307    let header_length = usize::try_from(fixed.header_length)
2308        .map_err(|_| SegmentError::Geometry("segment header length exceeds usize".to_owned()))?;
2309    validate_bounded_header_length(&artifact, header_length, actual_length)?;
2310    let remaining = header_length.saturating_sub(FILE_HEADER_LEN);
2311    if remaining > 0 {
2312        let tail = vfs
2313            .read_range(path, FILE_HEADER_LEN as u64, remaining)
2314            .map_err(|error| SegmentError::io(path, error))?;
2315        header_bytes.extend_from_slice(&tail);
2316    }
2317    let parsed = parse_segment_header(&artifact, &header_bytes, actual_length, expected.id)?;
2318    if !parsed.meta.same_segment_file(expected) {
2319        return Err(SegmentError::Geometry(format!(
2320            "manifest metadata {expected:?}, header metadata {:?}",
2321            parsed.meta
2322        )));
2323    }
2324    Ok(header_length)
2325}
2326
2327/// Fuzzing/parser seam that validates arbitrary complete segment bytes without mapping.
2328pub fn validate_segment_bytes(bytes: &[u8]) -> Result<SegmentMeta, SegmentError> {
2329    let id_bytes: [u8; 16] = bytes
2330        .get(FILE_HEADER_LEN..FILE_HEADER_LEN.saturating_add(16))
2331        .ok_or_else(|| {
2332            FormatError::new(
2333                "segment-bytes",
2334                FormatCheck::Length,
2335                format!("missing segment id in {} bytes", bytes.len()),
2336            )
2337        })?
2338        .try_into()
2339        .map_err(|_| {
2340            FormatError::new("segment-bytes", FormatCheck::Length, "invalid segment id")
2341        })?;
2342    let id = SegmentId::from_bytes(id_bytes);
2343    let actual_length = u64::try_from(bytes.len())
2344        .map_err(|_| SegmentError::Geometry("byte slice length exceeds u64".to_owned()))?;
2345    let parsed = parse_segment_header("segment-bytes", bytes, actual_length, id)?;
2346    for entry in &parsed.entries {
2347        let start = usize::try_from(entry.offset)
2348            .map_err(|_| SegmentError::Geometry("region offset exceeds usize".to_owned()))?;
2349        let length = usize::try_from(entry.length)
2350            .map_err(|_| SegmentError::Geometry("region length exceeds usize".to_owned()))?;
2351        let end = start
2352            .checked_add(length)
2353            .ok_or_else(|| SegmentError::Geometry("region end overflow".to_owned()))?;
2354        let region = bytes.get(start..end).ok_or_else(|| {
2355            FormatError::new(
2356                "segment-bytes",
2357                FormatCheck::BlockLength,
2358                format!("region {} range {start}..{end} is truncated", entry.kind),
2359            )
2360        })?;
2361        let actual = xxh3_64(region);
2362        if actual != entry.checksum {
2363            return Err(FormatError::new(
2364                format!("segment-bytes:region-{}", entry.kind),
2365                FormatCheck::BlockChecksum,
2366                format!("expected {:#018x}, computed {actual:#018x}", entry.checksum),
2367            )
2368            .into());
2369        }
2370    }
2371    let trailer = bytes.len().checked_sub(FILE_TRAILER_LEN).ok_or_else(|| {
2372        FormatError::new("segment-bytes", FormatCheck::Length, "missing file trailer")
2373    })?;
2374    let expected = read_u64("segment-bytes", bytes, trailer)?;
2375    let checksummed = bytes.get(..trailer).ok_or_else(|| {
2376        FormatError::new(
2377            "segment-bytes",
2378            FormatCheck::Length,
2379            "invalid trailer offset",
2380        )
2381    })?;
2382    let actual = xxh3_64(checksummed);
2383    if actual != expected {
2384        return Err(FormatError::new(
2385            "segment-bytes",
2386            FormatCheck::FileChecksum,
2387            format!("expected {expected:#018x}, computed {actual:#018x}"),
2388        )
2389        .into());
2390    }
2391    Ok(parsed.meta)
2392}
2393
2394fn preflight_region_count(
2395    artifact: &str,
2396    bytes: &[u8],
2397    actual_file_length: u64,
2398) -> Result<usize, SegmentError> {
2399    let fixed = decode_header(artifact, FormatFamily::Segment, bytes)?;
2400    if fixed.file_length != actual_file_length {
2401        return Err(FormatError::new(
2402            artifact,
2403            FormatCheck::FileLength,
2404            format!(
2405                "declared {}, actual {actual_file_length}",
2406                fixed.file_length
2407            ),
2408        )
2409        .into());
2410    }
2411    let header_length = usize::try_from(fixed.header_length)
2412        .map_err(|_| SegmentError::Geometry("header length exceeds usize".to_owned()))?;
2413    validate_bounded_header_length(artifact, header_length, actual_file_length)?;
2414    let header_bytes = bytes.get(..header_length).ok_or_else(|| {
2415        FormatError::new(
2416            artifact,
2417            FormatCheck::Length,
2418            format!("declared header {header_length}, available {}", bytes.len()),
2419        )
2420    })?;
2421    Ok(usize::from(read_u16(
2422        artifact,
2423        header_bytes,
2424        FILE_HEADER_LEN.saturating_add(20),
2425    )?))
2426}
2427
2428fn parse_segment_header(
2429    artifact: &str,
2430    bytes: &[u8],
2431    actual_file_length: u64,
2432    expected_id: SegmentId,
2433) -> Result<ParsedHeader, SegmentError> {
2434    #[cfg(any(test, feature = "test-support"))]
2435    let actual_family = bytes
2436        .get(8..10)
2437        .and_then(|family| <[u8; 2]>::try_from(family).ok())
2438        .map(u16::from_le_bytes);
2439    let fixed = decode_header(artifact, FormatFamily::Segment, bytes).map_err(|error| {
2440        #[cfg(any(test, feature = "test-support"))]
2441        crate::lifecycle::record_storage_segment_format_fault(&error, actual_family, expected_id);
2442        SegmentError::from(error)
2443    })?;
2444    if fixed.file_length != actual_file_length {
2445        return Err(FormatError::new(
2446            artifact,
2447            FormatCheck::FileLength,
2448            format!(
2449                "declared {}, actual {actual_file_length}",
2450                fixed.file_length
2451            ),
2452        )
2453        .into());
2454    }
2455    let header_length = usize::try_from(fixed.header_length)
2456        .map_err(|_| SegmentError::Geometry("header length exceeds usize".to_owned()))?;
2457    validate_bounded_header_length(artifact, header_length, actual_file_length)?;
2458    let header_bytes = bytes.get(..header_length).ok_or_else(|| {
2459        FormatError::new(
2460            artifact,
2461            FormatCheck::Length,
2462            format!("declared header {header_length}, available {}", bytes.len()),
2463        )
2464    })?;
2465    let id_bytes: [u8; 16] = header_bytes
2466        .get(FILE_HEADER_LEN..FILE_HEADER_LEN.saturating_add(16))
2467        .ok_or_else(|| FormatError::new(artifact, FormatCheck::Length, "missing segment id"))?
2468        .try_into()
2469        .map_err(|_| FormatError::new(artifact, FormatCheck::Length, "invalid segment id"))?;
2470    let actual_id = SegmentId::from_bytes(id_bytes);
2471    if actual_id != expected_id {
2472        #[cfg(any(test, feature = "test-support"))]
2473        crate::lifecycle::record_storage_segment_identity_fault(artifact, expected_id, actual_id);
2474        return Err(SegmentError::WrongObject {
2475            artifact: artifact.to_owned(),
2476            expected: expected_id,
2477            actual: actual_id,
2478        });
2479    }
2480    let row_count = read_u32(artifact, header_bytes, FILE_HEADER_LEN.saturating_add(16))?;
2481    let region_count = usize::from(read_u16(
2482        artifact,
2483        header_bytes,
2484        FILE_HEADER_LEN.saturating_add(20),
2485    )?);
2486    if read_u16(artifact, header_bytes, FILE_HEADER_LEN.saturating_add(22))? != 0 {
2487        return Err(SegmentError::Geometry(
2488            "segment prefix reserved field is non-zero".to_owned(),
2489        ));
2490    }
2491    let scheme = read_u16(artifact, header_bytes, FILE_HEADER_LEN.saturating_add(24))?;
2492    FormatRegistry::require_scheme(scheme)
2493        .map_err(|error| SegmentError::Geometry(error.to_string()))?;
2494    if read_u16(artifact, header_bytes, FILE_HEADER_LEN.saturating_add(26))? != 0 {
2495        return Err(SegmentError::Geometry(
2496            "segment scheme padding is non-zero".to_owned(),
2497        ));
2498    }
2499    let dims = read_u32(artifact, header_bytes, FILE_HEADER_LEN.saturating_add(28))?;
2500    let expected_header_length = FILE_HEADER_LEN
2501        .checked_add(SEGMENT_PREFIX_LEN)
2502        .and_then(|value| value.checked_add(region_count.saturating_mul(REGION_ENTRY_LEN)))
2503        .and_then(|value| value.checked_add(8))
2504        .ok_or_else(|| SegmentError::Geometry("header length overflow".to_owned()))?;
2505    if header_length != expected_header_length {
2506        return Err(FormatError::new(
2507            artifact,
2508            FormatCheck::HeaderLength,
2509            format!("declared {header_length}, directory implies {expected_header_length}"),
2510        )
2511        .into());
2512    }
2513    let checksum_offset = header_length.saturating_sub(8);
2514    let expected_checksum = read_u64(artifact, header_bytes, checksum_offset)?;
2515    let checksum_bytes = header_bytes.get(..checksum_offset).ok_or_else(|| {
2516        FormatError::new(
2517            artifact,
2518            FormatCheck::Length,
2519            "invalid header checksum offset",
2520        )
2521    })?;
2522    let actual_checksum = xxh3_64(checksum_bytes);
2523    if actual_checksum != expected_checksum {
2524        return Err(FormatError::new(
2525            artifact,
2526            FormatCheck::BlockChecksum,
2527            format!("header expected {expected_checksum:#018x}, computed {actual_checksum:#018x}"),
2528        )
2529        .into());
2530    }
2531
2532    let mut entries: Vec<RegionEntry> = Vec::with_capacity(region_count);
2533    let directory_start = FILE_HEADER_LEN.saturating_add(SEGMENT_PREFIX_LEN);
2534    for position in 0..region_count {
2535        let offset = directory_start
2536            .checked_add(position.saturating_mul(REGION_ENTRY_LEN))
2537            .ok_or_else(|| SegmentError::Geometry("directory offset overflow".to_owned()))?;
2538        let entry = RegionEntry {
2539            kind: read_u16(artifact, header_bytes, offset)?,
2540            version: read_u16(artifact, header_bytes, offset.saturating_add(2))?,
2541            reserved: read_u32(artifact, header_bytes, offset.saturating_add(4))?,
2542            offset: read_u64(artifact, header_bytes, offset.saturating_add(8))?,
2543            length: read_u64(artifact, header_bytes, offset.saturating_add(16))?,
2544            checksum: read_u64(artifact, header_bytes, offset.saturating_add(24))?,
2545        };
2546        if entry.reserved != 0 {
2547            return Err(SegmentError::Geometry(format!(
2548                "region {} reserved field is non-zero",
2549                entry.kind
2550            )));
2551        }
2552        if entries.iter().any(|existing| existing.kind == entry.kind) {
2553            return Err(SegmentError::Geometry(format!(
2554                "duplicate region kind {}",
2555                entry.kind
2556            )));
2557        }
2558        validate_entry(artifact, &entry, header_length, actual_file_length)?;
2559        if let Some(kind) = RegionKind::from_id(entry.kind)
2560            && let Some(family) = kind.family()
2561        {
2562            FormatRegistry::require(family.id(), entry.version).map_err(|error| {
2563                FormatError::new(artifact, FormatCheck::Version, error.to_string())
2564            })?;
2565        }
2566        entries.push(entry);
2567    }
2568    validate_non_overlapping(&entries)?;
2569    Ok(ParsedHeader {
2570        meta: SegmentMeta {
2571            id: actual_id,
2572            row_count,
2573            scheme,
2574            dims,
2575            file_size: actual_file_length,
2576            epoch_id: None,
2577            clustering_key_range: super::ClusteringKeyRange::Unstamped,
2578        },
2579        header_length,
2580        entries,
2581    })
2582}
2583
2584fn validate_bounded_header_length(
2585    artifact: &str,
2586    header_length: usize,
2587    actual_file_length: u64,
2588) -> Result<(), SegmentError> {
2589    if !(FILE_HEADER_LEN + SEGMENT_PREFIX_LEN + 8..=MAX_SEGMENT_HEADER_BYTES)
2590        .contains(&header_length)
2591    {
2592        return Err(FormatError::new(
2593            artifact,
2594            FormatCheck::HeaderLength,
2595            format!("header length {header_length} is outside bounded v1 range"),
2596        )
2597        .into());
2598    }
2599    let file_length = usize::try_from(actual_file_length)
2600        .map_err(|_| SegmentError::Geometry("file length exceeds usize".to_owned()))?;
2601    if header_length > file_length.saturating_sub(FILE_TRAILER_LEN) {
2602        return Err(FormatError::new(
2603            artifact,
2604            FormatCheck::HeaderLength,
2605            format!("header {header_length} exceeds file {file_length}"),
2606        )
2607        .into());
2608    }
2609    Ok(())
2610}
2611
2612fn validate_entry(
2613    artifact: &str,
2614    entry: &RegionEntry,
2615    header_length: usize,
2616    file_length: u64,
2617) -> Result<(), SegmentError> {
2618    let offset = usize::try_from(entry.offset)
2619        .map_err(|_| SegmentError::Geometry("region offset exceeds usize".to_owned()))?;
2620    let length = usize::try_from(entry.length)
2621        .map_err(|_| SegmentError::Geometry("region length exceeds usize".to_owned()))?;
2622    let minimum = align_up(header_length, REGION_ALIGNMENT)?;
2623    if offset < minimum || !offset.is_multiple_of(REGION_ALIGNMENT) {
2624        return Err(SegmentError::Geometry(format!(
2625            "region {} offset {offset} is below/aligned from {minimum}",
2626            entry.kind
2627        )));
2628    }
2629    let end = offset
2630        .checked_add(length)
2631        .ok_or_else(|| SegmentError::Geometry("region end overflow".to_owned()))?;
2632    let maximum = usize::try_from(file_length)
2633        .map_err(|_| SegmentError::Geometry("file length exceeds usize".to_owned()))?
2634        .checked_sub(FILE_TRAILER_LEN)
2635        .ok_or_else(|| SegmentError::Geometry("file is shorter than trailer".to_owned()))?;
2636    if end > maximum {
2637        return Err(FormatError::new(
2638            artifact,
2639            FormatCheck::BlockLength,
2640            format!("region {} ends at {end}, maximum {maximum}", entry.kind),
2641        )
2642        .into());
2643    }
2644    Ok(())
2645}
2646
2647fn validate_non_overlapping(entries: &[RegionEntry]) -> Result<(), SegmentError> {
2648    for (position, entry) in entries.iter().enumerate() {
2649        let entry_end = entry
2650            .offset
2651            .checked_add(entry.length)
2652            .ok_or_else(|| SegmentError::Geometry("region u64 end overflow".to_owned()))?;
2653        for other in entries.iter().skip(position.saturating_add(1)) {
2654            let other_end = other
2655                .offset
2656                .checked_add(other.length)
2657                .ok_or_else(|| SegmentError::Geometry("region u64 end overflow".to_owned()))?;
2658            if entry.offset < other_end && other.offset < entry_end {
2659                let (previous, current, previous_end) = if entry.offset <= other.offset {
2660                    (entry, other, entry_end)
2661                } else {
2662                    (other, entry, other_end)
2663                };
2664                return Err(SegmentError::Geometry(format!(
2665                    "region {} begins {} before previous end {previous_end} for region {}",
2666                    current.kind, current.offset, previous.kind
2667                )));
2668            }
2669        }
2670    }
2671    Ok(())
2672}
2673
2674fn cast_slice<'a, T>(
2675    bytes: &'a [u8],
2676    count: usize,
2677    artifact: &str,
2678) -> Result<&'a [T], SegmentError> {
2679    #[cfg(target_endian = "big")]
2680    {
2681        let _ = (bytes, count);
2682        return Err(SegmentError::Geometry(format!(
2683            "{artifact} zero-copy requires little-endian target"
2684        )));
2685    }
2686    #[cfg(target_endian = "little")]
2687    {
2688        let expected = count
2689            .checked_mul(std::mem::size_of::<T>())
2690            .ok_or_else(|| SegmentError::Geometry(format!("{artifact} byte length overflow")))?;
2691        if bytes.len() != expected {
2692            return Err(SegmentError::Geometry(format!(
2693                "{artifact} bytes {}, expected {expected}",
2694                bytes.len()
2695            )));
2696        }
2697        if !(bytes.as_ptr() as usize).is_multiple_of(std::mem::align_of::<T>()) {
2698            return Err(SegmentError::Geometry(format!(
2699                "{artifact} address is not {}-byte aligned",
2700                std::mem::align_of::<T>()
2701            )));
2702        }
2703        // SAFETY: byte length and alignment were checked above; T is one of the
2704        // pinned repr(C) all-f32 record types (or f32), and the checksum plus
2705        // little-endian target makes the mapped representation valid.
2706        Ok(unsafe { std::slice::from_raw_parts(bytes.as_ptr().cast::<T>(), count) })
2707    }
2708}