1use reifydb_codec::{
5 encoded::row::EncodedRow,
6 key::encoded::{EncodedKey, EncodedKeyRange},
7};
8use reifydb_value::{Result, util::cowvec::CowVec};
9
10use crate::{
11 common::CommitVersion,
12 delta::Delta,
13 interface::catalog::{flow::FlowNodeId, shape::ShapeId},
14 key::{
15 EncodableKeyRange, Key, flow_node_internal_state::FlowNodeInternalStateKeyRange,
16 flow_node_state::FlowNodeStateKeyRange, kind::KeyKind, partitioned_row::PartitionedRowKeyRange,
17 row::RowKeyRange,
18 },
19};
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub enum Tier {
23 Buffer,
24 Persistent,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub enum EntryKind {
29 Multi,
30
31 Source(ShapeId),
32
33 PartitionedSource(ShapeId),
34
35 Operator(FlowNodeId),
36
37 OperatorInternal(FlowNodeId),
38}
39
40pub fn classify_key(key: &EncodedKey) -> EntryKind {
41 match Key::decode(key) {
42 Some(Key::Row(row_key)) => EntryKind::Source(row_key.shape),
43 Some(Key::PartitionedRow(partitioned_key)) => EntryKind::PartitionedSource(partitioned_key.shape),
44 Some(Key::FlowNodeState(state_key)) => EntryKind::Operator(state_key.node),
45 Some(Key::FlowNodeInternalState(internal_key)) => EntryKind::OperatorInternal(internal_key.node),
46 _ => EntryKind::Multi,
47 }
48}
49
50pub fn is_single_version_semantics_key(key: &EncodedKey) -> bool {
51 Key::kind(key).is_some_and(|kind| matches!(kind, KeyKind::FlowNodeState | KeyKind::FlowNodeInternalState))
52}
53
54pub fn classify_range(range: &EncodedKeyRange) -> Option<EntryKind> {
55 if let (Some(start), Some(_end)) = RowKeyRange::decode(range) {
56 return Some(EntryKind::Source(start.shape));
57 }
58
59 if let (Some(start), Some(_end)) = PartitionedRowKeyRange::decode(range) {
60 return Some(EntryKind::PartitionedSource(start.shape));
61 }
62
63 if let (Some(start), Some(_end)) = FlowNodeStateKeyRange::decode(range) {
64 return Some(EntryKind::Operator(start.node));
65 }
66
67 if let (Some(start), Some(_end)) = FlowNodeInternalStateKeyRange::decode(range) {
68 return Some(EntryKind::OperatorInternal(start.node));
69 }
70
71 None
72}
73
74#[derive(Debug, Clone)]
75pub struct MultiVersionRow {
76 pub key: EncodedKey,
77 pub row: EncodedRow,
78 pub version: CommitVersion,
79}
80
81#[derive(Debug, Clone)]
82pub struct SingleVersionRow {
83 pub key: EncodedKey,
84 pub row: EncodedRow,
85}
86
87#[derive(Debug, Clone)]
88pub struct MultiVersionBatch {
89 pub items: Vec<MultiVersionRow>,
90
91 pub has_more: bool,
92}
93
94impl MultiVersionBatch {
95 pub fn empty() -> Self {
96 Self {
97 items: Vec::new(),
98 has_more: false,
99 }
100 }
101
102 pub fn is_empty(&self) -> bool {
103 self.items.is_empty()
104 }
105}
106
107pub trait MultiVersionCommit: Send + Sync {
108 fn commit(&self, deltas: CowVec<Delta>, version: CommitVersion) -> Result<()>;
109}
110
111#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
112pub struct ReadOptions {
113 pub bypass_buffer: bool,
114}
115
116pub trait MultiVersionGet: Send + Sync {
117 fn get(&self, key: &EncodedKey, version: CommitVersion) -> Result<Option<MultiVersionRow>>;
118
119 fn get_with_options(
120 &self,
121 key: &EncodedKey,
122 version: CommitVersion,
123 _options: ReadOptions,
124 ) -> Result<Option<MultiVersionRow>> {
125 self.get(key, version)
126 }
127}
128
129pub trait MultiVersionContains: Send + Sync {
130 fn contains(&self, key: &EncodedKey, version: CommitVersion) -> Result<bool>;
131
132 fn contains_with_options(
133 &self,
134 key: &EncodedKey,
135 version: CommitVersion,
136 _options: ReadOptions,
137 ) -> Result<bool> {
138 self.contains(key, version)
139 }
140}
141
142pub trait MultiVersionGetPrevious: Send + Sync {
143 fn get_previous_version(
144 &self,
145 key: &EncodedKey,
146 before_version: CommitVersion,
147 ) -> Result<Option<MultiVersionRow>>;
148}
149
150pub trait MultiVersionStore:
151 Send + Sync + Clone + MultiVersionCommit + MultiVersionGet + MultiVersionGetPrevious + MultiVersionContains + 'static
152{
153}
154
155#[derive(Debug, Clone)]
156pub struct SingleVersionBatch {
157 pub items: Vec<SingleVersionRow>,
158
159 pub has_more: bool,
160}
161
162impl SingleVersionBatch {
163 pub fn empty() -> Self {
164 Self {
165 items: Vec::new(),
166 has_more: false,
167 }
168 }
169
170 pub fn is_empty(&self) -> bool {
171 self.items.is_empty()
172 }
173}
174
175pub trait SingleVersionCommit: Send + Sync {
176 fn commit(&mut self, deltas: CowVec<Delta>) -> Result<()>;
177}
178
179pub trait SingleVersionGet: Send + Sync {
180 fn get(&self, key: &EncodedKey) -> Result<Option<SingleVersionRow>>;
181}
182
183pub trait SingleVersionContains: Send + Sync {
184 fn contains(&self, key: &EncodedKey) -> Result<bool>;
185}
186
187pub trait SingleVersionSet: SingleVersionCommit {
188 fn set(&mut self, key: &EncodedKey, row: EncodedRow) -> Result<()> {
189 Self::commit(
190 self,
191 CowVec::new(vec![Delta::Set {
192 key: key.clone(),
193 row: row.clone(),
194 }]),
195 )
196 }
197}
198
199pub trait SingleVersionRemove: SingleVersionCommit {
200 fn unset(&mut self, key: &EncodedKey, row: EncodedRow) -> Result<()> {
201 Self::commit(
202 self,
203 CowVec::new(vec![Delta::Unset {
204 key: key.clone(),
205 row,
206 }]),
207 )
208 }
209
210 fn remove(&mut self, key: &EncodedKey) -> Result<()> {
211 Self::commit(
212 self,
213 CowVec::new(vec![Delta::Remove {
214 key: key.clone(),
215 }]),
216 )
217 }
218}
219
220pub trait SingleVersionRange: Send + Sync {
221 fn range_batch(&self, range: EncodedKeyRange, batch_size: u64) -> Result<SingleVersionBatch>;
222
223 fn range(&self, range: EncodedKeyRange) -> Result<SingleVersionBatch> {
224 self.range_batch(range, 1024)
225 }
226
227 fn prefix(&self, prefix: &EncodedKey) -> Result<SingleVersionBatch> {
228 self.range(EncodedKeyRange::prefix(prefix))
229 }
230}
231
232pub trait SingleVersionRangeRev: Send + Sync {
233 fn range_rev_batch(&self, range: EncodedKeyRange, batch_size: u64) -> Result<SingleVersionBatch>;
234
235 fn range_rev(&self, range: EncodedKeyRange) -> Result<SingleVersionBatch> {
236 self.range_rev_batch(range, 1024)
237 }
238
239 fn prefix_rev(&self, prefix: &EncodedKey) -> Result<SingleVersionBatch> {
240 self.range_rev(EncodedKeyRange::prefix(prefix))
241 }
242}
243
244pub trait SingleVersionStore:
245 Send
246 + Sync
247 + Clone
248 + SingleVersionCommit
249 + SingleVersionGet
250 + SingleVersionContains
251 + SingleVersionSet
252 + SingleVersionRemove
253 + SingleVersionRange
254 + SingleVersionRangeRev
255 + 'static
256{
257}
258
259#[cfg(test)]
260mod tests {
261 use reifydb_value::value::{Value, partition::Partition, row_number::RowNumber};
262
263 use super::{EntryKind, classify_key, classify_range};
264 use crate::{
265 interface::catalog::{id::TableId, shape::ShapeId},
266 key::{
267 partitioned_row::{PartitionedRowKey, RowLocator},
268 row::RowKey,
269 },
270 };
271
272 fn part(v: &str) -> Partition {
273 Partition::of(&[Value::Utf8(v.to_string())])
274 }
275
276 #[test]
277 fn classify_key_partitioned_row_is_partitioned_source() {
278 let shape = ShapeId::Table(TableId(7));
279 let key = PartitionedRowKey::encoded(shape, part("us"), RowLocator::Row(RowNumber(1)));
280 assert_eq!(classify_key(&key), EntryKind::PartitionedSource(shape));
281 }
282
283 #[test]
284 fn classify_key_row_is_still_source() {
285 let shape = ShapeId::Table(TableId(7));
286 let key = RowKey::encoded(shape, RowNumber(1));
287 assert_eq!(classify_key(&key), EntryKind::Source(shape));
288 }
289
290 #[test]
291 fn classify_range_all_partition_forms_are_partitioned_source() {
292 let shape = ShapeId::Table(TableId(9));
293 let p = part("us");
294 let last = PartitionedRowKey::encoded(shape, p, RowLocator::Row(RowNumber(5)));
295 assert_eq!(
296 classify_range(&PartitionedRowKey::partition_range(shape, p)),
297 Some(EntryKind::PartitionedSource(shape))
298 );
299 assert_eq!(
300 classify_range(&PartitionedRowKey::partition_scan_range(shape, p, Some(&last))),
301 Some(EntryKind::PartitionedSource(shape))
302 );
303 assert_eq!(
304 classify_range(&PartitionedRowKey::scan_range(shape, None)),
305 Some(EntryKind::PartitionedSource(shape))
306 );
307 assert_eq!(
308 classify_range(&PartitionedRowKey::full_scan(shape)),
309 Some(EntryKind::PartitionedSource(shape))
310 );
311 }
312
313 #[test]
314 fn classify_range_row_range_is_still_source() {
315 let shape = ShapeId::Table(TableId(9));
316 assert_eq!(classify_range(&RowKey::full_scan(shape)), Some(EntryKind::Source(shape)));
317 }
318}