Skip to main content

reifydb_store_multi/tier/persistent/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4//! Cold tier of the multi-version store. Holds the durable, version-history-bearing record of every key the
5//! buffer has flushed. The default backend is SQLite; the trait surface is generic so other backends can be
6//! plugged in without touching the buffer or transaction layer.
7
8use std::{collections::HashMap, 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, util::cowvec::CowVec};
16
17use crate::{
18	MultiVersionScope,
19	tier::{
20		HistoricalCursor, 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::SqlitePersistentStorage;
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub struct CheckpointOutcome {
33	pub log_frames: u32,
34	pub restarted: bool,
35}
36
37#[derive(Clone)]
38#[cfg_attr(all(feature = "sqlite", not(target_arch = "wasm32")), repr(u8))]
39pub enum MultiPersistentTier {
40	#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
41	Sqlite(SqlitePersistentStorage) = 0,
42}
43
44impl Shutdown for MultiPersistentTier {
45	fn shutdown(&self) {
46		match self {
47			#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
48			Self::Sqlite(s) => s.shutdown(),
49			#[cfg(not(all(feature = "sqlite", not(target_arch = "wasm32"))))]
50			_ => {}
51		}
52	}
53}
54
55#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
56impl MultiPersistentTier {
57	pub fn sqlite(config: SqliteConfig) -> Self {
58		Self::Sqlite(SqlitePersistentStorage::new(config))
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 maybe_checkpoint(&self) -> Result<CheckpointOutcome> {
67		match self {
68			Self::Sqlite(s) => s.maybe_checkpoint(),
69		}
70	}
71
72	pub fn reclaim(&self) -> Result<()> {
73		match self {
74			Self::Sqlite(s) => s.reclaim(),
75		}
76	}
77
78	pub fn delete_below_version(
79		&self,
80		table: EntryKind,
81		cutoff_version: CommitVersion,
82		prefix: Option<&[u8]>,
83	) -> Result<Vec<EncodedKey>> {
84		match self {
85			Self::Sqlite(s) => s.delete_below_version(table, cutoff_version, prefix),
86		}
87	}
88
89	pub fn delete_keys(&self, table: EntryKind, keys: &[EncodedKey]) -> Result<u64> {
90		match self {
91			Self::Sqlite(s) => s.delete_keys(table, keys),
92		}
93	}
94
95	pub fn set_collecting_accepted(&self, version: CommitVersion, batches: TierBatch) -> Result<Vec<EncodedKey>> {
96		match self {
97			Self::Sqlite(s) => s.set_collecting_accepted(version, batches),
98		}
99	}
100
101	pub fn load_range_consistent(
102		&self,
103		table: EntryKind,
104		start: Bound<&[u8]>,
105		end: Bound<&[u8]>,
106		read: CommitVersion,
107	) -> Result<Vec<RawEntry>> {
108		match self {
109			Self::Sqlite(s) => s.load_range_consistent(table, start, end, read),
110		}
111	}
112}
113
114#[cfg(not(all(feature = "sqlite", not(target_arch = "wasm32"))))]
115impl MultiPersistentTier {
116	pub fn maybe_checkpoint(&self) -> Result<CheckpointOutcome> {
117		match *self {}
118	}
119
120	pub fn reclaim(&self) -> Result<()> {
121		match *self {}
122	}
123
124	pub fn delete_below_version(
125		&self,
126		_table: EntryKind,
127		_cutoff_version: CommitVersion,
128		_prefix: Option<&[u8]>,
129	) -> Result<Vec<EncodedKey>> {
130		match *self {}
131	}
132
133	pub fn delete_keys(&self, _table: EntryKind, _keys: &[EncodedKey]) -> Result<u64> {
134		match *self {}
135	}
136
137	pub fn load_range_consistent(
138		&self,
139		_table: EntryKind,
140		_start: Bound<&[u8]>,
141		_end: Bound<&[u8]>,
142		_read: CommitVersion,
143	) -> Result<Vec<RawEntry>> {
144		match *self {}
145	}
146}
147
148#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
149impl TierStorage for MultiPersistentTier {
150	fn get(&self, table: EntryKind, key: &[u8], version: CommitVersion) -> Result<VersionedGetResult> {
151		match self {
152			Self::Sqlite(s) => s.get(table, key, version),
153		}
154	}
155
156	fn get_many(
157		&self,
158		table: EntryKind,
159		keys: &[&[u8]],
160		version: CommitVersion,
161	) -> Result<Vec<VersionedGetResult>> {
162		match self {
163			Self::Sqlite(s) => s.get_many(table, keys, version),
164		}
165	}
166
167	fn set(&self, version: CommitVersion, batches: TierBatch) -> Result<()> {
168		match self {
169			Self::Sqlite(s) => s.set(version, batches),
170		}
171	}
172
173	fn range_next(
174		&self,
175		table: EntryKind,
176		cursor: &mut RangeCursor,
177		start: Bound<&[u8]>,
178		end: Bound<&[u8]>,
179		scope: MultiVersionScope,
180		batch_size: usize,
181	) -> Result<RangeBatch> {
182		match self {
183			Self::Sqlite(s) => s.range_next(table, cursor, start, end, scope, batch_size),
184		}
185	}
186
187	fn range_rev_next(
188		&self,
189		table: EntryKind,
190		cursor: &mut RangeCursor,
191		start: Bound<&[u8]>,
192		end: Bound<&[u8]>,
193		scope: MultiVersionScope,
194		batch_size: usize,
195	) -> Result<RangeBatch> {
196		match self {
197			Self::Sqlite(s) => s.range_rev_next(table, cursor, start, end, scope, batch_size),
198		}
199	}
200
201	fn ensure_table(&self, table: EntryKind) -> Result<()> {
202		match self {
203			Self::Sqlite(s) => s.ensure_table(table),
204		}
205	}
206
207	fn clear_table(&self, table: EntryKind) -> Result<()> {
208		match self {
209			Self::Sqlite(s) => s.clear_table(table),
210		}
211	}
212
213	fn drop(&self, batches: HashMap<EntryKind, Vec<(EncodedKey, CommitVersion)>>) -> Result<()> {
214		match self {
215			Self::Sqlite(s) => s.drop(batches),
216		}
217	}
218
219	fn get_all_versions(&self, table: EntryKind, key: &[u8]) -> Result<Vec<(CommitVersion, Option<CowVec<u8>>)>> {
220		match self {
221			Self::Sqlite(s) => s.get_all_versions(table, key),
222		}
223	}
224
225	fn scan_historical_below(
226		&self,
227		table: EntryKind,
228		cutoff: CommitVersion,
229		cursor: &mut HistoricalCursor,
230		batch_size: usize,
231	) -> Result<Vec<(EncodedKey, CommitVersion)>> {
232		match self {
233			Self::Sqlite(s) => s.scan_historical_below(table, cutoff, cursor, batch_size),
234		}
235	}
236}
237
238#[cfg(not(all(feature = "sqlite", not(target_arch = "wasm32"))))]
239impl TierStorage for MultiPersistentTier {
240	fn get(&self, _table: EntryKind, _key: &[u8], _version: CommitVersion) -> Result<VersionedGetResult> {
241		match *self {}
242	}
243
244	fn set(&self, _version: CommitVersion, _batches: TierBatch) -> Result<()> {
245		match *self {}
246	}
247
248	fn range_next(
249		&self,
250		_table: EntryKind,
251		_cursor: &mut RangeCursor,
252		_start: Bound<&[u8]>,
253		_end: Bound<&[u8]>,
254		_scope: MultiVersionScope,
255		_batch_size: usize,
256	) -> Result<RangeBatch> {
257		match *self {}
258	}
259
260	fn range_rev_next(
261		&self,
262		_table: EntryKind,
263		_cursor: &mut RangeCursor,
264		_start: Bound<&[u8]>,
265		_end: Bound<&[u8]>,
266		_scope: MultiVersionScope,
267		_batch_size: usize,
268	) -> Result<RangeBatch> {
269		match *self {}
270	}
271
272	fn ensure_table(&self, _table: EntryKind) -> Result<()> {
273		match *self {}
274	}
275
276	fn clear_table(&self, _table: EntryKind) -> Result<()> {
277		match *self {}
278	}
279
280	fn drop(&self, _batches: HashMap<EntryKind, Vec<(EncodedKey, CommitVersion)>>) -> Result<()> {
281		match *self {}
282	}
283
284	fn get_all_versions(&self, _table: EntryKind, _key: &[u8]) -> Result<Vec<(CommitVersion, Option<CowVec<u8>>)>> {
285		match *self {}
286	}
287
288	fn scan_historical_below(
289		&self,
290		_table: EntryKind,
291		_cutoff: CommitVersion,
292		_cursor: &mut HistoricalCursor,
293		_batch_size: usize,
294	) -> Result<Vec<(EncodedKey, CommitVersion)>> {
295		match *self {}
296	}
297}
298
299impl TierBackend for MultiPersistentTier {}