1use ailake_catalog::provider::DeletionVector;
11use ailake_core::{AilakeError, AilakeResult};
12use ailake_store::Store;
13use roaring::RoaringBitmap;
14use std::sync::Arc;
15
16pub async fn load_deletion_vector(
27 store: &Arc<dyn Store>,
28 dv: &DeletionVector,
29) -> AilakeResult<RoaringBitmap> {
30 let bytes = store
31 .get_range(&dv.path, dv.offset..dv.offset + dv.length)
32 .await?;
33
34 RoaringBitmap::deserialize_from(bytes.as_ref()).map_err(|e| {
35 AilakeError::Io(std::io::Error::other(format!(
36 "ailake: failed to deserialize Deletion Vector bitmap from '{}' \
37 (offset={}, length={}): {e}",
38 dv.path, dv.offset, dv.length
39 )))
40 })
41}
42
43#[inline]
47pub fn has_deletions(bitmap: &RoaringBitmap, row_ids: &[u64]) -> bool {
48 row_ids.iter().any(|&id| bitmap.contains(id as u32))
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use ailake_store::LocalStore;
55 use bytes::Bytes;
56 use roaring::RoaringBitmap;
57
58 fn make_bitmap_bytes(deleted: &[u32]) -> Vec<u8> {
59 let mut bm = RoaringBitmap::new();
60 for &r in deleted {
61 bm.insert(r);
62 }
63 let mut buf = Vec::new();
64 bm.serialize_into(&mut buf).unwrap();
65 buf
66 }
67
68 #[tokio::test]
69 async fn load_dv_roundtrip() {
70 let dir = tempfile::tempdir().unwrap();
71 let bitmap_bytes = make_bitmap_bytes(&[0, 5, 42, 1000]);
72
73 let offset: u64 = 16; let mut file_bytes = vec![0u8; offset as usize]; file_bytes.extend_from_slice(&bitmap_bytes);
79
80 let dvd_path = "data/dv-0001.dvd";
81 let store: Arc<dyn Store> = Arc::new(LocalStore::new(dir.path()));
82 store.put(dvd_path, Bytes::from(file_bytes)).await.unwrap();
83
84 let dv = DeletionVector {
85 path: dvd_path.to_string(),
86 offset,
87 length: bitmap_bytes.len() as u64,
88 cardinality: 4,
89 };
90
91 let bm = load_deletion_vector(&store, &dv).await.unwrap();
92 assert!(bm.contains(0));
93 assert!(bm.contains(5));
94 assert!(bm.contains(42));
95 assert!(bm.contains(1000));
96 assert!(!bm.contains(1)); assert_eq!(bm.len(), 4);
98 }
99
100 #[test]
101 fn has_deletions_detects_overlap() {
102 let mut bm = RoaringBitmap::new();
103 bm.insert(10);
104 bm.insert(20);
105
106 assert!(has_deletions(&bm, &[5, 10, 15])); assert!(!has_deletions(&bm, &[1, 2, 3])); }
109}