Skip to main content

nodedb_vector/segment_backing/
backing.rs

1// SPDX-License-Identifier: Apache-2.0
2
3/// Storage abstraction for HNSW vector data.
4///
5/// Two implementations coexist:
6/// - [`crate::segment_backing::PlainMmapBacking`]: zero-copy mmap of a plaintext NDVS file (Origin).
7/// - `PagedbBacking`: encrypted segment read via pagedb (Lite, task 2a.2).
8///
9/// Implementations are responsible for vector retrieval; HNSW graph traversal
10/// makes no storage-level decisions.
11///
12/// # `Send + Sync` bound
13///
14/// The bound allows consumers to park the backing in an
15/// `Arc<dyn VectorSegmentBacking>` and dispatch across tasks.  Lite will
16/// require this in task 2a.2.
17///
18/// # Return type for `get_vector`
19///
20/// `-> Option<&[f32]>` borrows from `&self`.  This is correct for
21/// `PlainMmapBacking` (slice into mmap region lives as long as the backing)
22/// and for the planned `PagedbBacking` (which will hold a long-lived
23/// decrypted vector slab in a `MmapView` field on `self`).
24///
25/// If a future backing genuinely cannot return a `&self`-lifetime slice
26/// without copying, the signature can be changed to `Cow<'_, [f32]>` in a
27/// follow-up refactor.  For now both known impls support the zero-copy path.
28pub trait VectorSegmentBacking: Send + Sync {
29    /// Number of vectors stored in this segment.
30    fn len(&self) -> usize;
31
32    /// Returns `true` when the segment contains no vectors.
33    fn is_empty(&self) -> bool {
34        self.len() == 0
35    }
36
37    /// Dimensionality of each stored vector.
38    fn dim(&self) -> usize;
39
40    /// Fetch one vector by local position id (0..len).
41    ///
42    /// Backings should make this cheap — zero-copy where possible, decrypted
43    /// page lookup on cold paths.  Returns `None` if `id` is out of bounds.
44    fn get_vector(&self, id: u32) -> Option<&[f32]>;
45
46    /// Surrogate id for a local position.
47    ///
48    /// Returns `None` if `id` is out of bounds.
49    fn get_surrogate(&self, id: u32) -> Option<u64>;
50
51    /// Optional prefetch hint.
52    ///
53    /// Implementations may call `madvise(MADV_WILLNEED)` (mmap) or warm a
54    /// pagedb page cache entry.  Default is a no-op.
55    fn prefetch(&self, _id: u32) {}
56}