1use std::marker::PhantomData;
16use std::path::{Path, PathBuf};
17
18use serde::de::DeserializeOwned;
19use serde::Serialize;
20
21use crate::error::IsamResult;
22use crate::index::BTree;
23use crate::store::DataStore;
24
25pub trait DeriveKey<V>: Send + Sync + 'static {
48 type Key: Serialize + DeserializeOwned + Ord + Clone + Send;
50
51 fn derive(value: &V) -> Self::Key;
53}
54
55pub(crate) trait AnySecondaryIndex<K, V>: Send {
62 fn on_insert(&mut self, key: &K, value: &V) -> IsamResult<()>;
65 fn on_update(&mut self, key: &K, old_value: &V, new_value: &V) -> IsamResult<()>;
66 fn on_delete(&mut self, key: &K, value: &V) -> IsamResult<()>;
67
68 fn undo_insert(&mut self, key: &K, value: &V) -> IsamResult<()>;
71 fn undo_update(&mut self, key: &K, old_value: &V, new_value: &V) -> IsamResult<()>;
72 fn undo_delete(&mut self, key: &K, value: &V) -> IsamResult<()>;
73
74 fn lookup_primary_keys(&mut self, sk_bytes: &[u8]) -> IsamResult<Vec<K>>;
76
77 fn fsync(&mut self) -> IsamResult<()>;
78 fn name(&self) -> &str;
79}
80
81pub(crate) struct SecondaryIndexImpl<K, V, E>
88where
89 E: DeriveKey<V>,
90{
91 name: String,
92 store: DataStore,
93 btree: BTree<E::Key>,
94 _phantom: PhantomData<(K, V)>,
95}
96
97impl<K, V, E> SecondaryIndexImpl<K, V, E>
98where
99 K: Serialize + DeserializeOwned + Ord + Clone + Send,
100 V: Send,
101 E: DeriveKey<V>,
102{
103 pub(crate) fn create(name: &str, base: &Path) -> IsamResult<Self> {
105 Ok(Self {
106 name: name.to_owned(),
107 store: DataStore::create(&sidb_path(base, name))?,
108 btree: BTree::create(&sidx_path(base, name))?,
109 _phantom: PhantomData,
110 })
111 }
112
113 pub(crate) fn open(name: &str, base: &Path) -> IsamResult<Self> {
115 Ok(Self {
116 name: name.to_owned(),
117 store: DataStore::open(&sidb_path(base, name))?,
118 btree: BTree::open(&sidx_path(base, name))?,
119 _phantom: PhantomData,
120 })
121 }
122
123 pub(crate) fn create_or_open(name: &str, base: &Path) -> IsamResult<Self> {
125 if sidb_path(base, name).exists() {
126 Self::open(name, base)
127 } else {
128 Self::create(name, base)
129 }
130 }
131
132 fn read_pks(&mut self, sk: &E::Key) -> IsamResult<Vec<K>> {
136 match self.btree.search(sk)? {
137 None => Ok(Vec::new()),
138 Some(rec) => self.store.read_value(rec),
139 }
140 }
141
142 fn write_pks(&mut self, sk: &E::Key, pks: &[K]) -> IsamResult<()> {
144 let exists = self.btree.search(sk)?.is_some();
145 let rec = self.store.append(sk, &pks)?;
146 if exists {
147 self.btree.update(sk, rec)?;
148 } else {
149 self.btree.insert(sk, rec)?;
150 }
151 Ok(())
152 }
153
154 fn add_pk(&mut self, sk: &E::Key, pk: &K) -> IsamResult<()> {
156 let mut pks = self.read_pks(sk)?;
157 if !pks.contains(pk) {
158 pks.push(pk.clone());
159 self.write_pks(sk, &pks)?;
160 }
161 Ok(())
162 }
163
164 fn remove_pk(&mut self, sk: &E::Key, pk: &K) -> IsamResult<()> {
166 let mut pks = self.read_pks(sk)?;
167 pks.retain(|k| k != pk);
168 if pks.is_empty() {
169 let _ = self.btree.delete(sk);
171 } else {
172 self.write_pks(sk, &pks)?;
173 }
174 Ok(())
175 }
176}
177
178impl<K, V, E> AnySecondaryIndex<K, V> for SecondaryIndexImpl<K, V, E>
179where
180 K: Serialize + DeserializeOwned + Ord + Clone + Send,
181 V: Send,
182 E: DeriveKey<V>,
183{
184 fn on_insert(&mut self, key: &K, value: &V) -> IsamResult<()> {
185 let sk = E::derive(value);
186 self.add_pk(&sk, key)
187 }
188
189 fn on_update(&mut self, key: &K, old_value: &V, new_value: &V) -> IsamResult<()> {
190 let old_sk = E::derive(old_value);
191 let new_sk = E::derive(new_value);
192 if old_sk != new_sk {
193 self.remove_pk(&old_sk, key)?;
194 self.add_pk(&new_sk, key)?;
195 }
196 Ok(())
197 }
198
199 fn on_delete(&mut self, key: &K, value: &V) -> IsamResult<()> {
200 let sk = E::derive(value);
201 self.remove_pk(&sk, key)
202 }
203
204 fn undo_insert(&mut self, key: &K, value: &V) -> IsamResult<()> {
207 self.on_delete(key, value)
208 }
209
210 fn undo_update(&mut self, key: &K, old_value: &V, new_value: &V) -> IsamResult<()> {
211 self.on_update(key, new_value, old_value)
213 }
214
215 fn undo_delete(&mut self, key: &K, value: &V) -> IsamResult<()> {
216 self.on_insert(key, value)
217 }
218
219 fn lookup_primary_keys(&mut self, sk_bytes: &[u8]) -> IsamResult<Vec<K>> {
220 let sk: E::Key = bincode::deserialize(sk_bytes)?;
221 self.read_pks(&sk)
222 }
223
224 fn fsync(&mut self) -> IsamResult<()> {
225 self.store.fsync()?;
226 self.btree.fsync()
227 }
228
229 fn name(&self) -> &str {
230 &self.name
231 }
232}
233
234pub(crate) fn sidb_path(base: &Path, name: &str) -> PathBuf {
237 let parent = base.parent().unwrap_or(Path::new(""));
238 let stem = base.file_stem().unwrap_or_default().to_string_lossy();
239 parent.join(format!("{stem}_{name}.sidb"))
240}
241
242pub(crate) fn sidx_path(base: &Path, name: &str) -> PathBuf {
243 let parent = base.parent().unwrap_or(Path::new(""));
244 let stem = base.file_stem().unwrap_or_default().to_string_lossy();
245 parent.join(format!("{stem}_{name}.sidx"))
246}