1use std::marker::PhantomData;
16use std::ops::Bound;
17use std::path::{Path, PathBuf};
18
19use serde::de::DeserializeOwned;
20use serde::Serialize;
21
22use crate::error::IsamResult;
23use crate::index::BTree;
24use crate::store::DataStore;
25
26pub trait DeriveKey<V>: Send + Sync + 'static {
80 type Key: Serialize + DeserializeOwned + Ord + Clone + Send;
82
83 fn derive(value: &V) -> Self::Key;
85}
86
87pub(crate) trait AnySecondaryIndex<K, V>: Send {
94 fn on_insert(&mut self, key: &K, value: &V) -> IsamResult<()>;
97 fn on_update(&mut self, key: &K, old_value: &V, new_value: &V) -> IsamResult<()>;
98 fn on_delete(&mut self, key: &K, value: &V) -> IsamResult<()>;
99
100 fn undo_insert(&mut self, key: &K, value: &V) -> IsamResult<()>;
103 fn undo_update(&mut self, key: &K, old_value: &V, new_value: &V) -> IsamResult<()>;
104 fn undo_delete(&mut self, key: &K, value: &V) -> IsamResult<()>;
105
106 fn lookup_primary_keys(&mut self, sk_bytes: &[u8]) -> IsamResult<Vec<K>>;
108
109 fn range_primary_keys(
112 &mut self,
113 start: Bound<&[u8]>,
114 end: Bound<&[u8]>,
115 ) -> IsamResult<Vec<(Vec<u8>, Vec<K>)>>;
116
117 fn fsync(&mut self) -> IsamResult<()>;
118 fn name(&self) -> &str;
119
120 fn extractor_type_name(&self) -> &'static str;
125
126 fn stored_schema_version(&self) -> u32;
128
129 fn persist_schema_version(&mut self, version: u32) -> IsamResult<()>;
131
132 fn reset(&mut self) -> IsamResult<()>;
136}
137
138pub(crate) struct SecondaryIndexImpl<K, V, E>
145where
146 E: DeriveKey<V>,
147{
148 name: String,
149 base: PathBuf,
150 store: DataStore,
151 btree: BTree<E::Key>,
152 _phantom: PhantomData<(K, V)>,
153}
154
155impl<K, V, E> SecondaryIndexImpl<K, V, E>
156where
157 K: Serialize + DeserializeOwned + Ord + Clone + Send,
158 V: Send,
159 E: DeriveKey<V>,
160{
161 pub(crate) fn create(name: &str, base: &Path) -> IsamResult<Self> {
163 Ok(Self {
164 name: name.to_owned(),
165 base: base.to_path_buf(),
166 store: DataStore::create(&sidb_path(base, name))?,
167 btree: BTree::create(&sidx_path(base, name))?,
168 _phantom: PhantomData,
169 })
170 }
171
172 pub(crate) fn open(name: &str, base: &Path) -> IsamResult<Self> {
174 Ok(Self {
175 name: name.to_owned(),
176 base: base.to_path_buf(),
177 store: DataStore::open(&sidb_path(base, name))?,
178 btree: BTree::open(&sidx_path(base, name))?,
179 _phantom: PhantomData,
180 })
181 }
182
183 pub(crate) fn create_or_open(name: &str, base: &Path) -> IsamResult<Self> {
185 if sidb_path(base, name).exists() {
186 Self::open(name, base)
187 } else {
188 Self::create(name, base)
189 }
190 }
191
192 fn read_pks(&mut self, sk: &E::Key) -> IsamResult<Vec<K>> {
196 match self.btree.search(sk)? {
197 None => Ok(Vec::new()),
198 Some(rec) => self.store.read_value(rec),
199 }
200 }
201
202 fn write_pks(&mut self, sk: &E::Key, pks: &[K]) -> IsamResult<()> {
204 let exists = self.btree.search(sk)?.is_some();
205 let rec = self.store.append(sk, &pks)?;
206 if exists {
207 self.btree.update(sk, rec)?;
208 } else {
209 self.btree.insert(sk, rec)?;
210 }
211 Ok(())
212 }
213
214 fn add_pk(&mut self, sk: &E::Key, pk: &K) -> IsamResult<()> {
216 let mut pks = self.read_pks(sk)?;
217 if !pks.contains(pk) {
218 pks.push(pk.clone());
219 self.write_pks(sk, &pks)?;
220 }
221 Ok(())
222 }
223
224 fn remove_pk(&mut self, sk: &E::Key, pk: &K) -> IsamResult<()> {
226 let mut pks = self.read_pks(sk)?;
227 pks.retain(|k| k != pk);
228 if pks.is_empty() {
229 let _ = self.btree.delete(sk);
231 } else {
232 self.write_pks(sk, &pks)?;
233 }
234 Ok(())
235 }
236}
237
238impl<K, V, E> AnySecondaryIndex<K, V> for SecondaryIndexImpl<K, V, E>
239where
240 K: Serialize + DeserializeOwned + Ord + Clone + Send,
241 V: Send,
242 E: DeriveKey<V>,
243{
244 fn on_insert(&mut self, key: &K, value: &V) -> IsamResult<()> {
245 let sk = E::derive(value);
246 self.add_pk(&sk, key)
247 }
248
249 fn on_update(&mut self, key: &K, old_value: &V, new_value: &V) -> IsamResult<()> {
250 let old_sk = E::derive(old_value);
251 let new_sk = E::derive(new_value);
252 if old_sk != new_sk {
253 self.remove_pk(&old_sk, key)?;
254 self.add_pk(&new_sk, key)?;
255 }
256 Ok(())
257 }
258
259 fn on_delete(&mut self, key: &K, value: &V) -> IsamResult<()> {
260 let sk = E::derive(value);
261 self.remove_pk(&sk, key)
262 }
263
264 fn undo_insert(&mut self, key: &K, value: &V) -> IsamResult<()> {
267 self.on_delete(key, value)
268 }
269
270 fn undo_update(&mut self, key: &K, old_value: &V, new_value: &V) -> IsamResult<()> {
271 self.on_update(key, new_value, old_value)
273 }
274
275 fn undo_delete(&mut self, key: &K, value: &V) -> IsamResult<()> {
276 self.on_insert(key, value)
277 }
278
279 fn lookup_primary_keys(&mut self, sk_bytes: &[u8]) -> IsamResult<Vec<K>> {
280 let sk: E::Key = bincode::deserialize(sk_bytes)?;
281 self.read_pks(&sk)
282 }
283
284 fn range_primary_keys(
285 &mut self,
286 start: Bound<&[u8]>,
287 end: Bound<&[u8]>,
288 ) -> IsamResult<Vec<(Vec<u8>, Vec<K>)>> {
289 let start_bound: Bound<E::Key> = match start {
290 Bound::Included(b) => Bound::Included(bincode::deserialize(b)?),
291 Bound::Excluded(b) => Bound::Excluded(bincode::deserialize(b)?),
292 Bound::Unbounded => Bound::Unbounded,
293 };
294 let end_bound: Bound<E::Key> = match end {
295 Bound::Included(b) => Bound::Included(bincode::deserialize(b)?),
296 Bound::Excluded(b) => Bound::Excluded(bincode::deserialize(b)?),
297 Bound::Unbounded => Bound::Unbounded,
298 };
299
300 let start_leaf_id = match &start_bound {
301 Bound::Included(k) | Bound::Excluded(k) => self.btree.find_leaf_for_key(k)?,
302 Bound::Unbounded => self.btree.first_leaf_id()?,
303 };
304
305 let mut results = Vec::new();
306 let mut leaf_id = start_leaf_id;
307
308 'outer: while leaf_id != 0 {
309 let (entries, next_leaf_id) = self.btree.read_leaf(leaf_id)?;
310
311 for (sk, rec) in entries {
312 let in_start = match &start_bound {
313 Bound::Included(lo) => &sk >= lo,
314 Bound::Excluded(lo) => &sk > lo,
315 Bound::Unbounded => true,
316 };
317 let in_end = match &end_bound {
318 Bound::Included(hi) => &sk <= hi,
319 Bound::Excluded(hi) => &sk < hi,
320 Bound::Unbounded => true,
321 };
322
323 if !in_end {
324 break 'outer;
325 }
326 if in_start {
327 let sk_bytes = bincode::serialize(&sk)?;
328 let pks: Vec<K> = self.store.read_value(rec)?;
329 results.push((sk_bytes, pks));
330 }
331 }
332
333 leaf_id = next_leaf_id;
334 }
335
336 Ok(results)
337 }
338
339 fn fsync(&mut self) -> IsamResult<()> {
340 self.store.fsync()?;
341 self.btree.fsync()
342 }
343
344 fn name(&self) -> &str {
345 &self.name
346 }
347
348 fn extractor_type_name(&self) -> &'static str {
349 std::any::type_name::<E>()
350 }
351
352 fn stored_schema_version(&self) -> u32 {
353 self.btree.index_schema_version()
354 }
355
356 fn persist_schema_version(&mut self, version: u32) -> IsamResult<()> {
357 self.btree.set_index_schema_version(version)
358 }
359
360 fn reset(&mut self) -> IsamResult<()> {
361 self.store = DataStore::create(&sidb_path(&self.base, &self.name))?;
362 self.btree = BTree::create(&sidx_path(&self.base, &self.name))?;
363 Ok(())
364 }
365}
366
367pub(crate) fn sidb_path(base: &Path, name: &str) -> PathBuf {
370 let parent = base.parent().unwrap_or(Path::new(""));
371 let stem = base.file_stem().unwrap_or_default().to_string_lossy();
372 parent.join(format!("{stem}_{name}.sidb"))
373}
374
375pub(crate) fn sidx_path(base: &Path, name: &str) -> PathBuf {
376 let parent = base.parent().unwrap_or(Path::new(""));
377 let stem = base.file_stem().unwrap_or_default().to_string_lossy();
378 parent.join(format!("{stem}_{name}.sidx"))
379}