nodedb_vector/segment_backing/
plain.rs1use std::sync::Arc;
7
8use crate::mmap_segment::MmapVectorSegment;
9
10use super::VectorSegmentBacking;
11
12pub struct PlainMmapBacking {
43 inner: Arc<MmapVectorSegment>,
44}
45
46impl PlainMmapBacking {
47 pub fn new(seg: MmapVectorSegment) -> Self {
49 Self {
50 inner: Arc::new(seg),
51 }
52 }
53
54 pub fn from_arc(seg: Arc<MmapVectorSegment>) -> Self {
60 Self { inner: seg }
61 }
62
63 pub fn segment(&self) -> &Arc<MmapVectorSegment> {
65 &self.inner
66 }
67}
68
69impl VectorSegmentBacking for PlainMmapBacking {
70 #[inline]
71 fn len(&self) -> usize {
72 self.inner.count()
73 }
74
75 #[inline]
76 fn dim(&self) -> usize {
77 self.inner.dim()
78 }
79
80 #[inline]
81 fn get_vector(&self, id: u32) -> Option<&[f32]> {
82 self.inner.get_vector(id)
83 }
84
85 #[inline]
86 fn get_surrogate(&self, id: u32) -> Option<u64> {
87 self.inner.get_surrogate_id(id)
88 }
89
90 #[inline]
91 fn prefetch(&self, id: u32) {
92 self.inner.prefetch(id);
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use tempfile::tempdir;
99
100 use super::*;
101 use crate::mmap_segment::MmapVectorSegment;
102
103 fn make_backing(dim: usize, vecs: &[Vec<f32>]) -> PlainMmapBacking {
104 let dir = tempdir().unwrap();
105 let path = dir.path().join("test.ndvs");
106
107 let refs: Vec<&[f32]> = vecs.iter().map(|v| v.as_slice()).collect();
108 let surrogates: Vec<u64> = (0..vecs.len() as u64).collect();
109
110 let seg =
111 MmapVectorSegment::create_with_surrogates(&path, dim, &refs, &surrogates).unwrap();
112
113 drop(dir);
117
118 PlainMmapBacking::new(seg)
119 }
120
121 #[test]
122 fn plain_backing_basic_roundtrip() {
123 let dim = 4;
124 let vecs = vec![
125 vec![1.0_f32, 2.0, 3.0, 4.0],
126 vec![5.0_f32, 6.0, 7.0, 8.0],
127 vec![9.0_f32, 10.0, 11.0, 12.0],
128 ];
129
130 let backing = make_backing(dim, &vecs);
131
132 assert_eq!(backing.len(), 3);
133 assert_eq!(backing.dim(), 4);
134 assert!(!backing.is_empty());
135
136 for (i, expected) in vecs.iter().enumerate() {
137 let got = backing
138 .get_vector(i as u32)
139 .expect("vector must be present");
140 assert_eq!(got, expected.as_slice(), "vector {i} mismatch");
141
142 let sid = backing
143 .get_surrogate(i as u32)
144 .expect("surrogate must be present");
145 assert_eq!(sid, i as u64, "surrogate {i} mismatch");
146 }
147
148 backing.prefetch(0);
150 backing.prefetch(1);
151 backing.prefetch(2);
152 }
153
154 #[test]
156 fn plain_backing_is_send_sync() {
157 fn assert_send_sync<T: Send + Sync>(_: &T) {}
158
159 let dir = tempdir().unwrap();
160 let path = dir.path().join("check.ndvs");
161 let seg = MmapVectorSegment::create(&path, 2, &[&[1.0_f32, 2.0]]).unwrap();
162 let backing = PlainMmapBacking::new(seg);
163
164 assert_send_sync(&backing);
165 }
166
167 #[test]
168 fn plain_backing_out_of_bounds_returns_none() {
169 let backing = make_backing(3, &[vec![1.0_f32, 2.0, 3.0]]);
170
171 assert!(
172 backing.get_vector(1).is_none(),
173 "id=1 must be out of bounds"
174 );
175 assert!(
176 backing.get_surrogate(1).is_none(),
177 "id=1 surrogate must be out of bounds"
178 );
179 backing.prefetch(1);
181 }
182
183 #[test]
184 fn plain_backing_empty_segment() {
185 let dir = tempdir().unwrap();
186 let path = dir.path().join("empty.ndvs");
187 let seg = MmapVectorSegment::create(&path, 4, &[]).unwrap();
188 let backing = PlainMmapBacking::new(seg);
189
190 assert_eq!(backing.len(), 0);
191 assert!(backing.is_empty());
192 assert!(backing.get_vector(0).is_none());
193 assert!(backing.get_surrogate(0).is_none());
194 backing.prefetch(0);
195 }
196}