1use std::io::Cursor;
4
5use ahash::HashMap;
6use parking_lot::RwLock;
7use roaring::RoaringBitmap;
8use serde::{Deserialize, Serialize};
9
10use mentedb_core::error::{MenteError, MenteResult};
11use mentedb_core::types::MemoryId;
12
13pub struct BitmapIndex {
18 inner: RwLock<BitmapInner>,
19}
20
21struct BitmapInner {
22 tag_bitmaps: HashMap<String, RoaringBitmap>,
24 id_to_offset: HashMap<MemoryId, u32>,
26 offset_to_id: Vec<MemoryId>,
28}
29
30impl BitmapIndex {
31 pub fn new() -> Self {
33 Self {
34 inner: RwLock::new(BitmapInner {
35 tag_bitmaps: HashMap::default(),
36 id_to_offset: HashMap::default(),
37 offset_to_id: Vec::new(),
38 }),
39 }
40 }
41
42 fn ensure_offset(inner: &mut BitmapInner, id: MemoryId) -> u32 {
44 if let Some(&offset) = inner.id_to_offset.get(&id) {
45 return offset;
46 }
47 let offset = inner.offset_to_id.len() as u32;
48 inner.id_to_offset.insert(id, offset);
49 inner.offset_to_id.push(id);
50 offset
51 }
52
53 pub fn add_tag(&self, id: MemoryId, tag: &str) {
55 let mut inner = self.inner.write();
56 let offset = Self::ensure_offset(&mut inner, id);
57 inner
58 .tag_bitmaps
59 .entry(tag.to_string())
60 .or_default()
61 .insert(offset);
62 }
63
64 pub fn remove_tag(&self, id: MemoryId, tag: &str) {
66 let mut inner = self.inner.write();
67 if let Some(&offset) = inner.id_to_offset.get(&id)
68 && let Some(bm) = inner.tag_bitmaps.get_mut(tag)
69 {
70 bm.remove(offset);
71 }
72 }
73
74 pub fn query_tag(&self, tag: &str) -> Vec<MemoryId> {
76 let inner = self.inner.read();
77 match inner.tag_bitmaps.get(tag) {
78 Some(bm) => bm
79 .iter()
80 .filter_map(|offset| inner.offset_to_id.get(offset as usize).copied())
81 .collect(),
82 None => Vec::new(),
83 }
84 }
85
86 pub fn tags_with_prefix(&self, prefix: &str) -> Vec<String> {
90 let inner = self.inner.read();
91 inner
92 .tag_bitmaps
93 .keys()
94 .filter(|t| t.starts_with(prefix))
95 .cloned()
96 .collect()
97 }
98
99 pub fn query_tags_and(&self, tags: &[&str]) -> Vec<MemoryId> {
101 let inner = self.inner.read();
102 if tags.is_empty() {
103 return Vec::new();
104 }
105
106 let mut result: Option<RoaringBitmap> = None;
107 for tag in tags {
108 match inner.tag_bitmaps.get(*tag) {
109 Some(bm) => {
110 result = Some(match result {
111 Some(r) => r & bm,
112 None => bm.clone(),
113 });
114 }
115 None => return Vec::new(),
116 }
117 }
118
119 match result {
120 Some(bm) => bm
121 .iter()
122 .filter_map(|offset| inner.offset_to_id.get(offset as usize).copied())
123 .collect(),
124 None => Vec::new(),
125 }
126 }
127
128 pub fn query_tags_or(&self, tags: &[&str]) -> Vec<MemoryId> {
130 let inner = self.inner.read();
131 if tags.is_empty() {
132 return Vec::new();
133 }
134
135 let mut result = RoaringBitmap::new();
136 for tag in tags {
137 if let Some(bm) = inner.tag_bitmaps.get(*tag) {
138 result |= bm;
139 }
140 }
141
142 result
143 .iter()
144 .filter_map(|offset| inner.offset_to_id.get(offset as usize).copied())
145 .collect()
146 }
147
148 pub fn remove_all(&self, id: MemoryId) {
150 let mut inner = self.inner.write();
151 if let Some(&offset) = inner.id_to_offset.get(&id) {
152 for bm in inner.tag_bitmaps.values_mut() {
153 bm.remove(offset);
154 }
155 }
156 }
157}
158
159#[derive(Serialize, Deserialize)]
161struct BitmapSnapshot {
162 tag_bitmaps: Vec<(String, Vec<u8>)>,
164 id_to_offset: Vec<(MemoryId, u32)>,
165 offset_to_id: Vec<MemoryId>,
166}
167
168impl BitmapIndex {
169 pub fn save(&self, path: &std::path::Path) -> MenteResult<()> {
171 let inner = self.inner.read();
172 let mut tag_bitmaps = Vec::new();
173 for (tag, bm) in &inner.tag_bitmaps {
174 let mut buf = Vec::new();
175 bm.serialize_into(&mut buf)
176 .map_err(|e| MenteError::Serialization(e.to_string()))?;
177 tag_bitmaps.push((tag.clone(), buf));
178 }
179 let snapshot = BitmapSnapshot {
180 tag_bitmaps,
181 id_to_offset: inner.id_to_offset.iter().map(|(&k, &v)| (k, v)).collect(),
182 offset_to_id: inner.offset_to_id.clone(),
183 };
184 let data =
185 bincode::serialize(&snapshot).map_err(|e| MenteError::Serialization(e.to_string()))?;
186 std::fs::write(path, data)?;
187 Ok(())
188 }
189
190 pub fn load(path: &std::path::Path) -> MenteResult<Self> {
192 let data = std::fs::read(path)?;
193 let snapshot: BitmapSnapshot = bincode::deserialize(&data)
194 .or_else(|_| serde_json::from_slice(&data))
195 .map_err(|e| MenteError::Serialization(e.to_string()))?;
196
197 let mut tag_bitmaps = HashMap::default();
198 for (tag, bytes) in snapshot.tag_bitmaps {
199 let bm = RoaringBitmap::deserialize_from(&mut Cursor::new(bytes))
200 .map_err(|e| MenteError::Serialization(e.to_string()))?;
201 tag_bitmaps.insert(tag, bm);
202 }
203
204 let mut id_to_offset = HashMap::default();
205 for (id, offset) in snapshot.id_to_offset {
206 id_to_offset.insert(id, offset);
207 }
208
209 Ok(Self {
210 inner: RwLock::new(BitmapInner {
211 tag_bitmaps,
212 id_to_offset,
213 offset_to_id: snapshot.offset_to_id,
214 }),
215 })
216 }
217}
218
219impl Default for BitmapIndex {
220 fn default() -> Self {
221 Self::new()
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn test_add_and_query_tag() {
231 let idx = BitmapIndex::new();
232 let id = MemoryId::new();
233 idx.add_tag(id, "important");
234
235 let results = idx.query_tag("important");
236 assert_eq!(results, vec![id]);
237 }
238
239 #[test]
240 fn test_query_empty_tag() {
241 let idx = BitmapIndex::new();
242 assert!(idx.query_tag("nonexistent").is_empty());
243 }
244
245 #[test]
246 fn test_remove_tag() {
247 let idx = BitmapIndex::new();
248 let id = MemoryId::new();
249 idx.add_tag(id, "foo");
250 idx.remove_tag(id, "foo");
251
252 assert!(idx.query_tag("foo").is_empty());
253 }
254
255 #[test]
256 fn test_tags_and() {
257 let idx = BitmapIndex::new();
258 let a = MemoryId::new();
259 let b = MemoryId::new();
260
261 idx.add_tag(a, "x");
262 idx.add_tag(a, "y");
263 idx.add_tag(b, "x");
264
265 let both = idx.query_tags_and(&["x", "y"]);
266 assert_eq!(both, vec![a]);
267 }
268
269 #[test]
270 fn test_tags_or() {
271 let idx = BitmapIndex::new();
272 let a = MemoryId::new();
273 let b = MemoryId::new();
274
275 idx.add_tag(a, "x");
276 idx.add_tag(b, "y");
277
278 let either = idx.query_tags_or(&["x", "y"]);
279 assert_eq!(either.len(), 2);
280 }
281
282 #[test]
283 fn test_remove_all() {
284 let idx = BitmapIndex::new();
285 let id = MemoryId::new();
286 idx.add_tag(id, "a");
287 idx.add_tag(id, "b");
288 idx.remove_all(id);
289
290 assert!(idx.query_tag("a").is_empty());
291 assert!(idx.query_tag("b").is_empty());
292 }
293}