1use std::ops::Bound;
9
10use reifydb_codec::key::encoded::EncodedKey;
11use reifydb_core::{common::CommitVersion, interface::store::EntryKind};
12use reifydb_runtime::shutdown::Shutdown;
13#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
14use reifydb_sqlite::{SqliteConfig, SqliteTempPathGuard};
15use reifydb_value::{Result, value::datetime::DateTime};
16
17use crate::{
18 MultiVersionScope,
19 tier::{
20 DisplacedValues, RangeBatch, RangeCursor, RawEntry, TierBackend, TierBatch, TierStorage,
21 VersionedGetResult,
22 },
23};
24
25#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
26pub mod sqlite;
27
28#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
29use sqlite::storage::{SqlitePageCacheMetrics, SqlitePersistentStorage};
30
31#[derive(Clone)]
32#[cfg_attr(all(feature = "sqlite", not(target_arch = "wasm32")), repr(u8))]
33pub enum MultiPersistentTier {
34 #[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
35 Sqlite(SqlitePersistentStorage) = 0,
36}
37
38impl Shutdown for MultiPersistentTier {
39 fn shutdown(&self) {
40 match self {
41 #[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
42 Self::Sqlite(s) => s.shutdown(),
43 #[cfg(not(all(feature = "sqlite", not(target_arch = "wasm32"))))]
44 _ => {}
45 }
46 }
47}
48
49#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
50impl MultiPersistentTier {
51 pub fn sqlite(config: SqliteConfig) -> Self {
52 Self::Sqlite(SqlitePersistentStorage::new(config))
53 }
54
55 pub fn page_cache_metrics(&self) -> SqlitePageCacheMetrics {
56 match self {
57 Self::Sqlite(storage) => storage.page_cache_metrics(),
58 }
59 }
60
61 pub fn sqlite_in_memory() -> (Self, SqliteTempPathGuard) {
62 let (storage, guard) = SqlitePersistentStorage::in_memory();
63 (Self::Sqlite(storage), guard)
64 }
65
66 pub fn set_checkpoint_threshold(&self, frames: u32) {
67 match self {
68 Self::Sqlite(s) => s.set_checkpoint_threshold(frames),
69 }
70 }
71
72 pub fn delete_below_version(
73 &self,
74 table: EntryKind,
75 cutoff_version: CommitVersion,
76 prefix: Option<&[u8]>,
77 cursor: Option<&[u8]>,
78 limit: usize,
79 ) -> Result<(Vec<EncodedKey>, Option<EncodedKey>)> {
80 match self {
81 Self::Sqlite(s) => s.delete_below_version(table, cutoff_version, prefix, cursor, limit),
82 }
83 }
84
85 pub fn delete_keys(&self, table: EntryKind, keys: &[EncodedKey]) -> Result<u64> {
86 match self {
87 Self::Sqlite(s) => s.delete_keys(table, keys),
88 }
89 }
90
91 pub fn expired_keys(
92 &self,
93 table: EntryKind,
94 cutoff: DateTime,
95 cursor: Option<(DateTime, &[u8])>,
96 limit: usize,
97 ) -> Result<Vec<(EncodedKey, DateTime)>> {
98 match self {
99 Self::Sqlite(s) => s.expired_keys(table, cutoff, cursor, limit),
100 }
101 }
102
103 pub fn list_current_entries(&self) -> Result<Vec<EntryKind>> {
104 match self {
105 Self::Sqlite(s) => s.list_current_entries(),
106 }
107 }
108
109 pub fn reap_tombstones(
110 &self,
111 kind: EntryKind,
112 cutoff_version: CommitVersion,
113 limit: usize,
114 ) -> Result<(u64, bool)> {
115 match self {
116 Self::Sqlite(s) => s.reap_tombstones(kind, cutoff_version, limit),
117 }
118 }
119
120 pub fn set_collecting_accepted(&self, version: CommitVersion, batches: TierBatch) -> Result<Vec<EncodedKey>> {
121 match self {
122 Self::Sqlite(s) => s.set_collecting_accepted(version, batches),
123 }
124 }
125
126 pub fn persist_sweep(&self, batches: Vec<(CommitVersion, TierBatch)>) -> Result<Vec<EncodedKey>> {
127 match self {
128 Self::Sqlite(s) => s.persist_sweep(batches),
129 }
130 }
131
132 pub fn load_range_consistent(
133 &self,
134 table: EntryKind,
135 start: Bound<&[u8]>,
136 end: Bound<&[u8]>,
137 read: CommitVersion,
138 limit: Option<usize>,
139 ) -> Result<Vec<RawEntry>> {
140 match self {
141 Self::Sqlite(s) => s.load_range_consistent(table, start, end, read, limit),
142 }
143 }
144}
145
146#[cfg(not(all(feature = "sqlite", not(target_arch = "wasm32"))))]
147impl MultiPersistentTier {
148 pub fn set_checkpoint_threshold(&self, _frames: u32) {
149 match *self {}
150 }
151
152 pub fn delete_below_version(
153 &self,
154 _table: EntryKind,
155 _cutoff_version: CommitVersion,
156 _prefix: Option<&[u8]>,
157 _cursor: Option<&[u8]>,
158 _limit: usize,
159 ) -> Result<(Vec<EncodedKey>, Option<EncodedKey>)> {
160 match *self {}
161 }
162
163 pub fn delete_keys(&self, _table: EntryKind, _keys: &[EncodedKey]) -> Result<u64> {
164 match *self {}
165 }
166
167 pub fn expired_keys(
168 &self,
169 _table: EntryKind,
170 _cutoff: DateTime,
171 _cursor: Option<(DateTime, &[u8])>,
172 _limit: usize,
173 ) -> Result<Vec<(EncodedKey, DateTime)>> {
174 match *self {}
175 }
176
177 pub fn list_current_entries(&self) -> Result<Vec<EntryKind>> {
178 match *self {}
179 }
180
181 pub fn reap_tombstones(
182 &self,
183 _kind: EntryKind,
184 _cutoff_version: CommitVersion,
185 _limit: usize,
186 ) -> Result<(u64, bool)> {
187 match *self {}
188 }
189
190 pub fn persist_sweep(&self, _batches: Vec<(CommitVersion, TierBatch)>) -> Result<Vec<EncodedKey>> {
191 match *self {}
192 }
193
194 pub fn load_range_consistent(
195 &self,
196 _table: EntryKind,
197 _start: Bound<&[u8]>,
198 _end: Bound<&[u8]>,
199 _read: CommitVersion,
200 _limit: Option<usize>,
201 ) -> Result<Vec<RawEntry>> {
202 match *self {}
203 }
204}
205
206#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
207impl TierStorage for MultiPersistentTier {
208 fn get(&self, table: EntryKind, key: &[u8], version: CommitVersion) -> Result<VersionedGetResult> {
209 match self {
210 Self::Sqlite(s) => s.get(table, key, version),
211 }
212 }
213
214 fn get_many(
215 &self,
216 table: EntryKind,
217 keys: &[&[u8]],
218 version: CommitVersion,
219 ) -> Result<Vec<VersionedGetResult>> {
220 match self {
221 Self::Sqlite(s) => s.get_many(table, keys, version),
222 }
223 }
224
225 fn set(&self, version: CommitVersion, batches: TierBatch) -> Result<DisplacedValues> {
226 match self {
227 Self::Sqlite(s) => s.set(version, batches),
228 }
229 }
230
231 fn range_next(
232 &self,
233 table: EntryKind,
234 cursor: &mut RangeCursor,
235 start: Bound<&[u8]>,
236 end: Bound<&[u8]>,
237 scope: MultiVersionScope,
238 batch_size: usize,
239 ) -> Result<RangeBatch> {
240 match self {
241 Self::Sqlite(s) => s.range_next(table, cursor, start, end, scope, batch_size),
242 }
243 }
244
245 fn range_rev_next(
246 &self,
247 table: EntryKind,
248 cursor: &mut RangeCursor,
249 start: Bound<&[u8]>,
250 end: Bound<&[u8]>,
251 scope: MultiVersionScope,
252 batch_size: usize,
253 ) -> Result<RangeBatch> {
254 match self {
255 Self::Sqlite(s) => s.range_rev_next(table, cursor, start, end, scope, batch_size),
256 }
257 }
258
259 fn ensure_table(&self, table: EntryKind) -> Result<()> {
260 match self {
261 Self::Sqlite(s) => s.ensure_table(table),
262 }
263 }
264
265 fn clear_table(&self, table: EntryKind) -> Result<()> {
266 match self {
267 Self::Sqlite(s) => s.clear_table(table),
268 }
269 }
270}
271
272#[cfg(not(all(feature = "sqlite", not(target_arch = "wasm32"))))]
273impl TierStorage for MultiPersistentTier {
274 fn get(&self, _table: EntryKind, _key: &[u8], _version: CommitVersion) -> Result<VersionedGetResult> {
275 match *self {}
276 }
277
278 fn set(&self, _version: CommitVersion, _batches: TierBatch) -> Result<DisplacedValues> {
279 match *self {}
280 }
281
282 fn range_next(
283 &self,
284 _table: EntryKind,
285 _cursor: &mut RangeCursor,
286 _start: Bound<&[u8]>,
287 _end: Bound<&[u8]>,
288 _scope: MultiVersionScope,
289 _batch_size: usize,
290 ) -> Result<RangeBatch> {
291 match *self {}
292 }
293
294 fn range_rev_next(
295 &self,
296 _table: EntryKind,
297 _cursor: &mut RangeCursor,
298 _start: Bound<&[u8]>,
299 _end: Bound<&[u8]>,
300 _scope: MultiVersionScope,
301 _batch_size: usize,
302 ) -> Result<RangeBatch> {
303 match *self {}
304 }
305
306 fn ensure_table(&self, _table: EntryKind) -> Result<()> {
307 match *self {}
308 }
309
310 fn clear_table(&self, _table: EntryKind) -> Result<()> {
311 match *self {}
312 }
313}
314
315impl TierBackend for MultiPersistentTier {}