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