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