mentedb_index/
temporal.rs1use std::collections::BTreeMap;
4
5use ahash::HashMap;
6use parking_lot::RwLock;
7use serde::{Deserialize, Serialize};
8
9use mentedb_core::error::{MenteError, MenteResult};
10use mentedb_core::types::{MemoryId, Timestamp};
11
12pub struct TemporalIndex {
14 inner: RwLock<TemporalInner>,
15}
16
17struct TemporalInner {
18 tree: BTreeMap<Timestamp, Vec<MemoryId>>,
20 id_to_ts: HashMap<MemoryId, Timestamp>,
22}
23
24impl TemporalIndex {
25 pub fn new() -> Self {
27 Self {
28 inner: RwLock::new(TemporalInner {
29 tree: BTreeMap::new(),
30 id_to_ts: HashMap::default(),
31 }),
32 }
33 }
34
35 pub fn insert(&self, id: MemoryId, timestamp: Timestamp) {
37 let mut inner = self.inner.write();
38 inner.tree.entry(timestamp).or_default().push(id);
39 inner.id_to_ts.insert(id, timestamp);
40 }
41
42 pub fn range(&self, start: Timestamp, end: Timestamp) -> Vec<MemoryId> {
44 let inner = self.inner.read();
45 inner
46 .tree
47 .range(start..=end)
48 .flat_map(|(_, ids)| ids.iter().copied())
49 .collect()
50 }
51
52 pub fn latest(&self, n: usize) -> Vec<MemoryId> {
54 let inner = self.inner.read();
55 let mut results = Vec::with_capacity(n);
56 for (_, ids) in inner.tree.iter().rev() {
57 for &id in ids.iter().rev() {
58 results.push(id);
59 if results.len() >= n {
60 return results;
61 }
62 }
63 }
64 results
65 }
66
67 pub fn remove(&self, id: MemoryId, timestamp: Timestamp) {
69 let mut inner = self.inner.write();
70 if let Some(ids) = inner.tree.get_mut(×tamp) {
71 ids.retain(|&i| i != id);
72 if ids.is_empty() {
73 inner.tree.remove(×tamp);
74 }
75 }
76 inner.id_to_ts.remove(&id);
77 }
78
79 pub fn remove_by_id(&self, id: MemoryId) {
81 let mut inner = self.inner.write();
82 if let Some(ts) = inner.id_to_ts.remove(&id)
83 && let Some(ids) = inner.tree.get_mut(&ts)
84 {
85 ids.retain(|&i| i != id);
86 if ids.is_empty() {
87 inner.tree.remove(&ts);
88 }
89 }
90 }
91
92 pub fn get_timestamp(&self, id: MemoryId) -> Option<Timestamp> {
94 let inner = self.inner.read();
95 inner.id_to_ts.get(&id).copied()
96 }
97}
98
99#[derive(Serialize, Deserialize)]
101struct TemporalSnapshot {
102 tree: Vec<(Timestamp, Vec<MemoryId>)>,
103 id_to_ts: Vec<(MemoryId, Timestamp)>,
104}
105
106impl TemporalIndex {
107 pub fn save(&self, path: &std::path::Path) -> MenteResult<()> {
109 let inner = self.inner.read();
110 let snapshot = TemporalSnapshot {
111 tree: inner.tree.iter().map(|(&k, v)| (k, v.clone())).collect(),
112 id_to_ts: inner.id_to_ts.iter().map(|(&k, &v)| (k, v)).collect(),
113 };
114 let data =
115 bincode::serialize(&snapshot).map_err(|e| MenteError::Serialization(e.to_string()))?;
116 std::fs::write(path, data)?;
117 Ok(())
118 }
119
120 pub fn load(path: &std::path::Path) -> MenteResult<Self> {
122 let data = std::fs::read(path)?;
123 let snapshot: TemporalSnapshot = bincode::deserialize(&data)
124 .or_else(|_| serde_json::from_slice(&data))
125 .map_err(|e| MenteError::Serialization(e.to_string()))?;
126
127 let mut tree = BTreeMap::new();
128 for (ts, ids) in snapshot.tree {
129 tree.insert(ts, ids);
130 }
131
132 let mut id_to_ts = HashMap::default();
133 for (id, ts) in snapshot.id_to_ts {
134 id_to_ts.insert(id, ts);
135 }
136
137 Ok(Self {
138 inner: RwLock::new(TemporalInner { tree, id_to_ts }),
139 })
140 }
141}
142
143impl Default for TemporalIndex {
144 fn default() -> Self {
145 Self::new()
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 #[test]
154 fn test_insert_and_range() {
155 let idx = TemporalIndex::new();
156 let a = MemoryId::new();
157 let b = MemoryId::new();
158 let c = MemoryId::new();
159
160 idx.insert(a, 100);
161 idx.insert(b, 200);
162 idx.insert(c, 300);
163
164 let result = idx.range(100, 200);
165 assert_eq!(result.len(), 2);
166 assert!(result.contains(&a));
167 assert!(result.contains(&b));
168 }
169
170 #[test]
171 fn test_latest() {
172 let idx = TemporalIndex::new();
173 let a = MemoryId::new();
174 let b = MemoryId::new();
175 let c = MemoryId::new();
176
177 idx.insert(a, 100);
178 idx.insert(b, 200);
179 idx.insert(c, 300);
180
181 let latest = idx.latest(2);
182 assert_eq!(latest.len(), 2);
183 assert_eq!(latest[0], c);
184 assert_eq!(latest[1], b);
185 }
186
187 #[test]
188 fn test_remove() {
189 let idx = TemporalIndex::new();
190 let a = MemoryId::new();
191 idx.insert(a, 100);
192 idx.remove(a, 100);
193
194 assert!(idx.range(0, 1000).is_empty());
195 }
196
197 #[test]
198 fn test_remove_by_id() {
199 let idx = TemporalIndex::new();
200 let a = MemoryId::new();
201 idx.insert(a, 500);
202 idx.remove_by_id(a);
203
204 assert!(idx.range(0, 1000).is_empty());
205 }
206
207 #[test]
208 fn test_empty_range() {
209 let idx = TemporalIndex::new();
210 assert!(idx.range(0, 100).is_empty());
211 }
212}