Skip to main content

reifydb_store_multi/tier/commit/
buffer.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::{collections::HashMap, ops::Bound};
5
6use reifydb_core::{common::CommitVersion, encoded::key::EncodedKey, interface::store::EntryKind};
7use reifydb_value::{Result, util::cowvec::CowVec};
8
9use crate::{
10	MultiVersionScope,
11	tier::{
12		HistoricalCursor, RangeBatch, RangeCursor, TierBackend, TierBatch, TierStorage, VersionedGetResult,
13		commit::memory::storage::MemoryPrimitiveStorage,
14	},
15};
16
17#[derive(Clone)]
18#[repr(u8)]
19pub enum MultiCommitBufferTier {
20	Memory(MemoryPrimitiveStorage) = 0,
21}
22
23impl MultiCommitBufferTier {
24	pub fn memory() -> Self {
25		Self::Memory(MemoryPrimitiveStorage::new())
26	}
27}
28
29impl MultiCommitBufferTier {
30	pub fn maintenance(&self) {
31		match self {
32			Self::Memory(_) => {}
33		}
34	}
35
36	pub fn count_current(&self, table: EntryKind) -> Result<u64> {
37		match self {
38			Self::Memory(s) => s.count_current(table),
39		}
40	}
41
42	pub fn count_historical(&self, table: EntryKind) -> Result<u64> {
43		match self {
44			Self::Memory(s) => s.count_historical(table),
45		}
46	}
47
48	pub fn list_all_entry_kinds(&self) -> Result<Vec<EntryKind>> {
49		match self {
50			Self::Memory(s) => s.list_all_entry_kinds(),
51		}
52	}
53}
54
55impl TierStorage for MultiCommitBufferTier {
56	#[inline]
57	fn get(&self, table: EntryKind, key: &[u8], version: CommitVersion) -> Result<VersionedGetResult> {
58		match self {
59			Self::Memory(s) => s.get(table, key, version),
60		}
61	}
62
63	#[inline]
64	fn contains(&self, table: EntryKind, key: &[u8], version: CommitVersion) -> Result<bool> {
65		match self {
66			Self::Memory(s) => s.contains(table, key, version),
67		}
68	}
69
70	#[inline]
71	fn set(&self, version: CommitVersion, batches: TierBatch) -> Result<()> {
72		match self {
73			Self::Memory(s) => s.set(version, batches),
74		}
75	}
76
77	#[inline]
78	fn range_next(
79		&self,
80		table: EntryKind,
81		cursor: &mut RangeCursor,
82		start: Bound<&[u8]>,
83		end: Bound<&[u8]>,
84		scope: MultiVersionScope,
85		batch_size: usize,
86	) -> Result<RangeBatch> {
87		match self {
88			Self::Memory(s) => s.range_next(table, cursor, start, end, scope, batch_size),
89		}
90	}
91
92	#[inline]
93	fn range_rev_next(
94		&self,
95		table: EntryKind,
96		cursor: &mut RangeCursor,
97		start: Bound<&[u8]>,
98		end: Bound<&[u8]>,
99		scope: MultiVersionScope,
100		batch_size: usize,
101	) -> Result<RangeBatch> {
102		match self {
103			Self::Memory(s) => s.range_rev_next(table, cursor, start, end, scope, batch_size),
104		}
105	}
106
107	#[inline]
108	fn ensure_table(&self, table: EntryKind) -> Result<()> {
109		match self {
110			Self::Memory(s) => s.ensure_table(table),
111		}
112	}
113
114	#[inline]
115	fn clear_table(&self, table: EntryKind) -> Result<()> {
116		match self {
117			Self::Memory(s) => s.clear_table(table),
118		}
119	}
120
121	#[inline]
122	fn drop(&self, batches: HashMap<EntryKind, Vec<(EncodedKey, CommitVersion)>>) -> Result<()> {
123		match self {
124			Self::Memory(s) => s.drop(batches),
125		}
126	}
127
128	#[inline]
129	fn get_all_versions(&self, table: EntryKind, key: &[u8]) -> Result<Vec<(CommitVersion, Option<CowVec<u8>>)>> {
130		match self {
131			Self::Memory(s) => s.get_all_versions(table, key),
132		}
133	}
134
135	#[inline]
136	fn scan_historical_below(
137		&self,
138		table: EntryKind,
139		cutoff: CommitVersion,
140		cursor: &mut HistoricalCursor,
141		batch_size: usize,
142	) -> Result<Vec<(EncodedKey, CommitVersion)>> {
143		match self {
144			Self::Memory(s) => s.scan_historical_below(table, cutoff, cursor, batch_size),
145		}
146	}
147}
148
149impl TierBackend for MultiCommitBufferTier {}
150
151#[cfg(test)]
152pub mod tests {
153	use super::*;
154
155	#[test]
156	fn test_memory_backend() {
157		let storage = MultiCommitBufferTier::memory();
158
159		let key = EncodedKey::new(b"key".to_vec());
160		let version = CommitVersion(1);
161
162		storage.set(
163			version,
164			HashMap::from([(EntryKind::Multi, vec![(key.clone(), Some(CowVec::new(b"value".to_vec())))])]),
165		)
166		.unwrap();
167		assert_eq!(
168			storage.get(EntryKind::Multi, &key, version).unwrap().value().as_deref(),
169			Some(b"value".as_slice())
170		);
171	}
172
173	#[test]
174	fn test_range_next_memory() {
175		let storage = MultiCommitBufferTier::memory();
176
177		let version = CommitVersion(1);
178		storage.set(
179			version,
180			HashMap::from([(
181				EntryKind::Multi,
182				vec![
183					(EncodedKey::new(b"a".to_vec()), Some(CowVec::new(b"1".to_vec()))),
184					(EncodedKey::new(b"b".to_vec()), Some(CowVec::new(b"2".to_vec()))),
185					(EncodedKey::new(b"c".to_vec()), Some(CowVec::new(b"3".to_vec()))),
186				],
187			)]),
188		)
189		.unwrap();
190
191		let mut cursor = RangeCursor::new();
192		let batch = storage
193			.range_next(
194				EntryKind::Multi,
195				&mut cursor,
196				Bound::Unbounded,
197				Bound::Unbounded,
198				MultiVersionScope::AsOf {
199					read: version,
200				},
201				100,
202			)
203			.unwrap();
204
205		assert_eq!(batch.entries.len(), 3);
206		assert!(!batch.has_more);
207		assert!(cursor.exhausted);
208	}
209}