1use crate::data_model::GraphDataType;
7use diskann::{graph::AdjacencyList, ANNError, ANNResult};
8use hashbrown::{hash_map::Entry::Occupied, HashMap};
9
10pub struct Cache<Data: GraphDataType<VectorIdType = u32>> {
11 mapping: HashMap<Data::VectorIdType, usize>,
13
14 vectors: Vec<Data::VectorDataType>,
16
17 adjacency_lists: Vec<AdjacencyList<Data::VectorIdType>>,
19
20 associated_data: Vec<Data::AssociatedDataType>,
22
23 dimension: usize,
25
26 capacity: usize,
28}
29
30impl<Data> Cache<Data>
31where
32 Data: GraphDataType<VectorIdType = u32>,
33{
34 pub fn new(dimension: usize, capacity: usize) -> ANNResult<Self> {
36 Ok(Self {
37 mapping: HashMap::new(),
38 vectors: vec![Data::VectorDataType::default(); capacity * dimension],
39 adjacency_lists: Vec::with_capacity(capacity),
40 associated_data: Vec::with_capacity(capacity),
41 dimension,
42 capacity,
43 })
44 }
45
46 pub fn contains(&self, vector_id: &Data::VectorIdType) -> bool {
48 self.mapping.contains_key(vector_id)
49 }
50
51 pub fn get_vector(&self, vector_id: &Data::VectorIdType) -> Option<&[Data::VectorDataType]> {
53 if let Some(idx) = self.mapping.get(vector_id) {
54 Some(&self.vectors[idx * self.dimension..(idx + 1) * self.dimension])
55 } else {
56 Option::None
57 }
58 }
59
60 pub fn get_adjacency_list(
62 &self,
63 vector_id: &Data::VectorIdType,
64 ) -> Option<&AdjacencyList<Data::VectorIdType>> {
65 if let Some(idx) = self.mapping.get(vector_id) {
66 Some(&self.adjacency_lists[*idx])
67 } else {
68 Option::None
69 }
70 }
71
72 pub fn get_associated_data(
74 &self,
75 vector_id: &Data::VectorIdType,
76 ) -> Option<&Data::AssociatedDataType> {
77 if let Some(idx) = self.mapping.get(vector_id) {
78 Some(&self.associated_data[*idx])
79 } else {
80 Option::None
81 }
82 }
83
84 pub fn insert(
87 &mut self,
88 vector_id: &Data::VectorIdType,
89 vector: &[Data::VectorDataType],
90 adjacency_list: AdjacencyList<Data::VectorIdType>,
91 associated_data: Data::AssociatedDataType,
92 ) -> ANNResult<()> {
93 if self.dimension != vector.len() {
94 return ANNResult::Err(ANNError::log_index_error(
95 "Vector dimension does not match the dimension set in cache.",
96 ));
97 }
98
99 if let Occupied(occupied_entry) = self.mapping.entry(*vector_id) {
100 let idx = *occupied_entry.get();
101 self.copy_to_cache(idx, vector, adjacency_list, associated_data);
102 return ANNResult::Ok(());
103 }
104
105 if self.mapping.len() >= self.capacity {
106 return ANNResult::Err(ANNError::log_index_error(
107 "Cache is full, cannot insert more nodes",
108 ));
109 }
110
111 let idx = self.mapping.len();
112 self.mapping.insert(*vector_id, idx);
113 self.copy_to_cache(idx, vector, adjacency_list, associated_data);
114 ANNResult::Ok(())
115 }
116
117 pub fn is_empty(&self) -> bool {
119 self.mapping.is_empty()
120 }
121
122 pub fn len(&self) -> usize {
124 self.mapping.len()
125 }
126
127 fn copy_to_cache(
128 &mut self,
129 idx: usize,
130 vector: &[Data::VectorDataType],
131 adjacency_list: AdjacencyList<Data::VectorIdType>,
132 associated_data: Data::AssociatedDataType,
133 ) {
134 self.vectors[idx * self.dimension..(idx + 1) * self.dimension].copy_from_slice(vector);
135 self.adjacency_lists.push(adjacency_list);
136 self.associated_data.push(associated_data);
137 }
138}
139
140#[derive(PartialEq)]
141pub enum CachingStrategy {
142 None,
143 StaticCacheWithBfsNodes(usize),
144}
145
146#[cfg(test)]
147mod tests {
148 use crate::test_utils::GraphDataF32VectorUnitData;
149 use diskann::graph::AdjacencyList;
150 use rstest::rstest;
151
152 use crate::data_model::Cache;
153
154 #[rstest]
155 fn test_contains() {
156 let mut cache =
157 Cache::<GraphDataF32VectorUnitData>::new(10, 2).unwrap();
158 insert_a_random_node(&mut cache);
159 let vector_id = 1;
160 let vector = vec![1.0; 10];
161 let adjacency_list = AdjacencyList::from_iter_untrusted([2, 3, 4]);
162 cache
163 .insert(&vector_id, &vector, adjacency_list, ())
164 .unwrap();
165
166 assert!(cache.contains(&vector_id));
167
168 let not_exist_vector_id = 2;
169 assert!(!cache.contains(¬_exist_vector_id));
170 }
171
172 #[rstest]
173 fn test_get_vector() {
174 let mut cache =
175 Cache::<GraphDataF32VectorUnitData>::new(10, 2).unwrap();
176 insert_a_random_node(&mut cache);
177 let vector_id = 1;
178 let vector = vec![1.0; 10];
179 let adjacency_list = AdjacencyList::from_iter_untrusted([2, 3, 4]);
180 cache
181 .insert(&vector_id, &vector, adjacency_list, ())
182 .unwrap();
183
184 let result = cache.get_vector(&vector_id).unwrap();
185 assert_eq!(result, vector.as_slice());
186
187 let not_exist_vector_id = 2;
188 assert!(cache.get_vector(¬_exist_vector_id).is_none());
189 }
190
191 #[rstest]
192 fn test_get_adjacency_list() {
193 let mut cache =
194 Cache::<GraphDataF32VectorUnitData>::new(10, 2).unwrap();
195 insert_a_random_node(&mut cache);
196 let vector_id = 1;
197 let vector = vec![1.0; 10];
198 let adjacency_list = AdjacencyList::from_iter_untrusted([2, 3, 4]);
199 cache
200 .insert(&vector_id, &vector, adjacency_list.clone(), ())
201 .unwrap();
202
203 let result = cache.get_adjacency_list(&vector_id).unwrap();
204 assert_eq!(*result, adjacency_list);
205
206 let not_exist_vector_id = 2;
207 assert!(cache.get_adjacency_list(¬_exist_vector_id).is_none());
208 }
209
210 #[rstest]
211 fn test_get_associated_data() {
212 let mut cache =
213 Cache::<GraphDataF32VectorUnitData>::new(10, 2).unwrap();
214 insert_a_random_node(&mut cache);
215 let vector_id = 1;
216 let vector = vec![1.0; 10];
217 let adjacency_list = AdjacencyList::from_iter_untrusted([2, 3, 4]);
218 let associated_data = ();
219 cache
220 .insert(&vector_id, &vector, adjacency_list, associated_data)
221 .unwrap();
222
223 let result = cache.get_associated_data(&vector_id);
224 assert!(result.is_some());
225
226 let not_exist_vector_id = 2;
227 assert!(cache.get_associated_data(¬_exist_vector_id).is_none());
228 }
229
230 #[rstest]
231 fn test_insert() {
232 let mut cache =
233 Cache::<GraphDataF32VectorUnitData>::new(10, 2).unwrap();
234 insert_a_random_node(&mut cache);
235 let vector_id = 1;
236 let vector = vec![1.0; 10];
237 let adjacency_list = AdjacencyList::from_iter_untrusted([2, 3, 4]);
238
239 cache
241 .insert(&vector_id, &vector, adjacency_list.clone(), ())
242 .unwrap();
243 assert!(cache.contains(&vector_id));
244
245 let updated_vector = vec![2.0; 10];
247 cache
248 .insert(&vector_id, &updated_vector, adjacency_list.clone(), ())
249 .unwrap();
250 assert_eq!(
251 cache.get_vector(&vector_id).unwrap(),
252 updated_vector.as_slice()
253 );
254
255 let vector_id_2 = 2;
257 let result = cache.insert(&vector_id_2, &vector, adjacency_list.clone(), ());
258 assert!(result.is_err());
259
260 let wrong_dimentions_vector = vec![1.0; 11];
262 assert!(cache
263 .insert(&vector_id, &wrong_dimentions_vector, adjacency_list, ())
264 .is_err());
265 }
266
267 #[rstest]
268 fn test_is_empty() {
269 let mut cache =
270 Cache::<GraphDataF32VectorUnitData>::new(10, 1).unwrap();
271
272 assert!(cache.is_empty());
273
274 insert_a_random_node(&mut cache);
275
276 assert!(!cache.is_empty());
277 }
278
279 #[rstest]
280 fn test_len() {
281 let mut cache =
282 Cache::<GraphDataF32VectorUnitData>::new(10, 5).unwrap();
283
284 assert_eq!(cache.len(), 0);
285
286 let vector_id = 1;
287 let vector = vec![1.0; 10];
288 let adjacency_list = AdjacencyList::from_iter_untrusted([2, 3, 4]);
289 cache
290 .insert(&vector_id, &vector, adjacency_list.clone(), ())
291 .unwrap();
292 let vector_id_2 = 2;
293 cache
294 .insert(&vector_id_2, &vector, adjacency_list.clone(), ())
295 .unwrap();
296 let vector_id_3 = 3;
297 cache
298 .insert(&vector_id_3, &vector, adjacency_list, ())
299 .unwrap();
300
301 assert_eq!(cache.len(), 3);
302 }
303
304 fn insert_a_random_node(cache: &mut Cache<GraphDataF32VectorUnitData>) {
305 let vector_id = 99;
306 let vector = vec![9.0; 10];
307 cache
308 .insert(
309 &vector_id,
310 &vector,
311 AdjacencyList::from_iter_untrusted([20, 30, 40]),
312 (),
313 )
314 .unwrap();
315 }
316}