1use std::collections::HashMap;
11use std::sync::Mutex;
12
13#[derive(Debug)]
18pub struct VectorVersionInfo {
19 inserted: Mutex<HashMap<u64, Vec<u32>>>,
21 deleted: Mutex<HashMap<u64, Vec<u32>>>,
23}
24
25impl Clone for VectorVersionInfo {
26 fn clone(&self) -> Self {
27 Self {
28 inserted: Mutex::new(self.inserted.lock().unwrap().clone()),
29 deleted: Mutex::new(self.deleted.lock().unwrap().clone()),
30 }
31 }
32}
33
34impl Default for VectorVersionInfo {
35 fn default() -> Self {
36 Self {
37 inserted: Mutex::new(HashMap::new()),
38 deleted: Mutex::new(HashMap::new()),
39 }
40 }
41}
42
43impl VectorVersionInfo {
44 pub fn new() -> Self {
45 Self::default()
46 }
47
48 pub fn insert(&self, txn_id: u64, row_in_vector: u32) {
50 let mut ins = self.inserted.lock().unwrap();
51 ins.entry(txn_id).or_default().push(row_in_vector);
52 }
53
54 pub fn delete(&self, txn_id: u64, row_in_vector: u32) {
56 let mut del = self.deleted.lock().unwrap();
57 del.entry(txn_id).or_default().push(row_in_vector);
58 }
59
60 pub fn reset(&self) {
66 self.inserted.lock().unwrap().clear();
67 self.deleted.lock().unwrap().clear();
68 }
69
70 pub fn is_visible(&self, row_in_vector: u32, snapshot_ts: u64, commit_history: &HashMap<u64, u64>) -> bool {
79 if let Ok(del) = self.deleted.lock() {
82 for (&txn_id, rows) in del.iter() {
83 if rows.contains(&row_in_vector) && is_txn_committed_before(txn_id, snapshot_ts, commit_history) {
84 return false;
85 }
86 }
87 }
88
89 if let Ok(ins) = self.inserted.lock() {
93 for (&txn_id, rows) in ins.iter() {
94 if rows.contains(&row_in_vector) {
95 return is_txn_committed_before(txn_id, snapshot_ts, commit_history);
96 }
97 }
98 }
99
100 true
102 }
103
104 pub fn num_inserters(&self) -> usize {
106 self.inserted.lock().map(|m| m.len()).unwrap_or(0)
107 }
108
109 pub fn num_deleters(&self) -> usize {
111 self.deleted.lock().map(|m| m.len()).unwrap_or(0)
112 }
113}
114
115fn is_txn_committed_before(txn_id: u64, snapshot_ts: u64, commit_history: &HashMap<u64, u64>) -> bool {
117 commit_history
118 .get(&txn_id)
119 .is_some_and(|&commit_ts| commit_ts <= snapshot_ts)
120}
121
122#[derive(Debug)]
129pub struct VersionInfo {
130 vectors: Vec<VectorVersionInfo>,
132 vector_size: u32,
134}
135
136impl Clone for VersionInfo {
137 fn clone(&self) -> Self {
138 Self {
139 vectors: self.vectors.clone(),
140 vector_size: self.vector_size,
141 }
142 }
143}
144
145impl VersionInfo {
146 pub fn new(total_rows: usize) -> Self {
148 let vector_size = 1024u32;
150 let num_vectors = total_rows.div_ceil(vector_size as usize);
151 let vectors = (0..num_vectors).map(|_| VectorVersionInfo::new()).collect();
152 Self { vectors, vector_size }
153 }
154
155 fn vector_idx(&self, row: u32) -> usize {
156 (row / self.vector_size) as usize
157 }
158
159 fn row_in_vector(&self, row: u32) -> u32 {
160 row % self.vector_size
161 }
162
163 pub fn insert(&self, txn_id: u64, row: u32) {
165 let v_idx = self.vector_idx(row);
166 if v_idx < self.vectors.len() {
167 self.vectors[v_idx].insert(txn_id, self.row_in_vector(row));
168 }
169 }
170
171 pub fn delete(&self, txn_id: u64, row: u32) {
173 let v_idx = self.vector_idx(row);
174 if v_idx < self.vectors.len() {
175 self.vectors[v_idx].delete(txn_id, self.row_in_vector(row));
176 }
177 }
178
179 pub fn reset(&self) {
185 for v in &self.vectors {
186 v.reset();
187 }
188 }
189
190 pub fn num_inserters(&self) -> usize {
192 self.vectors.iter().map(|v| v.num_inserters()).sum()
193 }
194
195 pub fn num_deleters(&self) -> usize {
197 self.vectors.iter().map(|v| v.num_deleters()).sum()
198 }
199
200 pub fn is_visible(&self, row: u32, snapshot_ts: u64, commit_history: &HashMap<u64, u64>) -> bool {
202 let v_idx = self.vector_idx(row);
203 if v_idx < self.vectors.len() {
204 self.vectors[v_idx].is_visible(self.row_in_vector(row), snapshot_ts, commit_history)
205 } else {
206 true }
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214
215 #[test]
216 fn test_version_info_basic() {
217 let vi = VersionInfo::new(NODE_GROUP_SIZE);
218 let history = HashMap::from([(1u64, 10u64), (2u64, 20u64)]);
219
220 vi.insert(1, 5);
221 vi.delete(2, 10);
222
223 assert!(vi.is_visible(5, 10, &history));
225 assert!(!vi.is_visible(10, 20, &history));
227 assert!(vi.is_visible(10, 15, &history));
229 assert!(vi.is_visible(0, 10, &history));
231 }
232
233 #[test]
234 fn test_vector_version_info_insert() {
235 let vvi = VectorVersionInfo::new();
236 vvi.insert(1, 42);
237 let history = HashMap::from([(1u64, 5u64)]);
238
239 assert!(vvi.is_visible(42, 5, &history));
240 assert!(!vvi.is_visible(42, 3, &history)); }
242
243 #[test]
244 fn test_vector_version_info_delete() {
245 let vvi = VectorVersionInfo::new();
246 vvi.delete(1, 7);
247 let history = HashMap::from([(1u64, 10u64)]);
248
249 assert!(!vvi.is_visible(7, 10, &history)); assert!(vvi.is_visible(7, 5, &history)); }
252
253 #[test]
254 fn test_version_info_history_lookup_semantics() {
255 let vi = VersionInfo::new(NODE_GROUP_SIZE);
258 vi.insert(1, 5);
259 vi.delete(2, 10);
260
261 assert!(vi.is_visible(5, 10, &HashMap::from([(1u64, 10u64), (2u64, 20u64)])));
263 assert!(!vi.is_visible(5, 9, &HashMap::from([(1u64, 10u64), (2u64, 20u64)])));
264 assert!(!vi.is_visible(5, 10, &HashMap::from([(2u64, 20u64)])));
266 assert!(!vi.is_visible(10, 20, &HashMap::from([(1u64, 10u64), (2u64, 20u64)])));
268 assert!(!vi.is_visible(5, 10, &HashMap::new()));
271 assert!(vi.is_visible(10, 10, &HashMap::new()));
272 }
273
274 #[test]
275 fn test_version_info_reset_clears_all_records() {
276 let vi = VersionInfo::new(NODE_GROUP_SIZE);
277 let history = HashMap::from([(1u64, 10u64), (2u64, 20u64)]);
278
279 vi.insert(1, 5);
280 vi.delete(2, 10);
281 assert_eq!(vi.num_inserters(), 1);
282 assert_eq!(vi.num_deleters(), 1);
283
284 vi.reset();
285
286 assert_eq!(vi.num_inserters(), 0);
287 assert_eq!(vi.num_deleters(), 0);
288 assert!(vi.is_visible(5, 0, &history));
290 assert!(vi.is_visible(5, 10, &history));
291 assert!(vi.is_visible(10, 0, &history));
292 }
293
294 #[test]
295 fn test_vector_version_info_reset_clears_all_records() {
296 let vvi = VectorVersionInfo::new();
297 vvi.insert(1, 42);
298 vvi.delete(2, 7);
299 assert_eq!(vvi.num_inserters(), 1);
300 assert_eq!(vvi.num_deleters(), 1);
301
302 vvi.reset();
303 assert_eq!(vvi.num_inserters(), 0);
304 assert_eq!(vvi.num_deleters(), 0);
305 assert!(vvi.is_visible(42, 0, &HashMap::from([(1u64, 10u64)])));
306 assert!(vvi.is_visible(7, 0, &HashMap::from([(2u64, 10u64)])));
307 }
308
309 use crate::column_chunk::NODE_GROUP_SIZE;
311}
312
313pub const STORAGE_VERSION: u32 = 1;