1use reifydb_codec::{
5 key::encoded::{EncodedKey, EncodedKeyRange},
6 row::bytes::EncodedBytes,
7};
8use reifydb_value::{Result, util::cowvec::CowVec};
9use reifydb_wal::lsn::Lsn;
10
11use crate::{
12 common::CommitVersion,
13 delta::Delta,
14 interface::catalog::storage::StorageId,
15 key::{
16 KeyRangeCodec,
17 any::TaggedKey,
18 row::{
19 PartitionedRowKey, PartitionedRowKeyRange, PartitionedSortedViewRowKey, RowKey, RowKeyRange,
20 SortedViewRowKey, StoragePartitionedRowKey, StorageRowKey,
21 },
22 series::{
23 PartitionedSeriesRowKey, PartitionedSeriesRowKeyRange, SeriesRowKey, SeriesRowKeyRange,
24 StoragePartitionedSeriesKey, StorageSeriesKey,
25 },
26 tag::KeyTag,
27 typed::BoundedKey,
28 },
29};
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
32pub enum Tier {
33 Buffer,
34 Persistent,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub enum EntryLayout {
39 Row,
40 Series,
41 SortedView,
42}
43
44impl EntryLayout {
45 pub fn type_tag(&self) -> u8 {
46 match self {
47 Self::Row => 1,
48 Self::Series => 2,
49 Self::SortedView => 3,
50 }
51 }
52
53 pub fn from_type_tag(tag: u8) -> Option<Self> {
54 match tag {
55 1 => Some(Self::Row),
56 2 => Some(Self::Series),
57 3 => Some(Self::SortedView),
58 _ => None,
59 }
60 }
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
64pub enum EntryKind {
65 Multi,
66
67 Source(StorageId, EntryLayout),
68
69 PartitionedSource(StorageId, EntryLayout),
70}
71
72impl EntryKind {
73 pub fn caches_ranges(&self) -> bool {
74 matches!(self, Self::Source(_, EntryLayout::Row | EntryLayout::Series))
75 }
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
79pub enum StorageKey {
80 Table(StorageRowKey),
81 RingBuffer(StorageRowKey),
82 Queue(StorageRowKey),
83 View(StorageRowKey),
84
85 PartitionedTable(StoragePartitionedRowKey),
86 PartitionedRingBuffer(StoragePartitionedRowKey),
87 PartitionedQueue(StoragePartitionedRowKey),
88 PartitionedView(StoragePartitionedRowKey),
89
90 Series(StorageSeriesKey),
91 SeriesView(StorageSeriesKey),
92
93 PartitionedSeries(StoragePartitionedSeriesKey),
94 PartitionedSeriesView(StoragePartitionedSeriesKey),
95}
96
97fn row_storage_key(storage: StorageId, row: StorageRowKey) -> Option<StorageKey> {
98 match storage {
99 StorageId::Table(_) => Some(StorageKey::Table(row)),
100 StorageId::RingBuffer(_) => Some(StorageKey::RingBuffer(row)),
101 StorageId::Queue(_) => Some(StorageKey::Queue(row)),
102 StorageId::View(_) => Some(StorageKey::View(row)),
103 StorageId::Series(_) => None,
104 }
105}
106
107fn partitioned_row_storage_key(storage: StorageId, row: StoragePartitionedRowKey) -> Option<StorageKey> {
108 match storage {
109 StorageId::Table(_) => Some(StorageKey::PartitionedTable(row)),
110 StorageId::RingBuffer(_) => Some(StorageKey::PartitionedRingBuffer(row)),
111 StorageId::Queue(_) => Some(StorageKey::PartitionedQueue(row)),
112 StorageId::View(_) => Some(StorageKey::PartitionedView(row)),
113 StorageId::Series(_) => None,
114 }
115}
116
117fn series_storage_key(storage: StorageId, series: StorageSeriesKey) -> Option<StorageKey> {
118 match storage {
119 StorageId::Series(_) => Some(StorageKey::Series(series)),
120 StorageId::View(_) => Some(StorageKey::SeriesView(series)),
121 StorageId::Table(_) | StorageId::RingBuffer(_) | StorageId::Queue(_) => None,
122 }
123}
124
125fn partitioned_series_storage_key(storage: StorageId, series: StoragePartitionedSeriesKey) -> Option<StorageKey> {
126 match storage {
127 StorageId::Series(_) => Some(StorageKey::PartitionedSeries(series)),
128 StorageId::View(_) => Some(StorageKey::PartitionedSeriesView(series)),
129 StorageId::Table(_) | StorageId::RingBuffer(_) | StorageId::Queue(_) => None,
130 }
131}
132
133fn source_entry(storage: StorageId, layout: EntryLayout, key: Option<StorageKey>) -> (EntryKind, Option<StorageKey>) {
134 match key {
135 Some(key) => (EntryKind::Source(storage, layout), Some(key)),
136 None => (EntryKind::Multi, None),
137 }
138}
139
140fn partitioned_source_entry(
141 storage: StorageId,
142 layout: EntryLayout,
143 key: Option<StorageKey>,
144) -> (EntryKind, Option<StorageKey>) {
145 match key {
146 Some(key) => (EntryKind::PartitionedSource(storage, layout), Some(key)),
147 None => (EntryKind::Multi, None),
148 }
149}
150
151pub fn storage_key(key: &EncodedKey) -> (EntryKind, Option<StorageKey>) {
152 match KeyTag::of(key) {
153 Some(KeyTag::Row) => match RowKey::decode(key) {
154 Some(row_key) => source_entry(
155 row_key.storage,
156 EntryLayout::Row,
157 row_storage_key(row_key.storage, StorageRowKey::new(row_key.row)),
158 ),
159 None => (EntryKind::Multi, None),
160 },
161 Some(KeyTag::SeriesRow) => match SeriesRowKey::decode(key) {
162 Some(series_key) => source_entry(
163 series_key.storage,
164 EntryLayout::Series,
165 series_storage_key(series_key.storage, StorageSeriesKey::from(series_key)),
166 ),
167 None => (EntryKind::Multi, None),
168 },
169 Some(KeyTag::PartitionedRow) => match PartitionedRowKey::decode(key) {
170 Some(partitioned_key) => partitioned_source_entry(
171 partitioned_key.storage,
172 EntryLayout::Row,
173 partitioned_row_storage_key(
174 partitioned_key.storage,
175 StoragePartitionedRowKey::new(partitioned_key.partition, partitioned_key.row),
176 ),
177 ),
178 None => (EntryKind::Multi, None),
179 },
180 Some(KeyTag::PartitionedSeriesRow) => match PartitionedSeriesRowKey::decode(key) {
181 Some(partitioned_key) => partitioned_source_entry(
182 partitioned_key.storage,
183 EntryLayout::Series,
184 partitioned_series_storage_key(
185 partitioned_key.storage,
186 StoragePartitionedSeriesKey::from(partitioned_key),
187 ),
188 ),
189 None => (EntryKind::Multi, None),
190 },
191 Some(KeyTag::SortedViewRow) => match SortedViewRowKey::storage_of(key) {
192 Some(storage) => (EntryKind::Source(storage, EntryLayout::SortedView), None),
193 None => (EntryKind::Multi, None),
194 },
195 Some(KeyTag::PartitionedSortedViewRow) => match PartitionedSortedViewRowKey::storage_of(key) {
196 Some(storage) => (EntryKind::PartitionedSource(storage, EntryLayout::SortedView), None),
197 None => (EntryKind::Multi, None),
198 },
199 _ => (EntryKind::Multi, None),
200 }
201}
202
203pub fn storage_key_of(key: &TaggedKey) -> (EntryKind, Option<StorageKey>) {
204 match key {
205 TaggedKey::Row(row_key) => source_entry(
206 row_key.storage,
207 EntryLayout::Row,
208 row_storage_key(row_key.storage, StorageRowKey::new(row_key.row)),
209 ),
210 TaggedKey::SeriesRow(series_key) => source_entry(
211 series_key.storage,
212 EntryLayout::Series,
213 series_storage_key(series_key.storage, StorageSeriesKey::from(series_key.clone())),
214 ),
215 TaggedKey::PartitionedRow(partitioned_key) => partitioned_source_entry(
216 partitioned_key.storage,
217 EntryLayout::Row,
218 partitioned_row_storage_key(
219 partitioned_key.storage,
220 StoragePartitionedRowKey::new(partitioned_key.partition, partitioned_key.row),
221 ),
222 ),
223 TaggedKey::PartitionedSeriesRow(partitioned_key) => partitioned_source_entry(
224 partitioned_key.storage,
225 EntryLayout::Series,
226 partitioned_series_storage_key(
227 partitioned_key.storage,
228 StoragePartitionedSeriesKey::from(partitioned_key.clone()),
229 ),
230 ),
231 TaggedKey::SortedViewRow(sorted) => (EntryKind::Source(sorted.storage, EntryLayout::SortedView), None),
232 TaggedKey::PartitionedSortedViewRow(sorted) => {
233 (EntryKind::PartitionedSource(sorted.storage, EntryLayout::SortedView), None)
234 }
235 _ => (EntryKind::Multi, None),
236 }
237}
238
239pub fn classify_key_of(key: &TaggedKey) -> EntryKind {
240 storage_key_of(key).0
241}
242
243pub fn classify_key(key: &EncodedKey) -> EntryKind {
244 storage_key(key).0
245}
246
247pub fn classify_range(range: &EncodedKeyRange) -> Option<EntryKind> {
248 if let (Some(start), Some(_end)) = RowKeyRange::decode(range) {
249 return row_storage_key(start.storage, <StorageRowKey as BoundedKey>::low())
250 .map(|_| EntryKind::Source(start.storage, EntryLayout::Row));
251 }
252
253 if let (Some(start), Some(_end)) = SeriesRowKeyRange::decode(range) {
254 return series_storage_key(start, <StorageSeriesKey as BoundedKey>::low())
255 .map(|_| EntryKind::Source(start, EntryLayout::Series));
256 }
257
258 if let (Some(start), Some(_end)) = PartitionedRowKeyRange::decode(range) {
259 return partitioned_row_storage_key(start.storage, <StoragePartitionedRowKey as BoundedKey>::low())
260 .map(|_| EntryKind::PartitionedSource(start.storage, EntryLayout::Row));
261 }
262
263 if let (Some(start), Some(_end)) = PartitionedSeriesRowKeyRange::decode(range) {
264 return partitioned_series_storage_key(start, <StoragePartitionedSeriesKey as BoundedKey>::low())
265 .map(|_| EntryKind::PartitionedSource(start, EntryLayout::Series));
266 }
267
268 if let Some(storage) = SortedViewRowKey::range_storage_of(range) {
269 return Some(EntryKind::Source(storage, EntryLayout::SortedView));
270 }
271
272 if let Some(storage) = PartitionedSortedViewRowKey::range_storage_of(range) {
273 return Some(EntryKind::PartitionedSource(storage, EntryLayout::SortedView));
274 }
275
276 None
277}
278
279#[derive(Debug, Clone)]
280pub struct MultiVersionRow<K = EncodedKey> {
281 pub key: K,
282 pub bytes: EncodedBytes,
283 pub version: CommitVersion,
284}
285
286#[derive(Debug, Clone)]
287pub struct SingleVersionRow {
288 pub key: EncodedKey,
289 pub bytes: EncodedBytes,
290}
291
292#[derive(Debug, Clone)]
293pub struct MultiVersionBatch<K = EncodedKey> {
294 pub items: Vec<MultiVersionRow<K>>,
295
296 pub has_more: bool,
297}
298
299impl<K> MultiVersionBatch<K> {
300 pub fn empty() -> Self {
301 Self {
302 items: Vec::new(),
303 has_more: false,
304 }
305 }
306
307 pub fn is_empty(&self) -> bool {
308 self.items.is_empty()
309 }
310}
311
312pub trait MultiVersionCommit: Send + Sync {
313 fn commit(&self, deltas: CowVec<Delta>, version: CommitVersion) -> Result<()>;
314}
315
316pub trait MultiVersionGet: Send + Sync {
317 fn get(&self, keys: &[TaggedKey], version: CommitVersion) -> Result<Vec<Option<MultiVersionRow<TaggedKey>>>>;
318}
319
320pub trait MultiVersionGetPrevious: Send + Sync {
321 fn get_previous(
322 &self,
323 keys: &[TaggedKey],
324 before_version: CommitVersion,
325 ) -> Result<Vec<Option<MultiVersionRow<TaggedKey>>>>;
326}
327
328pub trait MultiVersionStore:
329 Send + Sync + Clone + MultiVersionCommit + MultiVersionGet + MultiVersionGetPrevious + 'static
330{
331}
332
333pub trait WalCheckpoint: Send + Sync + 'static {
334 fn make_durable(&self) -> Result<CommitVersion>;
335
336 fn saved_through(&self, version: CommitVersion) -> Result<()>;
337}
338
339pub trait SingleWalCheckpoint: Send + Sync + 'static {
340 fn make_durable(&self, through: Lsn) -> Result<()>;
341
342 fn saved_through(&self, through: Lsn) -> Result<()>;
343}
344
345#[derive(Debug, Clone)]
346pub struct SingleVersionBatch {
347 pub items: Vec<SingleVersionRow>,
348
349 pub has_more: bool,
350}
351
352impl SingleVersionBatch {
353 pub fn empty() -> Self {
354 Self {
355 items: Vec::new(),
356 has_more: false,
357 }
358 }
359
360 pub fn is_empty(&self) -> bool {
361 self.items.is_empty()
362 }
363}
364
365pub trait SingleVersionCommit: Send + Sync {
366 fn commit(&mut self, deltas: CowVec<Delta>) -> Result<()>;
367}
368
369pub trait SingleVersionGet: Send + Sync {
370 fn get(&self, keys: &[EncodedKey]) -> Result<Vec<Option<SingleVersionRow>>>;
371}
372
373pub trait SingleVersionRange: Send + Sync {
374 fn range_batch(&self, range: EncodedKeyRange, batch_size: u64) -> Result<SingleVersionBatch>;
375
376 fn range(&self, range: EncodedKeyRange) -> Result<SingleVersionBatch> {
377 self.range_batch(range, 1024)
378 }
379
380 fn prefix(&self, prefix: &EncodedKey) -> Result<SingleVersionBatch> {
381 self.range(EncodedKeyRange::prefix(prefix))
382 }
383}
384
385pub trait SingleVersionRangeRev: Send + Sync {
386 fn range_rev_batch(&self, range: EncodedKeyRange, batch_size: u64) -> Result<SingleVersionBatch>;
387
388 fn range_rev(&self, range: EncodedKeyRange) -> Result<SingleVersionBatch> {
389 self.range_rev_batch(range, 1024)
390 }
391
392 fn prefix_rev(&self, prefix: &EncodedKey) -> Result<SingleVersionBatch> {
393 self.range_rev(EncodedKeyRange::prefix(prefix))
394 }
395}
396
397pub trait SingleVersionStore:
398 Send + Sync + Clone + SingleVersionCommit + SingleVersionGet + SingleVersionRange + SingleVersionRangeRev + 'static
399{
400}
401
402#[cfg(test)]
403#[allow(clippy::disallowed_methods)]
404mod tests {
405 use reifydb_codec::key::encoded::EncodedKey;
406 use reifydb_value::value::{Value, partition::Partition, row_number::RowNumber};
407
408 use super::{EntryKind, EntryLayout, StorageKey, classify_key, classify_range, storage_key};
409 use crate::{
410 interface::catalog::{
411 id::{SeriesId, TableId, ViewId},
412 storage::StorageId,
413 },
414 key::{
415 any::TaggedKey,
416 row::{
417 PartitionedRowKey, PartitionedSortedViewRowKey, RowKey, RowSequenceKey,
418 SortedViewRowKey, StoragePartitionedRowKey, StorageRowKey,
419 },
420 series::{
421 PartitionedSeriesRowKey, PartitionedSeriesRowKeyRange, SeriesRowKey, SeriesRowKeyRange,
422 StoragePartitionedSeriesKey, StorageSeriesKey,
423 },
424 },
425 };
426
427 fn part(v: &str) -> Partition {
428 Partition::of(&[Value::Utf8(v.to_string())])
429 }
430
431 #[test]
432 fn storage_key_hands_back_the_identity_it_decoded() {
433 let storage = StorageId::Table(TableId(7));
436
437 let row = RowKey::encoded(storage, RowNumber(5));
438 assert_eq!(
439 storage_key(&row),
440 (
441 EntryKind::Source(storage, EntryLayout::Row),
442 Some(StorageKey::Table(StorageRowKey::new(RowNumber(5))))
443 )
444 );
445
446 let partitioned = PartitionedRowKey::encoded(storage, part("us"), RowNumber(5));
447 assert_eq!(
448 storage_key(&partitioned),
449 (
450 EntryKind::PartitionedSource(storage, EntryLayout::Row),
451 Some(StorageKey::PartitionedTable(StoragePartitionedRowKey::new(
452 part("us"),
453 RowNumber(5)
454 )))
455 )
456 );
457 }
458
459 #[test]
460 fn storage_key_names_the_storage_a_row_belongs_to() {
461 let row = StorageRowKey::new(RowNumber(5));
464 for (storage, expected) in [
465 (StorageId::table(7), StorageKey::Table(row)),
466 (StorageId::ringbuffer(7), StorageKey::RingBuffer(row)),
467 (StorageId::queue(7), StorageKey::Queue(row)),
468 (StorageId::view(7), StorageKey::View(row)),
469 ] {
470 assert_eq!(storage_key(&RowKey::encoded(storage, RowNumber(5))).1, Some(expected));
471 }
472 }
473
474 #[test]
475 fn a_series_key_carries_its_own_identity_on_a_series_and_on_a_view() {
476 let series = StorageSeriesKey::new(None, 5, 1);
479 for (storage, expected) in [
480 (StorageId::series(7), StorageKey::Series(series)),
481 (StorageId::view(7), StorageKey::SeriesView(series)),
482 ] {
483 let series = SeriesRowKey {
484 storage,
485 variant_tag: None,
486 key: 5,
487 sequence: 1,
488 }
489 .encode();
490 assert_eq!(
491 storage_key(&series),
492 (EntryKind::Source(storage, EntryLayout::Series), Some(expected))
493 );
494 }
495
496 let partitioned = StoragePartitionedSeriesKey::new(part("us"), None, 5, 1);
497 for (storage, expected) in [
498 (StorageId::series(7), StorageKey::PartitionedSeries(partitioned)),
499 (StorageId::view(7), StorageKey::PartitionedSeriesView(partitioned)),
500 ] {
501 let partitioned = PartitionedSeriesRowKey::encoded(storage, part("us"), None, 5, 1);
502 assert_eq!(
503 storage_key(&partitioned),
504 (EntryKind::PartitionedSource(storage, EntryLayout::Series), Some(expected))
505 );
506 }
507 }
508
509 #[test]
510 fn a_view_row_and_a_view_series_row_do_not_share_a_storage_key() {
511 let storage = StorageId::view(7);
514 let row = storage_key(&RowKey::encoded(storage, RowNumber(5))).1.unwrap();
515 let series = storage_key(
516 &SeriesRowKey {
517 storage,
518 variant_tag: None,
519 key: 5,
520 sequence: 5,
521 }
522 .encode(),
523 )
524 .1
525 .unwrap();
526 assert_ne!(row, series);
527 }
528
529 #[test]
530 fn a_layout_its_storage_cannot_hold_claims_no_entry_at_all() {
531 let storage = StorageId::series(7);
534 assert_eq!(storage_key(&RowKey::encoded(storage, RowNumber(5))), (EntryKind::Multi, None));
535
536 let series_on_a_table = SeriesRowKey {
537 storage: StorageId::table(7),
538 variant_tag: None,
539 key: 5,
540 sequence: 1,
541 }
542 .encode();
543 assert_eq!(storage_key(&series_on_a_table), (EntryKind::Multi, None));
544 }
545
546 #[test]
547 fn a_source_entry_never_holds_a_key_without_an_identity() {
548 let series = |storage| {
551 SeriesRowKey {
552 storage,
553 variant_tag: None,
554 key: 5,
555 sequence: 1,
556 }
557 .encode()
558 };
559
560 for storage in [
561 StorageId::table(7),
562 StorageId::ringbuffer(7),
563 StorageId::queue(7),
564 StorageId::view(7),
565 StorageId::series(7),
566 ] {
567 for key in [
568 RowKey::encoded(storage, RowNumber(5)),
569 PartitionedRowKey::encoded(storage, part("us"), RowNumber(5)),
570 series(storage),
571 PartitionedSeriesRowKey::encoded(storage, part("us"), None, 5, 1),
572 RowSequenceKey::encoded(storage),
573 ] {
574 let (entry, ident) = storage_key(&key);
575 match entry {
576 EntryKind::Multi => assert_eq!(ident, None),
577 EntryKind::Source(_, _) | EntryKind::PartitionedSource(_, _) => {
578 assert!(ident.is_some(), "{entry:?} took a key with no identity")
579 }
580 }
581 }
582 }
583 }
584
585 #[test]
586 fn an_entry_never_mixes_the_two_layouts() {
587 let storage = StorageId::view(7);
590 let row = storage_key(&RowKey::encoded(storage, RowNumber(5))).0;
591 let series = storage_key(
592 &SeriesRowKey {
593 storage,
594 variant_tag: None,
595 key: 5,
596 sequence: 1,
597 }
598 .encode(),
599 )
600 .0;
601
602 assert_eq!(row, EntryKind::Source(storage, EntryLayout::Row));
603 assert_eq!(series, EntryKind::Source(storage, EntryLayout::Series));
604
605 let partitioned_row = storage_key(&PartitionedRowKey::encoded(storage, part("us"), RowNumber(5))).0;
606 let partitioned_series =
607 storage_key(&PartitionedSeriesRowKey::encoded(storage, part("us"), None, 5, 1)).0;
608
609 assert_eq!(partitioned_row, EntryKind::PartitionedSource(storage, EntryLayout::Row));
610 assert_eq!(partitioned_series, EntryKind::PartitionedSource(storage, EntryLayout::Series));
611 }
612
613 #[test]
614 fn storage_key_agrees_with_classify_key_on_the_entry() {
615 let storage = StorageId::Table(TableId(7));
616 for key in [
617 RowKey::encoded(storage, RowNumber(5)),
618 PartitionedRowKey::encoded(storage, part("us"), RowNumber(5)),
619 RowSequenceKey::encoded(storage),
620 ] {
621 assert_eq!(storage_key(&key).0, classify_key(&key));
622 }
623 }
624
625 #[test]
626 fn an_over_long_row_kind_key_never_passes_as_a_row() {
627 let storage = StorageId::view(3);
631 let mut over_long = RowKey::encoded(storage, RowNumber(1)).as_slice().to_vec();
632 over_long.extend_from_slice(&[0xAA; 8]);
633 over_long.extend_from_slice(&99u64.to_be_bytes());
634
635 assert_eq!(storage_key(&EncodedKey::new(over_long)), (EntryKind::Multi, None));
636 }
637
638 #[test]
639 fn a_sorted_view_key_and_a_sorted_view_scan_range_classify_the_same_way() {
640 let storage = StorageId::view(3);
644
645 let mut sorted_view = SortedViewRowKey::storage_start(storage).as_slice().to_vec();
646 sorted_view.extend_from_slice(&[0xAA; 8]);
647 sorted_view.extend_from_slice(&99u64.to_be_bytes());
648 let sorted_view = EncodedKey::new(sorted_view);
649 let range = SortedViewRowKey::scan_range(storage, None).encode();
650 assert_eq!(classify_key(&sorted_view), EntryKind::Source(storage, EntryLayout::SortedView));
651 assert_eq!(classify_range(&range).unwrap_or(EntryKind::Multi), classify_key(&sorted_view));
652
653 let mut partitioned = PartitionedSortedViewRowKey::storage_start(storage).as_slice().to_vec();
654 partitioned.extend_from_slice(&[0xBB; 16]);
655 partitioned.extend_from_slice(&[0xAA; 8]);
656 partitioned.extend_from_slice(&99u64.to_be_bytes());
657 let partitioned = EncodedKey::new(partitioned);
658 let partitioned_range = PartitionedSortedViewRowKey::scan_range(storage, None).encode();
659 assert_eq!(classify_key(&partitioned), EntryKind::PartitionedSource(storage, EntryLayout::SortedView));
660 assert_eq!(classify_range(&partitioned_range).unwrap_or(EntryKind::Multi), classify_key(&partitioned));
661 }
662
663 #[test]
664 fn a_sorted_view_scan_range_never_reaches_the_narrowed_row_bucket() {
665 let storage = StorageId::view(3);
668 assert_ne!(
669 classify_range(&SortedViewRowKey::scan_range(storage, None).encode()),
670 Some(EntryKind::Source(storage, EntryLayout::Row))
671 );
672 assert_ne!(
673 classify_range(&PartitionedSortedViewRowKey::scan_range(storage, None).encode()),
674 Some(EntryKind::PartitionedSource(storage, EntryLayout::Row))
675 );
676 }
677
678 #[test]
679 fn storage_key_leaves_a_key_it_does_not_own_without_an_identity() {
680 assert_eq!(
681 storage_key(&RowSequenceKey::encoded(StorageId::Table(TableId(7)))),
682 (EntryKind::Multi, None)
683 );
684 }
685
686 #[test]
687 fn classify_key_partitioned_row_is_partitioned_source() {
688 let storage = StorageId::Table(TableId(7));
689 let key = PartitionedRowKey::encoded(storage, part("us"), RowNumber(1));
690 assert_eq!(classify_key(&key), EntryKind::PartitionedSource(storage, EntryLayout::Row));
691 }
692
693 #[test]
694 fn classify_key_partitioned_view_row_is_partitioned_source() {
695 let storage = StorageId::view(7);
697 let key = PartitionedRowKey::encoded(storage, part("us"), RowNumber(1));
698 assert_eq!(classify_key(&key), EntryKind::PartitionedSource(storage, EntryLayout::Row));
699 assert_ne!(
700 classify_key(&key),
701 EntryKind::PartitionedSource(StorageId::table(7), EntryLayout::Row),
702 "a view and a table sharing id 7 must not classify to the same entry"
703 );
704 }
705
706 #[test]
707 fn classify_key_row_is_still_source() {
708 let storage = StorageId::Table(TableId(7));
709 let key = RowKey::encoded(storage, RowNumber(1));
710 assert_eq!(classify_key(&key), EntryKind::Source(storage, EntryLayout::Row));
711 }
712
713 #[test]
714 fn classify_range_all_partition_forms_are_partitioned_source_for_table_and_view() {
715 for storage in [StorageId::Table(TableId(9)), StorageId::view(9)] {
717 let p = part("us");
718 let last = TaggedKey::from(PartitionedRowKey::new(storage, p, RowNumber(5)));
719 assert_eq!(
720 classify_range(&PartitionedRowKey::partition_range(storage, p).encode()),
721 Some(EntryKind::PartitionedSource(storage, EntryLayout::Row))
722 );
723 assert_eq!(
724 classify_range(
725 &PartitionedRowKey::partition_scan_range(storage, p, Some(&last)).encode()
726 ),
727 Some(EntryKind::PartitionedSource(storage, EntryLayout::Row))
728 );
729 assert_eq!(
730 classify_range(&PartitionedRowKey::scan_range(storage, None).encode()),
731 Some(EntryKind::PartitionedSource(storage, EntryLayout::Row))
732 );
733 assert_eq!(
734 classify_range(&PartitionedRowKey::full_scan(storage).encode()),
735 Some(EntryKind::PartitionedSource(storage, EntryLayout::Row))
736 );
737 }
738 }
739
740 #[test]
741 fn classify_range_row_range_is_still_source() {
742 let storage = StorageId::Table(TableId(9));
743 assert_eq!(
744 classify_range(&RowKey::full_scan(storage).encode()),
745 Some(EntryKind::Source(storage, EntryLayout::Row))
746 );
747 }
748
749 #[test]
750 fn classify_key_and_classify_range_agree_for_the_series_kinds() {
751 let series = StorageId::series(SeriesId(11));
754 let view = StorageId::View(ViewId(11));
755
756 for storage in [series, view] {
757 let key = SeriesRowKey {
758 storage,
759 variant_tag: None,
760 key: 5,
761 sequence: 1,
762 }
763 .encode();
764 assert_eq!(classify_key(&key), EntryKind::Source(storage, EntryLayout::Series));
765 assert_eq!(
766 classify_range(&SeriesRowKeyRange::full_scan(storage, None).encode()),
767 Some(EntryKind::Source(storage, EntryLayout::Series))
768 );
769
770 let partitioned = PartitionedSeriesRowKey::encoded(
771 storage,
772 Partition::of(&[Value::Utf8("us".to_string())]),
773 None,
774 5,
775 1,
776 );
777 assert_eq!(
778 classify_key(&partitioned),
779 EntryKind::PartitionedSource(storage, EntryLayout::Series)
780 );
781 assert_eq!(
782 classify_range(&PartitionedSeriesRowKeyRange::full_scan(storage).encode()),
783 Some(EntryKind::PartitionedSource(storage, EntryLayout::Series))
784 );
785 }
786 }
787}