Skip to main content

reifydb_store_multi/
lib.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2026 ReifyDB
3
4//! Multi-version storage backend for OLTP traffic. Implements the `MultiVersionStore` family of traits from
5//! `core::interface::store` so the engine can read at a snapshot, write a new version, and step backwards through
6//! history without coordinating with concurrent readers.
7//!
8//! The backend is tiered: hot writes land in the in-memory buffer, the flusher migrates them to persistent storage
9//! at commit boundaries, and the garbage collector reclaims versions that have aged out behind the configured
10//! retention. The persistent tier is pluggable - a SQLite-backed implementation is the default but the trait surface
11//! is what the engine binds to, so other backends can be slotted in.
12//!
13//! Invariant: a row at `version V` is the value visible to a reader whose snapshot is `>= V` and where no later
14//! version exists at `V' <= snapshot`. Commit must publish all deltas of a transaction atomically with respect to
15//! readers; partial visibility breaks snapshot isolation.
16
17#![cfg_attr(not(debug_assertions), deny(clippy::disallowed_methods))]
18#![cfg_attr(debug_assertions, warn(clippy::disallowed_methods))]
19#![cfg_attr(not(debug_assertions), deny(warnings))]
20#![allow(clippy::tabs_in_doc_comments)]
21
22use reifydb_core::{
23	event::EventBus,
24	interface::version::{ComponentType, HasVersion, SystemVersion},
25};
26use reifydb_value::Result;
27
28pub mod flush;
29pub mod gc;
30pub mod tier;
31
32pub mod config;
33pub mod store;
34
35use std::collections::HashMap;
36
37use config::{CommitBufferConfig, MultiStoreConfig};
38use reifydb_core::{
39	common::CommitVersion,
40	delta::Delta,
41	encoded::key::{EncodedKey, EncodedKeyRange},
42	interface::store::{
43		MultiVersionCommit, MultiVersionContains, MultiVersionGet, MultiVersionGetPrevious, MultiVersionRow,
44		MultiVersionStore,
45	},
46};
47#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
48use reifydb_sqlite::SqliteTempPathGuard;
49use reifydb_value::util::cowvec::CowVec;
50use store::StandardMultiStore;
51
52pub mod memory {}
53pub mod sqlite {}
54
55pub struct MultiStoreVersion;
56
57impl HasVersion for MultiStoreVersion {
58	fn version(&self) -> SystemVersion {
59		SystemVersion {
60			name: env!("CARGO_PKG_NAME")
61				.strip_prefix("reifydb-")
62				.unwrap_or(env!("CARGO_PKG_NAME"))
63				.to_string(),
64			version: env!("CARGO_PKG_VERSION").to_string(),
65			description: "Multi-version storage for OLTP operations with MVCC support".to_string(),
66			r#type: ComponentType::Module,
67		}
68	}
69}
70
71#[repr(u8)]
72#[derive(Clone)]
73pub enum MultiStore {
74	Standard(StandardMultiStore) = 0,
75}
76
77impl MultiStore {
78	pub fn standard(config: MultiStoreConfig) -> Self {
79		Self::Standard(StandardMultiStore::new(config).unwrap())
80	}
81}
82
83impl MultiStore {
84	pub fn testing_memory() -> Self {
85		MultiStore::Standard(StandardMultiStore::testing_memory())
86	}
87
88	pub fn testing_memory_with_eventbus(event_bus: EventBus) -> Self {
89		MultiStore::Standard(StandardMultiStore::testing_memory_with_eventbus(event_bus))
90	}
91
92	#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
93	pub fn testing_memory_with_persistent_sqlite() -> (Self, SqliteTempPathGuard) {
94		let (store, guard) = StandardMultiStore::testing_memory_with_persistent_sqlite();
95		(MultiStore::Standard(store), guard)
96	}
97
98	#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
99	pub fn testing_memory_with_persistent_sqlite_with_eventbus(event_bus: EventBus) -> (Self, SqliteTempPathGuard) {
100		let (store, guard) = StandardMultiStore::testing_memory_with_persistent_sqlite_with_eventbus(event_bus);
101		(MultiStore::Standard(store), guard)
102	}
103
104	pub fn flush_pending_blocking(&self) {
105		match self {
106			MultiStore::Standard(store) => store.flush_pending_blocking(),
107		}
108	}
109
110	pub fn commit(&self) -> Option<&tier::commit::buffer::MultiCommitBufferTier> {
111		match self {
112			MultiStore::Standard(store) => store.commit(),
113		}
114	}
115
116	pub fn persistent(&self) -> Option<&tier::persistent::MultiPersistentTier> {
117		match self {
118			MultiStore::Standard(store) => store.persistent(),
119		}
120	}
121}
122
123impl MultiVersionGet for MultiStore {
124	#[inline]
125	fn get(&self, key: &EncodedKey, version: CommitVersion) -> Result<Option<MultiVersionRow>> {
126		match self {
127			MultiStore::Standard(store) => MultiVersionGet::get(store, key, version),
128		}
129	}
130}
131
132impl MultiVersionContains for MultiStore {
133	#[inline]
134	fn contains(&self, key: &EncodedKey, version: CommitVersion) -> Result<bool> {
135		match self {
136			MultiStore::Standard(store) => MultiVersionContains::contains(store, key, version),
137		}
138	}
139}
140
141impl MultiVersionCommit for MultiStore {
142	#[inline]
143	fn commit(&self, deltas: CowVec<Delta>, version: CommitVersion) -> Result<()> {
144		match self {
145			MultiStore::Standard(store) => MultiVersionCommit::commit(store, deltas, version),
146		}
147	}
148}
149
150impl MultiVersionGetPrevious for MultiStore {
151	#[inline]
152	fn get_previous_version(
153		&self,
154		key: &EncodedKey,
155		before_version: CommitVersion,
156	) -> Result<Option<MultiVersionRow>> {
157		match self {
158			MultiStore::Standard(store) => store.get_previous_version(key, before_version),
159		}
160	}
161}
162
163pub type MultiVersionRangeIterator<'a> = Box<dyn Iterator<Item = Result<MultiVersionRow>> + Send + 'a>;
164
165impl MultiStore {
166	pub fn range(
167		&self,
168		range: EncodedKeyRange,
169		version: CommitVersion,
170		batch_size: usize,
171	) -> MultiVersionRangeIterator<'_> {
172		match self {
173			MultiStore::Standard(store) => Box::new(store.range(range, version, batch_size)),
174		}
175	}
176
177	pub fn range_rev(
178		&self,
179		range: EncodedKeyRange,
180		version: CommitVersion,
181		batch_size: usize,
182	) -> MultiVersionRangeIterator<'_> {
183		match self {
184			MultiStore::Standard(store) => Box::new(store.range_rev(range, version, batch_size)),
185		}
186	}
187
188	pub fn get_many(
189		&self,
190		keys: &[EncodedKey],
191		version: CommitVersion,
192	) -> Result<HashMap<EncodedKey, MultiVersionRow>> {
193		match self {
194			MultiStore::Standard(store) => store.get_many(keys, version),
195		}
196	}
197}
198
199impl MultiVersionStore for MultiStore {}