Skip to main content

reifydb_store_multi/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 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_type::Result;
27
28pub mod buffer;
29pub mod flush;
30pub mod gc;
31pub mod persistent;
32pub mod tier;
33
34pub mod config;
35pub mod multi;
36pub mod store;
37
38use config::{BufferConfig, MultiStoreConfig};
39use reifydb_core::{
40	common::CommitVersion,
41	delta::Delta,
42	encoded::key::{EncodedKey, EncodedKeyRange},
43	interface::store::{
44		MultiVersionCommit, MultiVersionContains, MultiVersionGet, MultiVersionGetPrevious, MultiVersionRow,
45		MultiVersionStore,
46	},
47};
48use reifydb_type::util::cowvec::CowVec;
49use store::StandardMultiStore;
50
51pub mod memory {}
52pub mod sqlite {}
53
54pub struct MultiStoreVersion;
55
56impl HasVersion for MultiStoreVersion {
57	fn version(&self) -> SystemVersion {
58		SystemVersion {
59			name: env!("CARGO_PKG_NAME")
60				.strip_prefix("reifydb-")
61				.unwrap_or(env!("CARGO_PKG_NAME"))
62				.to_string(),
63			version: env!("CARGO_PKG_VERSION").to_string(),
64			description: "Multi-version storage for OLTP operations with MVCC support".to_string(),
65			r#type: ComponentType::Module,
66		}
67	}
68}
69
70#[repr(u8)]
71#[derive(Clone)]
72pub enum MultiStore {
73	Standard(StandardMultiStore) = 0,
74}
75
76impl MultiStore {
77	pub fn standard(config: MultiStoreConfig) -> Self {
78		Self::Standard(StandardMultiStore::new(config).unwrap())
79	}
80}
81
82impl MultiStore {
83	pub fn testing_memory() -> Self {
84		MultiStore::Standard(StandardMultiStore::testing_memory())
85	}
86
87	pub fn testing_memory_with_eventbus(event_bus: EventBus) -> Self {
88		MultiStore::Standard(StandardMultiStore::testing_memory_with_eventbus(event_bus))
89	}
90
91	#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
92	pub fn testing_memory_with_persistent_sqlite() -> Self {
93		MultiStore::Standard(StandardMultiStore::testing_memory_with_persistent_sqlite())
94	}
95
96	#[cfg(all(feature = "sqlite", not(target_arch = "wasm32")))]
97	pub fn testing_memory_with_persistent_sqlite_with_eventbus(event_bus: EventBus) -> Self {
98		MultiStore::Standard(StandardMultiStore::testing_memory_with_persistent_sqlite_with_eventbus(event_bus))
99	}
100
101	pub fn flush_pending_blocking(&self) {
102		match self {
103			MultiStore::Standard(store) => store.flush_pending_blocking(),
104		}
105	}
106
107	pub fn buffer(&self) -> Option<&buffer::tier::MultiBufferTier> {
108		match self {
109			MultiStore::Standard(store) => store.buffer(),
110		}
111	}
112
113	pub fn persistent(&self) -> Option<&persistent::MultiPersistentTier> {
114		match self {
115			MultiStore::Standard(store) => store.persistent(),
116		}
117	}
118}
119
120impl MultiVersionGet for MultiStore {
121	#[inline]
122	fn get(&self, key: &EncodedKey, version: CommitVersion) -> Result<Option<MultiVersionRow>> {
123		match self {
124			MultiStore::Standard(store) => MultiVersionGet::get(store, key, version),
125		}
126	}
127}
128
129impl MultiVersionContains for MultiStore {
130	#[inline]
131	fn contains(&self, key: &EncodedKey, version: CommitVersion) -> Result<bool> {
132		match self {
133			MultiStore::Standard(store) => MultiVersionContains::contains(store, key, version),
134		}
135	}
136}
137
138impl MultiVersionCommit for MultiStore {
139	#[inline]
140	fn commit(&self, deltas: CowVec<Delta>, version: CommitVersion) -> Result<()> {
141		match self {
142			MultiStore::Standard(store) => store.commit(deltas, version),
143		}
144	}
145}
146
147impl MultiVersionGetPrevious for MultiStore {
148	#[inline]
149	fn get_previous_version(
150		&self,
151		key: &EncodedKey,
152		before_version: CommitVersion,
153	) -> Result<Option<MultiVersionRow>> {
154		match self {
155			MultiStore::Standard(store) => store.get_previous_version(key, before_version),
156		}
157	}
158}
159
160pub type MultiVersionRangeIterator<'a> = Box<dyn Iterator<Item = Result<MultiVersionRow>> + Send + 'a>;
161
162impl MultiStore {
163	pub fn range(
164		&self,
165		range: EncodedKeyRange,
166		version: CommitVersion,
167		batch_size: usize,
168	) -> MultiVersionRangeIterator<'_> {
169		match self {
170			MultiStore::Standard(store) => Box::new(store.range(range, version, batch_size)),
171		}
172	}
173
174	pub fn range_rev(
175		&self,
176		range: EncodedKeyRange,
177		version: CommitVersion,
178		batch_size: usize,
179	) -> MultiVersionRangeIterator<'_> {
180		match self {
181			MultiStore::Standard(store) => Box::new(store.range_rev(range, version, batch_size)),
182		}
183	}
184}
185
186impl MultiVersionStore for MultiStore {}