mongreldb_core/index/
bitmap.rs1use crate::rowid::RowId;
7use roaring::RoaringBitmap;
8use std::collections::HashMap;
9use std::sync::Arc;
10
11type BitmapLayer = HashMap<Vec<u8>, RoaringBitmap>;
12
13#[derive(Clone)]
16pub struct BitmapIndex {
17 frozen: Arc<Vec<Arc<BitmapLayer>>>,
18 active: BitmapLayer,
19}
20
21impl Default for BitmapIndex {
22 fn default() -> Self {
23 Self::new()
24 }
25}
26
27impl BitmapIndex {
28 pub fn new() -> Self {
29 Self {
30 frozen: Arc::new(Vec::new()),
31 active: HashMap::new(),
32 }
33 }
34
35 pub fn insert(&mut self, value: Vec<u8>, row_id: RowId) {
36 let id32 = u32::try_from(row_id.0)
40 .expect("bitmap index supports row_id < 2^32; shard-by-high-bits is a Phase-3 upgrade");
41 self.active.entry(value).or_default().insert(id32);
42 }
43
44 pub fn remove(&mut self, value: &[u8], row_id: RowId) -> bool {
50 let Ok(id32) = u32::try_from(row_id.0) else {
51 return false;
52 };
53 let mut removed = false;
54 if let Some(bm) = self.active.get_mut(value) {
55 removed |= bm.remove(id32);
56 if bm.is_empty() {
57 self.active.remove(value);
58 }
59 }
60 let mut new_frozen: Option<Vec<Arc<BitmapLayer>>> = None;
63 for (i, layer) in self.frozen.iter().enumerate() {
64 if layer.get(value).is_some_and(|bm| bm.contains(id32)) {
65 let layers = new_frozen
66 .get_or_insert_with(|| self.frozen.iter().cloned().collect::<Vec<_>>());
67 let mut owned = (*layers[i]).clone();
68 if let Some(bm) = owned.get_mut(value) {
69 if bm.remove(id32) {
70 removed = true;
71 if bm.is_empty() {
72 owned.remove(value);
73 }
74 }
75 }
76 layers[i] = Arc::new(owned);
77 }
78 }
79 if let Some(layers) = new_frozen {
80 self.frozen = Arc::new(layers);
81 }
82 removed
83 }
84
85 #[cfg(test)]
87 pub fn contains(&self, value: &[u8], row_id: RowId) -> bool {
88 let Ok(id32) = u32::try_from(row_id.0) else {
89 return false;
90 };
91 if self.active.get(value).is_some_and(|bm| bm.contains(id32)) {
92 return true;
93 }
94 self.frozen
95 .iter()
96 .any(|layer| layer.get(value).is_some_and(|bm| bm.contains(id32)))
97 }
98
99 pub fn get(&self, value: &[u8]) -> RoaringBitmap {
101 let mut rows = self.active.get(value).cloned().unwrap_or_default();
102 for layer in self.frozen.iter() {
103 if let Some(layer_rows) = layer.get(value) {
104 rows |= layer_rows;
105 }
106 }
107 rows
108 }
109
110 pub fn intersect(sets: &[RoaringBitmap]) -> RoaringBitmap {
112 match sets {
113 [] => RoaringBitmap::new(),
114 [first, rest @ ..] => {
115 let mut acc = first.clone();
116 for s in rest {
117 acc &= s;
118 }
119 acc
120 }
121 }
122 }
123
124 pub fn value_count(&self) -> usize {
125 self.keys().len()
126 }
127
128 pub fn keys(&self) -> Vec<Vec<u8>> {
130 let mut keys = std::collections::HashSet::new();
131 keys.extend(self.active.keys().cloned());
132 for layer in self.frozen.iter() {
133 keys.extend(layer.keys().cloned());
134 }
135 keys.into_iter().collect()
136 }
137
138 pub fn entries(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
141 self.keys()
142 .into_iter()
143 .map(|k| {
144 let v = self.get(&k);
145 let mut bytes = Vec::new();
146 v.serialize_into(&mut bytes)
147 .expect("roaring serialize is infallible for Vec");
148 (k, bytes)
149 })
150 .collect()
151 }
152
153 pub fn from_entries(
155 entries: Vec<(Vec<u8>, Vec<u8>)>,
156 ) -> std::result::Result<Self, &'static str> {
157 let mut active = HashMap::new();
158 for (k, bytes) in entries {
159 let bm = RoaringBitmap::deserialize_from(&bytes[..]).map_err(|_| "bad bitmap bytes")?;
160 active.insert(k, bm);
161 }
162 Ok(Self {
163 frozen: Arc::new(Vec::new()),
164 active,
165 })
166 }
167
168 pub(crate) fn seal(&mut self) {
169 if self.active.is_empty() {
170 return;
171 }
172 let active = std::mem::take(&mut self.active);
173 Arc::make_mut(&mut self.frozen).push(Arc::new(active));
174 if self.frozen.len() >= crate::MAX_READ_GENERATION_LAYERS {
175 self.consolidate();
176 }
177 }
178
179 fn consolidate(&mut self) {
180 let mut merged = HashMap::<Vec<u8>, RoaringBitmap>::new();
181 for layer in self.frozen.iter() {
182 for (key, rows) in layer.iter() {
183 *merged.entry(key.clone()).or_default() |= rows;
184 }
185 }
186 self.frozen = Arc::new(vec![Arc::new(merged)]);
187 }
188
189 #[cfg(test)]
190 pub(crate) fn frozen_layer_count(&self) -> usize {
191 self.frozen.len()
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn insert_get_and_intersect() {
201 let mut color = BitmapIndex::new();
202 color.insert(b"red".to_vec(), RowId(1));
203 color.insert(b"red".to_vec(), RowId(3));
204 color.insert(b"blue".to_vec(), RowId(3));
205
206 let mut region = BitmapIndex::new();
207 region.insert(b"us".to_vec(), RowId(1));
208 region.insert(b"us".to_vec(), RowId(3));
209 region.insert(b"eu".to_vec(), RowId(2));
210
211 let red = color.get(b"red");
212 let us = region.get(b"us");
213 let both = BitmapIndex::intersect(&[red, us]);
214 let ids: Vec<u32> = both.iter().collect();
215 assert_eq!(ids, vec![1, 3]);
216 }
217
218 #[test]
219 fn remove_drops_membership_across_active_and_sealed() {
220 let mut idx = BitmapIndex::new();
221 idx.insert(b"tok".to_vec(), RowId(1));
222 idx.insert(b"tok".to_vec(), RowId(2));
223 idx.seal();
224 idx.insert(b"tok".to_vec(), RowId(3));
225 assert!(idx.contains(b"tok", RowId(1)));
226 assert!(idx.remove(b"tok", RowId(1)));
227 assert!(!idx.contains(b"tok", RowId(1)));
228 assert!(idx.contains(b"tok", RowId(2)));
229 assert!(idx.contains(b"tok", RowId(3)));
230 assert!(idx.remove(b"tok", RowId(3)));
231 assert!(!idx.contains(b"tok", RowId(3)));
232 assert!(!idx.remove(b"missing", RowId(9)));
233 }
234
235 #[test]
236 fn sealed_generations_share_bitmaps_and_consolidate() {
237 let mut writer = BitmapIndex::new();
238 for id in 0..crate::MAX_READ_GENERATION_LAYERS as u64 + 2 {
239 writer.insert(b"all".to_vec(), RowId(id));
240 writer.seal();
241 }
242 assert!(writer.frozen_layer_count() < crate::MAX_READ_GENERATION_LAYERS);
243 let generation = writer.clone();
244 writer.insert(b"new".to_vec(), RowId(99));
245 assert!(generation.get(b"new").is_empty());
246 assert!(writer.get(b"new").contains(99));
247 }
248}