nodedb_columnar/
delete_bitmap.rs1use roaring::RoaringBitmap;
13
14use crate::error::ColumnarError;
15
16#[derive(Debug, Clone)]
21pub struct DeleteBitmap {
22 inner: RoaringBitmap,
23}
24
25impl DeleteBitmap {
26 pub fn new() -> Self {
28 Self {
29 inner: RoaringBitmap::new(),
30 }
31 }
32
33 pub fn mark_deleted(&mut self, row_idx: u32) -> bool {
35 self.inner.insert(row_idx)
36 }
37
38 pub fn mark_deleted_batch(&mut self, row_indices: &[u32]) {
40 for &idx in row_indices {
41 self.inner.insert(idx);
42 }
43 }
44
45 pub fn is_deleted(&self, row_idx: u32) -> bool {
47 self.inner.contains(row_idx)
48 }
49
50 pub fn deleted_count(&self) -> u64 {
52 self.inner.len()
53 }
54
55 pub fn is_empty(&self) -> bool {
57 self.inner.is_empty()
58 }
59
60 pub fn delete_ratio(&self, total_rows: u64) -> f64 {
65 if total_rows == 0 {
66 return 0.0;
67 }
68 self.inner.len() as f64 / total_rows as f64
69 }
70
71 pub fn should_compact(&self, total_rows: u64, threshold: f64) -> bool {
73 self.delete_ratio(total_rows) > threshold
74 }
75
76 pub fn is_block_fully_deleted(&self, block_start: u32, block_len: u32) -> bool {
81 if block_len == 0 {
82 return true;
83 }
84 let count = self
86 .inner
87 .range(block_start..block_start + block_len)
88 .count() as u32;
89 count == block_len
90 }
91
92 pub fn apply_to_validity(&self, valid: &mut [bool], global_offset: u32) {
97 for (i, v) in valid.iter_mut().enumerate() {
98 if self.inner.contains(global_offset + i as u32) {
99 *v = false;
100 }
101 }
102 }
103
104 pub fn to_bytes(&self) -> Result<Vec<u8>, ColumnarError> {
106 let mut buf = Vec::with_capacity(self.inner.serialized_size());
107 self.inner
108 .serialize_into(&mut buf)
109 .map_err(|e| ColumnarError::Serialization(format!("delete bitmap: {e}")))?;
110 Ok(buf)
111 }
112
113 pub fn from_bytes(data: &[u8]) -> Result<Self, ColumnarError> {
115 let inner = RoaringBitmap::deserialize_from(data)
116 .map_err(|e| ColumnarError::Serialization(format!("delete bitmap: {e}")))?;
117 Ok(Self { inner })
118 }
119
120 pub fn iter(&self) -> impl Iterator<Item = u32> + '_ {
122 self.inner.iter()
123 }
124
125 pub fn unmark_deleted(&mut self, row_idx: u32) -> bool {
131 self.inner.remove(row_idx)
132 }
133
134 pub fn unmark_from(&mut self, start: u32) {
139 self.inner.remove_range(start..);
140 }
141
142 pub fn merge(&mut self, other: &DeleteBitmap) {
147 self.inner |= &other.inner;
148 }
149}
150
151impl Default for DeleteBitmap {
152 fn default() -> Self {
153 Self::new()
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn mark_and_check() {
163 let mut bm = DeleteBitmap::new();
164 assert!(!bm.is_deleted(5));
165 assert!(bm.mark_deleted(5));
166 assert!(bm.is_deleted(5));
167 assert!(!bm.mark_deleted(5)); assert_eq!(bm.deleted_count(), 1);
169 }
170
171 #[test]
172 fn unmark_from_clears_the_tail_only() {
173 let mut bm = DeleteBitmap::new();
174 bm.mark_deleted_batch(&[1, 4, 5, 9]);
175 bm.unmark_from(4);
176 assert!(bm.is_deleted(1));
177 assert!(!bm.is_deleted(4));
178 assert!(!bm.is_deleted(5));
179 assert!(!bm.is_deleted(9));
180 assert_eq!(bm.deleted_count(), 1);
181 }
182
183 #[test]
184 fn batch_delete() {
185 let mut bm = DeleteBitmap::new();
186 bm.mark_deleted_batch(&[1, 3, 5, 7, 9]);
187 assert_eq!(bm.deleted_count(), 5);
188 assert!(bm.is_deleted(3));
189 assert!(!bm.is_deleted(4));
190 }
191
192 #[test]
193 fn serialization_roundtrip() {
194 let mut bm = DeleteBitmap::new();
195 bm.mark_deleted_batch(&[0, 10, 100, 1000, 10000]);
196
197 let bytes = bm.to_bytes().unwrap();
198 let restored = DeleteBitmap::from_bytes(&bytes).expect("deserialize");
199
200 assert_eq!(restored.deleted_count(), 5);
201 assert!(restored.is_deleted(0));
202 assert!(restored.is_deleted(10));
203 assert!(restored.is_deleted(10000));
204 assert!(!restored.is_deleted(50));
205 }
206
207 #[test]
208 fn delete_ratio_reports_fraction_deleted() {
209 let mut bm = DeleteBitmap::new();
210 for i in 0..30 {
211 bm.mark_deleted(i);
212 }
213 assert!((bm.delete_ratio(100) - 0.3).abs() < 0.001);
215 assert_eq!(DeleteBitmap::new().delete_ratio(0), 0.0);
217 assert!(bm.should_compact(100, 0.2));
219 assert!(!bm.should_compact(100, 0.5));
221 }
222
223 #[test]
224 fn block_fully_deleted() {
225 let mut bm = DeleteBitmap::new();
226 for i in 10..20 {
228 bm.mark_deleted(i);
229 }
230 assert!(bm.is_block_fully_deleted(10, 10));
231 assert!(!bm.is_block_fully_deleted(10, 11)); assert!(!bm.is_block_fully_deleted(5, 10)); }
234
235 #[test]
236 fn apply_to_validity() {
237 let mut bm = DeleteBitmap::new();
238 bm.mark_deleted_batch(&[2, 4]);
239
240 let mut valid = vec![true, true, true, true, true];
241 bm.apply_to_validity(&mut valid, 0);
242
243 assert!(valid[0]);
244 assert!(valid[1]);
245 assert!(!valid[2]); assert!(valid[3]);
247 assert!(!valid[4]); }
249
250 #[test]
251 fn apply_to_validity_with_offset() {
252 let mut bm = DeleteBitmap::new();
253 bm.mark_deleted(1025); let mut valid = vec![true; 1024];
256 bm.apply_to_validity(&mut valid, 1024); assert!(valid[0]); assert!(!valid[1]); assert!(valid[2]); }
262
263 #[test]
264 fn merge_bitmaps() {
265 let mut bm1 = DeleteBitmap::new();
266 bm1.mark_deleted_batch(&[1, 2, 3]);
267
268 let mut bm2 = DeleteBitmap::new();
269 bm2.mark_deleted_batch(&[3, 4, 5]);
270
271 bm1.merge(&bm2);
272 assert_eq!(bm1.deleted_count(), 5); }
274
275 #[test]
276 fn empty_bitmap() {
277 let bm = DeleteBitmap::new();
278 assert!(bm.is_empty());
279 assert_eq!(bm.deleted_count(), 0);
280 assert!(!bm.is_deleted(0));
281
282 let bytes = bm.to_bytes().unwrap();
284 let restored = DeleteBitmap::from_bytes(&bytes).expect("deserialize");
285 assert!(restored.is_empty());
286 }
287}