1use std::{
5 borrow::Cow,
6 fmt::{Display, Formatter, Result as FmtResult},
7 ops::Bound,
8};
9
10use reifydb_codec::key::{
11 deserializer::KeyDeserializer,
12 encode_u8,
13 encoded::{EncodedKey, EncodedKeyRange},
14 serializer::KeySerializer,
15};
16use reifydb_value::util::hash::{Hash128, xxh3_128};
17use serde::{Deserialize, Serialize};
18use smallvec::{SmallVec, smallvec};
19
20use super::super::KeyTag;
21use crate::{
22 interface::catalog::flow::OperatorId,
23 key::{
24 any::{ByteEncoding, Field, KeyFields, RawEncoding, Width},
25 bound::{TaggedKeyBound, TaggedKeyBoundRange},
26 operator::{
27 keyspace::{
28 KeyspaceVisitor, REGISTERED, dispatch,
29 root::{CustomNotCachedSuffix, NodeCounter, NodeCounterKey, NodeCounterKind},
30 suffix_width_of,
31 },
32 traits::Keyspace,
33 },
34 typed::{BoundedKey, layout::KeyLayout},
35 },
36 metrics::heap::HeapSize,
37 state::typed::{SuffixBytes, typed_key},
38};
39
40#[repr(transparent)]
41#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
42pub struct GroupId([u8; GroupId::WIDTH]);
43
44impl GroupId {
45 pub const WIDTH: usize = 24;
46
47 const HASH_OFFSET: usize = size_of::<u64>();
48
49 const NOT_A_WINDOW: u64 = u64::MAX;
50
51 pub const ROOT: Self = Self([0; Self::WIDTH]);
52
53 pub const FIRST_NON_ROOT: Self = {
54 let mut bytes = [0u8; Self::WIDTH];
55 bytes[Self::WIDTH - 1] = 1;
56 Self(bytes)
57 };
58
59 pub const MIN: Self = Self([u8::MIN; Self::WIDTH]);
60
61 pub const MAX: Self = Self([u8::MAX; Self::WIDTH]);
62
63 pub const fn from_bytes(bytes: [u8; Self::WIDTH]) -> Self {
64 Self(bytes)
65 }
66
67 pub const fn as_bytes(&self) -> &[u8; Self::WIDTH] {
68 &self.0
69 }
70
71 pub fn of(key: &EncodedKey) -> Self {
72 Self::hashed(xxh3_128(key.as_slice()))
73 }
74
75 pub fn hashed(hash: Hash128) -> Self {
76 match hash.0 {
77 0 => Self::FIRST_NON_ROOT,
78 carried => Self::at(Self::NOT_A_WINDOW, carried),
79 }
80 }
81
82 pub fn window(partition: Hash128, window_id: u64) -> Self {
83 assert!(
84 window_id != Self::NOT_A_WINDOW,
85 "window id {window_id} is the sentinel that marks a group as having no window; a window \
86 minted at it would collide with the join and distinct groups of the same operator"
87 );
88 Self::at(window_id, partition.0)
89 }
90
91 pub fn window_span(window_id: u64) -> (Self, Self) {
92 (Self::at(window_id, u128::MIN), Self::at(window_id, u128::MAX))
93 }
94
95 pub fn window_id(&self) -> Option<u64> {
96 let mut leading = [0u8; size_of::<u64>()];
97 leading.copy_from_slice(&self.0[..Self::HASH_OFFSET]);
98 match !u64::from_be_bytes(leading) {
99 Self::NOT_A_WINDOW => None,
100 window_id => Some(window_id),
101 }
102 }
103
104 fn at(window_id: u64, hash: u128) -> Self {
105 let mut bytes = [0u8; Self::WIDTH];
106 bytes[..Self::HASH_OFFSET].copy_from_slice(&(!window_id).to_be_bytes());
107 bytes[Self::HASH_OFFSET..].copy_from_slice(&hash.to_be_bytes());
108 Self(bytes)
109 }
110
111 pub fn is_root(&self) -> bool {
112 *self == Self::ROOT
113 }
114
115 pub fn successor(&self) -> Option<Self> {
116 let mut bytes = self.0;
117 for byte in bytes.iter_mut().rev() {
118 let (stepped, carried) = byte.overflowing_add(1);
119 *byte = stepped;
120 if !carried {
121 return Some(Self(bytes));
122 }
123 }
124 None
125 }
126
127 pub fn predecessor(&self) -> Option<Self> {
128 let mut bytes = self.0;
129 for byte in bytes.iter_mut().rev() {
130 let (stepped, borrowed) = byte.overflowing_sub(1);
131 *byte = stepped;
132 if !borrowed {
133 return Some(Self(bytes));
134 }
135 }
136 None
137 }
138}
139
140impl Display for GroupId {
141 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
142 for byte in self.0 {
143 write!(f, "{byte:02x}")?;
144 }
145 Ok(())
146 }
147}
148
149impl HeapSize for GroupId {
150 fn heap_size(&self) -> usize {
151 0
152 }
153}
154
155#[derive(Debug, Clone, Default, PartialEq, Eq)]
156pub struct GroupSet(Vec<GroupId>);
157
158impl GroupSet {
159 pub fn new(groups: impl IntoIterator<Item = GroupId>) -> Self {
160 let mut groups: Vec<GroupId> = groups.into_iter().filter(|g| !g.is_root()).collect();
161 groups.sort_unstable();
162 groups.dedup();
163 Self(groups)
164 }
165
166 pub fn contains(&self, group: GroupId) -> bool {
167 self.0.binary_search(&group).is_ok()
168 }
169
170 pub fn as_slice(&self) -> &[GroupId] {
171 &self.0
172 }
173
174 pub fn len(&self) -> usize {
175 self.0.len()
176 }
177
178 pub fn is_empty(&self) -> bool {
179 self.0.is_empty()
180 }
181}
182
183pub fn group_data_of_inner(inner: &[u8]) -> Option<GroupId> {
184 let mut de = KeyDeserializer::from_bytes(inner);
185 let group = GroupId::from_bytes(de.read_fixed().ok()?);
186 let keyspace = KeyspaceId(de.read_u8().ok()?);
187 if !keyspace.is_data() {
188 return None;
189 }
190 inner.starts_with(&group_inner_prefix(group)).then_some(group)
191}
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
194pub struct KeyspaceId(pub u8);
195
196impl KeyspaceId {
197 pub const HIGHEST_DATA: u8 = 0x24;
198
199 pub const NODE_COUNTER: Self = Self(0xFF);
200
201 pub const SOURCE_WATERMARK: Self = Self(0xFE);
202
203 pub const TIMER_WHEEL: Self = Self(0xFD);
204
205 pub const TIMER_INDEX: Self = Self(0xFC);
206
207 pub const JOIN_ROW_MAPPING: Self = Self(0xFB);
208
209 pub const GROUP_ROW_MAPPING: Self = Self(0xFA);
210
211 pub const GUEST_ROW_MAPPING: Self = Self(0xF9);
212
213 pub const ACCUMULATOR: Self = Self(0x00);
214
215 pub const BUFFER: Self = Self(0x01);
216
217 pub const RUNNING: Self = Self(0x02);
218
219 pub const EMIT: Self = Self(0x03);
220
221 pub const ROLLING_EXPIRY: Self = Self(0x04);
222
223 pub const COUNT: Self = Self(0x05);
224
225 pub const ROW_INDEX: Self = Self(0x06);
226
227 pub const SESSION: Self = Self(0x07);
228
229 pub const ROLLING_META: Self = Self(0x08);
230
231 pub const ENGINE_META: Self = Self(0x09);
232
233 pub const DISTINCT_ENTRY: Self = Self(0x0A);
234
235 pub const WINDOW_META: Self = Self(0x0B);
236
237 pub const JOIN_LEFT: Self = Self(0x0C);
238
239 pub const JOIN_RIGHT: Self = Self(0x0D);
240
241 pub const JOIN_SCHEMA: Self = Self(0x0E);
242
243 pub const RINGBUFFER_FORWARD: Self = Self(0x0F);
244
245 pub const RINGBUFFER_ENTRY: Self = Self(0x10);
246
247 pub const GATE_VISIBILITY: Self = Self(0x11);
248
249 pub const DISTINCT_LAYOUT: Self = Self(0x12);
250
251 pub const RINGBUFFER_EXPIRY: Self = Self(0x13);
252
253 pub const RINGBUFFER_TTL_ARM: Self = Self(0x14);
254
255 pub const SEAL_LEDGER: Self = Self(0x15);
256
257 pub const JOIN_PUBLISHED: Self = Self(0x16);
258
259 pub const JOIN_PIN: Self = Self(0x17);
260
261 pub const RINGBUFFER_META: Self = Self(0x18);
262
263 pub const REAP_QUEUE: Self = Self(0x19);
264
265 pub const JOIN_ROW_EXPIRY: Self = Self(0x1A);
266
267 pub const GUEST_ACCUMULATOR: Self = Self(0x1B);
268
269 pub const GUEST_BUFFER: Self = Self(0x1C);
270
271 pub const GUEST_RUNNING: Self = Self(0x1D);
272
273 pub const TUMBLING_EXPIRY: Self = Self(0x1E);
274
275 pub const PARTITIONED_RINGBUFFER_ENTRY: Self = Self(0x1F);
276
277 pub const PARTITIONED_RINGBUFFER_EXPIRY: Self = Self(0x20);
278
279 pub const PARTITIONED_RINGBUFFER_TTL_ARM: Self = Self(0x21);
280
281 pub const PARTITIONED_RINGBUFFER_META: Self = Self(0x22);
282
283 pub const CUSTOM_NOT_CACHED: Self = Self(0x23);
284
285 pub const JOIN_EXPIRY_DUE: Self = Self(0x24);
286
287 pub fn name(&self) -> Cow<'static, str> {
288 match *self {
289 Self::NODE_COUNTER => "NODE_COUNTER",
290 Self::SOURCE_WATERMARK => "SOURCE_WATERMARK",
291 Self::TIMER_WHEEL => "TIMER_WHEEL",
292 Self::TIMER_INDEX => "TIMER_INDEX",
293 Self::JOIN_ROW_MAPPING => "JOIN_ROW_MAPPING",
294 Self::GROUP_ROW_MAPPING => "GROUP_ROW_MAPPING",
295 Self::GUEST_ROW_MAPPING => "GUEST_ROW_MAPPING",
296 Self::ACCUMULATOR => "ACCUMULATOR",
297 Self::BUFFER => "BUFFER",
298 Self::RUNNING => "RUNNING",
299 Self::EMIT => "EMIT",
300 Self::ROLLING_EXPIRY => "ROLLING_EXPIRY",
301 Self::COUNT => "COUNT",
302 Self::ROW_INDEX => "ROW_INDEX",
303 Self::SESSION => "SESSION",
304 Self::ROLLING_META => "ROLLING_META",
305 Self::ENGINE_META => "ENGINE_META",
306 Self::DISTINCT_ENTRY => "DISTINCT_ENTRY",
307 Self::WINDOW_META => "WINDOW_META",
308 Self::JOIN_LEFT => "JOIN_LEFT",
309 Self::JOIN_RIGHT => "JOIN_RIGHT",
310 Self::JOIN_SCHEMA => "JOIN_SCHEMA",
311 Self::RINGBUFFER_FORWARD => "RINGBUFFER_FORWARD",
312 Self::RINGBUFFER_ENTRY => "RINGBUFFER_ENTRY",
313 Self::GATE_VISIBILITY => "GATE_VISIBILITY",
314 Self::DISTINCT_LAYOUT => "DISTINCT_LAYOUT",
315 Self::RINGBUFFER_EXPIRY => "RINGBUFFER_EXPIRY",
316 Self::RINGBUFFER_TTL_ARM => "RINGBUFFER_TTL_ARM",
317 Self::SEAL_LEDGER => "SEAL_LEDGER",
318 Self::JOIN_PUBLISHED => "JOIN_PUBLISHED",
319 Self::JOIN_PIN => "JOIN_PIN",
320 Self::RINGBUFFER_META => "RINGBUFFER_META",
321 Self::REAP_QUEUE => "REAP_QUEUE",
322 Self::JOIN_ROW_EXPIRY => "JOIN_ROW_EXPIRY",
323 Self::JOIN_EXPIRY_DUE => "JOIN_EXPIRY_DUE",
324 Self::GUEST_ACCUMULATOR => "GUEST_ACCUMULATOR",
325 Self::GUEST_BUFFER => "GUEST_BUFFER",
326 Self::GUEST_RUNNING => "GUEST_RUNNING",
327 Self::TUMBLING_EXPIRY => "TUMBLING_EXPIRY",
328 Self::PARTITIONED_RINGBUFFER_ENTRY => "PARTITIONED_RINGBUFFER_ENTRY",
329 Self::PARTITIONED_RINGBUFFER_EXPIRY => "PARTITIONED_RINGBUFFER_EXPIRY",
330 Self::PARTITIONED_RINGBUFFER_TTL_ARM => "PARTITIONED_RINGBUFFER_TTL_ARM",
331 Self::PARTITIONED_RINGBUFFER_META => "PARTITIONED_RINGBUFFER_META",
332 Self::CUSTOM_NOT_CACHED => "CUSTOM_NOT_CACHED",
333 _ => return Cow::Owned(format!("{:#04x}", self.0)),
334 }
335 .into()
336 }
337
338 pub fn is_data(&self) -> bool {
339 self.0 <= Self::HIGHEST_DATA
340 }
341
342 pub fn is_identity(&self) -> bool {
343 !self.is_data()
344 }
345
346 pub fn caches_ranges(&self) -> bool {
347 *self != Self::CUSTOM_NOT_CACHED
348 }
349
350 pub fn is_guest_owned(&self) -> bool {
351 matches!(*self, Self::CUSTOM_NOT_CACHED)
352 }
353
354 pub const fn is_known(&self) -> bool {
355 REGISTERED[(self.0 >> 6) as usize] & (1u64 << (self.0 & 63)) != 0
356 }
357}
358
359pub fn is_framed_inner(inner: &[u8]) -> bool {
360 inner.is_empty() || OperatorStateKey::decode_inner(inner).is_some_and(|(_, keyspace, _)| keyspace.is_known())
361}
362
363pub fn is_guest_framed_inner(inner: &[u8]) -> bool {
364 OperatorStateKey::decode_inner(inner).is_some_and(|(_, keyspace, suffix)| {
365 keyspace.is_guest_owned() && suffix_width_of(keyspace) == Some(suffix.len())
366 })
367}
368
369pub fn is_identity_framed_inner(inner: &[u8]) -> bool {
370 OperatorStateKey::decode_inner(inner)
371 .is_some_and(|(_, keyspace, _)| keyspace.is_identity() && keyspace.is_known())
372}
373
374#[derive(Debug, Clone, PartialEq, Eq, Hash)]
375pub struct OperatorStateKey {
376 pub operator: OperatorId,
377 pub group: GroupId,
378 pub keyspace: KeyspaceId,
379 pub suffix: Vec<u8>,
380}
381
382impl OperatorStateKey {
383 pub fn new(operator: OperatorId, group: GroupId, keyspace: KeyspaceId, suffix: impl Into<Vec<u8>>) -> Self {
384 Self {
385 operator,
386 group,
387 keyspace,
388 suffix: suffix.into(),
389 }
390 }
391
392 pub fn root(operator: OperatorId, keyspace: KeyspaceId, suffix: impl Into<Vec<u8>>) -> Self {
393 Self::new(operator, GroupId::ROOT, keyspace, suffix)
394 }
395
396 pub fn encoded(
397 operator: OperatorId,
398 group: GroupId,
399 keyspace: KeyspaceId,
400 suffix: impl AsRef<[u8]>,
401 ) -> EncodedKey {
402 let suffix = suffix.as_ref();
403 let mut serializer = KeySerializer::with_capacity(NODE_GROUP_PREFIX_LEN + 1 + suffix.len());
404 serializer
405 .extend_u8(KeyTag::OperatorState as u8)
406 .extend_u64(operator.0)
407 .extend_fixed(*group.as_bytes())
408 .extend_u8(keyspace.0)
409 .extend_raw(suffix);
410 serializer.to_encoded_key()
411 }
412
413 pub fn inner(&self) -> EncodedKey {
414 let mut serializer = KeySerializer::with_capacity(KEYSPACE_INNER_PREFIX_LEN + self.suffix.len());
415 serializer.extend_fixed(*self.group.as_bytes()).extend_u8(self.keyspace.0).extend_raw(&self.suffix);
416 serializer.to_encoded_key()
417 }
418
419 pub const KEYSPACE_INNER_OFFSET: u32 = GroupId::WIDTH as u32;
420
421 pub fn decode_keyspace(stored: u8) -> KeyspaceId {
422 KeyspaceId(KeyDeserializer::from_bytes(&[stored]).read_u8().expect("a single byte decodes as u8"))
423 }
424
425 pub fn inner_encoded(group: GroupId, keyspace: KeyspaceId, suffix: impl AsRef<[u8]>) -> GroupStateKey {
426 let suffix = suffix.as_ref();
427 let mut serializer = KeySerializer::with_capacity(KEYSPACE_INNER_PREFIX_LEN + suffix.len());
428 serializer.extend_fixed(*group.as_bytes()).extend_u8(keyspace.0).extend_raw(suffix);
429 GroupStateKey(serializer.to_encoded_key())
430 }
431
432 pub fn decode_inner(inner: &[u8]) -> Option<(GroupId, KeyspaceId, &[u8])> {
433 let mut de = KeyDeserializer::from_bytes(inner);
434 let group = de.read_fixed().ok()?;
435 let keyspace = de.read_u8().ok()?;
436 let suffix = de.read_raw(de.remaining()).ok()?;
437 Some((GroupId::from_bytes(group), KeyspaceId(keyspace), suffix))
438 }
439
440 pub fn node_range(operator: OperatorId) -> TaggedKeyBoundRange {
441 node_range(operator)
442 }
443
444 pub fn decode_operator(key: &EncodedKey) -> Option<(OperatorId, EncodedKey)> {
445 let mut de = KeyDeserializer::from_bytes(key.as_slice());
446 let kind: KeyTag = de.read_u8().ok()?.try_into().ok()?;
447 if kind != KeyTag::OperatorState {
448 return None;
449 }
450 let operator = de.read_u64().ok()?;
451 let inner = de.read_raw(de.remaining()).ok()?.to_vec();
452 Some((OperatorId(operator), EncodedKey::new(inner)))
453 }
454}
455
456impl OperatorStateKey {
457 pub const TAG: KeyTag = KeyTag::OperatorState;
458
459 pub fn encode(&self) -> EncodedKey {
460 let mut serializer = KeySerializer::with_capacity(NODE_GROUP_PREFIX_LEN + 1 + self.suffix.len());
461 serializer
462 .extend_u8(KeyTag::OperatorState as u8)
463 .extend_u64(self.operator.0)
464 .extend_fixed(*self.group.as_bytes())
465 .extend_u8(self.keyspace.0)
466 .extend_raw(&self.suffix);
467 serializer.to_encoded_key()
468 }
469
470 pub fn decode(key: &EncodedKey) -> Option<Self> {
471 let mut de = KeyDeserializer::from_bytes(key.as_slice());
472
473 let kind: KeyTag = de.read_u8().ok()?.try_into().ok()?;
474 if kind != KeyTag::OperatorState {
475 return None;
476 }
477
478 let operator = de.read_u64().ok()?;
479 let group = de.read_fixed().ok()?;
480 let keyspace = de.read_u8().ok()?;
481 let suffix = de.read_raw(de.remaining()).ok()?.to_vec();
482
483 Some(Self {
484 operator: OperatorId(operator),
485 group: GroupId::from_bytes(group),
486 keyspace: KeyspaceId(keyspace),
487 suffix,
488 })
489 }
490}
491
492#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
493pub struct GroupStateKey(EncodedKey);
494
495impl GroupStateKey {
496 pub fn new(group: GroupId, keyspace: KeyspaceId, suffix: impl AsRef<[u8]>) -> Self {
497 OperatorStateKey::inner_encoded(group, keyspace, suffix)
498 }
499
500 pub fn root(keyspace: KeyspaceId, suffix: impl AsRef<[u8]>) -> Self {
501 Self::new(GroupId::ROOT, keyspace, suffix)
502 }
503
504 pub fn from_framed(key: EncodedKey) -> Option<Self> {
505 is_framed_inner(key.as_slice()).then_some(Self(key))
506 }
507
508 pub fn from_guest_framed(key: EncodedKey) -> Option<Self> {
509 is_guest_framed_inner(key.as_slice()).then_some(Self(key))
510 }
511
512 pub fn from_identity_framed(key: EncodedKey) -> Option<Self> {
513 is_identity_framed_inner(key.as_slice()).then_some(Self(key))
514 }
515
516 pub fn bound_unchecked(key: EncodedKey) -> Self {
517 Self(key)
518 }
519
520 pub fn as_encoded(&self) -> &EncodedKey {
521 &self.0
522 }
523
524 pub fn into_encoded(self) -> EncodedKey {
525 self.0
526 }
527
528 pub fn as_slice(&self) -> &[u8] {
529 self.0.as_slice()
530 }
531
532 pub fn as_bytes(&self) -> &[u8] {
533 self.0.as_bytes()
534 }
535
536 pub fn group(&self) -> Option<GroupId> {
537 OperatorStateKey::decode_inner(self.0.as_slice()).map(|(group, _, _)| group)
538 }
539
540 pub fn keyspace(&self) -> Option<KeyspaceId> {
541 let bytes = self.0.as_slice();
542 let offset = OperatorStateKey::KEYSPACE_INNER_OFFSET as usize;
543 (bytes.len() > offset).then(|| KeyspaceId(encode_u8(bytes[offset])))
544 }
545}
546
547impl AsRef<[u8]> for GroupStateKey {
548 fn as_ref(&self) -> &[u8] {
549 self.0.as_slice()
550 }
551}
552
553impl AsRef<EncodedKey> for GroupStateKey {
554 fn as_ref(&self) -> &EncodedKey {
555 &self.0
556 }
557}
558
559pub trait IntoGroupStateKey {
560 fn into_group_state_key(self) -> GroupStateKey;
561}
562
563impl IntoGroupStateKey for GroupStateKey {
564 fn into_group_state_key(self) -> GroupStateKey {
565 self
566 }
567}
568
569fn group_inner_prefix(group: GroupId) -> Vec<u8> {
570 let mut serializer = KeySerializer::with_capacity(GroupId::WIDTH);
571 serializer.extend_fixed(*group.as_bytes());
572 serializer.finish().as_ref().to_vec()
573}
574
575fn keyspace_inner_prefix(group: GroupId, keyspace: KeyspaceId) -> Vec<u8> {
576 let mut prefix = group_inner_prefix(group);
577 prefix.push(encode_u8(keyspace.0));
578 prefix
579}
580
581pub fn group_inner_range(group: GroupId) -> EncodedKeyRange {
582 EncodedKeyRange::prefix(&group_inner_prefix(group))
583}
584
585pub fn keyspace_inner_range(group: GroupId, keyspace: KeyspaceId) -> EncodedKeyRange {
586 EncodedKeyRange::prefix(&keyspace_inner_prefix(group, keyspace))
587}
588
589enum SuffixEdge {
590 Low,
591 High,
592}
593
594fn suffix_at_edge(keyspace: KeyspaceId, suffix: &[u8], edge: SuffixEdge) -> Vec<u8> {
595 struct Pad<'a> {
596 suffix: &'a [u8],
597 edge: SuffixEdge,
598 }
599
600 impl KeyspaceVisitor for Pad<'_> {
601 type Output = Vec<u8>;
602
603 fn visit<K: Keyspace>(self) -> Self::Output {
604 let template = match self.edge {
605 SuffixEdge::Low => <K::Suffix as BoundedKey>::low().to_suffix_bytes(),
606 SuffixEdge::High => <K::Suffix as KeyLayout>::high().to_suffix_bytes(),
607 };
608 let mut bytes = self.suffix.to_vec();
609 bytes.truncate(template.len());
610 bytes.extend_from_slice(&template[bytes.len()..]);
611 bytes
612 }
613 }
614
615 dispatch(
616 keyspace,
617 Pad {
618 suffix,
619 edge,
620 },
621 )
622 .unwrap_or_else(|| suffix.to_vec())
623}
624
625pub fn keyspace_inner_range_in(
626 group: GroupId,
627 keyspace: KeyspaceId,
628 start: Bound<&[u8]>,
629 end: Bound<&[u8]>,
630) -> EncodedKeyRange {
631 let prefix = keyspace_inner_prefix(group, keyspace);
632 let whole = EncodedKeyRange::prefix(&prefix);
633 let at = |suffix: &[u8], edge: SuffixEdge| {
634 let mut key = prefix.clone();
635 key.extend_from_slice(&suffix_at_edge(keyspace, suffix, edge));
636 EncodedKey::new(key)
637 };
638 let lower = match start {
639 Bound::Unbounded => whole.start.clone(),
640 Bound::Included(suffix) => Bound::Included(at(suffix, SuffixEdge::Low)),
641 Bound::Excluded(suffix) => Bound::Excluded(at(suffix, SuffixEdge::High)),
642 };
643 let upper = match end {
644 Bound::Unbounded => whole.end.clone(),
645 Bound::Included(suffix) => Bound::Included(at(suffix, SuffixEdge::High)),
646 Bound::Excluded(suffix) => Bound::Excluded(at(suffix, SuffixEdge::Low)),
647 };
648 EncodedKeyRange::new(lower, upper)
649}
650
651pub type KeyspaceInnerRangeSplit = (GroupId, KeyspaceId, Bound<Vec<u8>>, Bound<Vec<u8>>);
652
653pub fn keyspace_inner_range_split(range: &EncodedKeyRange) -> Option<KeyspaceInnerRangeSplit> {
654 let (group, keyspace, start) = match &range.start {
655 Bound::Included(key) => {
656 let (group, keyspace, suffix) = OperatorStateKey::decode_inner(key.as_slice())?;
657 (group, keyspace, Bound::Included(suffix.to_vec()))
658 }
659 Bound::Excluded(key) => {
660 let (group, keyspace, suffix) = OperatorStateKey::decode_inner(key.as_slice())?;
661 (group, keyspace, Bound::Excluded(suffix.to_vec()))
662 }
663 Bound::Unbounded => return None,
664 };
665 let whole = EncodedKeyRange::prefix(&keyspace_inner_prefix(group, keyspace));
666 let end = if range.end == whole.end {
667 Bound::Unbounded
668 } else {
669 match &range.end {
670 Bound::Included(key) => match OperatorStateKey::decode_inner(key.as_slice())? {
671 (g, k, suffix) if g == group && k == keyspace => Bound::Included(suffix.to_vec()),
672 _ => return None,
673 },
674 Bound::Excluded(key) => match OperatorStateKey::decode_inner(key.as_slice())? {
675 (g, k, suffix) if g == group && k == keyspace => Bound::Excluded(suffix.to_vec()),
676 _ => return None,
677 },
678 Bound::Unbounded => return None,
679 }
680 };
681 Some((group, keyspace, start, end))
682}
683
684pub fn group_inner_range_split(range: &EncodedKeyRange) -> Option<GroupId> {
685 let key = match &range.start {
686 Bound::Included(key) | Bound::Excluded(key) => key,
687 Bound::Unbounded => return None,
688 };
689 let group = GroupId::from_bytes(KeyDeserializer::from_bytes(key.as_slice()).read_fixed().ok()?);
690 for candidate in [group_inner_range(group), group_data_inner_range(group)] {
691 if range.start == candidate.start && range.end == candidate.end {
692 return Some(group);
693 }
694 }
695 None
696}
697
698pub fn custom_not_cached_key_in(group: GroupId, id: &[u8]) -> Option<GroupStateKey> {
699 CustomNotCachedSuffix::of(id)
700 .map(|key| OperatorStateKey::inner_encoded(group, KeyspaceId::CUSTOM_NOT_CACHED, key.to_suffix_bytes()))
701}
702
703pub fn custom_not_cached_key(id: &[u8]) -> Option<GroupStateKey> {
704 custom_not_cached_key_in(GroupId::ROOT, id)
705}
706
707pub fn node_counter_key(kind: NodeCounterKind) -> GroupStateKey {
708 typed_key::<NodeCounter>(GroupId::ROOT, &NodeCounterKey::of(kind))
709}
710
711pub fn row_number_counter_key() -> GroupStateKey {
712 node_counter_key(NodeCounterKind::RowNumber)
713}
714
715pub fn keyspace_inner_range_upto(group: GroupId, keyspace: KeyspaceId, suffix: &[u8]) -> EncodedKeyRange {
716 let mut bound = keyspace_inner_prefix(group, keyspace);
717 bound.extend_from_slice(suffix);
718 EncodedKeyRange::new(keyspace_inner_range(group, keyspace).start, EncodedKeyRange::prefix(&bound).end)
719}
720
721pub fn group_data_inner_range(group: GroupId) -> EncodedKeyRange {
722 let prefix = group_inner_prefix(group);
723 let mut start = prefix.clone();
724 start.push(encode_u8(KeyspaceId::HIGHEST_DATA));
725 EncodedKeyRange::new(Bound::Included(EncodedKey::new(start)), EncodedKeyRange::prefix(&prefix).end)
726}
727
728pub fn group_identity_inner_range(group: GroupId) -> EncodedKeyRange {
729 let prefix = group_inner_prefix(group);
730 let mut end = prefix.clone();
731 end.push(encode_u8(KeyspaceId::HIGHEST_DATA));
732 EncodedKeyRange::new(Bound::Included(EncodedKey::new(prefix)), Bound::Excluded(EncodedKey::new(end)))
733}
734
735pub const NODE_PREFIX_LEN: usize = 9;
736
737pub const KEYSPACE_INNER_PREFIX_LEN: usize = GroupId::WIDTH + size_of::<u8>();
738
739pub const NODE_GROUP_PREFIX_LEN: usize = NODE_PREFIX_LEN + GroupId::WIDTH;
740
741pub fn extend_node_prefix(serializer: &mut KeySerializer, operator: OperatorId) {
742 serializer.extend_u8(KeyTag::OperatorState as u8).extend_u64(operator.0);
743}
744
745pub fn node_prefix(operator: OperatorId) -> Vec<u8> {
746 let mut serializer = KeySerializer::with_capacity(NODE_PREFIX_LEN);
747 extend_node_prefix(&mut serializer, operator);
748 serializer.finish().as_ref().to_vec()
749}
750
751pub fn node_range(operator: OperatorId) -> TaggedKeyBoundRange {
752 TaggedKeyBoundRange::prefix(KeyTag::OperatorState, [Field::UDesc(Width::U64, operator.0 as u128)])
753}
754
755pub fn group_range(operator: OperatorId, group: GroupId) -> TaggedKeyBoundRange {
756 TaggedKeyBoundRange::prefix(
757 KeyTag::OperatorState,
758 [
759 Field::UDesc(Width::U64, operator.0 as u128),
760 Field::BytesDesc(ByteEncoding::Fixed, Cow::Owned(group.as_bytes().to_vec())),
761 ],
762 )
763}
764
765pub fn keyspace_range(operator: OperatorId, group: GroupId, keyspace: KeyspaceId) -> TaggedKeyBoundRange {
766 TaggedKeyBoundRange::prefix(
767 KeyTag::OperatorState,
768 [
769 Field::UDesc(Width::U64, operator.0 as u128),
770 Field::BytesDesc(ByteEncoding::Fixed, Cow::Owned(group.as_bytes().to_vec())),
771 Field::UDesc(Width::U8, keyspace.0 as u128),
772 ],
773 )
774}
775
776pub fn group_data_range(operator: OperatorId, group: GroupId) -> TaggedKeyBoundRange {
777 TaggedKeyBoundRange {
778 start: Bound::Included(TaggedKeyBound::prefix(
779 KeyTag::OperatorState,
780 [
781 Field::UDesc(Width::U64, operator.0 as u128),
782 Field::BytesDesc(ByteEncoding::Fixed, Cow::Owned(group.as_bytes().to_vec())),
783 Field::UDesc(Width::U8, KeyspaceId::HIGHEST_DATA as u128),
784 ],
785 )),
786 end: Bound::Excluded(TaggedKeyBound::prefix_end(
787 KeyTag::OperatorState,
788 [
789 Field::UDesc(Width::U64, operator.0 as u128),
790 Field::BytesDesc(ByteEncoding::Fixed, Cow::Owned(group.as_bytes().to_vec())),
791 ],
792 )),
793 }
794}
795
796pub fn group_identity_range(operator: OperatorId, group: GroupId) -> TaggedKeyBoundRange {
797 TaggedKeyBoundRange {
798 start: Bound::Included(TaggedKeyBound::prefix(
799 KeyTag::OperatorState,
800 [
801 Field::UDesc(Width::U64, operator.0 as u128),
802 Field::BytesDesc(ByteEncoding::Fixed, Cow::Owned(group.as_bytes().to_vec())),
803 ],
804 )),
805 end: Bound::Excluded(TaggedKeyBound::prefix(
806 KeyTag::OperatorState,
807 [
808 Field::UDesc(Width::U64, operator.0 as u128),
809 Field::BytesDesc(ByteEncoding::Fixed, Cow::Owned(group.as_bytes().to_vec())),
810 Field::UDesc(Width::U8, KeyspaceId::HIGHEST_DATA as u128),
811 ],
812 )),
813 }
814}
815
816#[cfg(test)]
817mod tests {
818 use std::ops::Bound;
819
820 use reifydb_value::util::hash::Hash128;
821
822 use super::{
823 EncodedKey, EncodedKeyRange, GroupId, GroupSet, GroupStateKey, KeySerializer, KeyspaceId,
824 OperatorStateKey, custom_not_cached_key_in, group_data_inner_range, group_data_of_inner,
825 group_data_range, group_identity_inner_range, group_identity_range, group_inner_prefix,
826 group_inner_range, group_range, is_framed_inner, is_guest_framed_inner, keyspace_range, node_prefix,
827 node_range,
828 };
829 use crate::interface::catalog::flow::OperatorId;
830
831 const NODES: [u64; 4] = [1, 17, 300, 70_000];
832 const GROUPS: [u128; 8] = [1, 2, 127, 128, 1000, 100_000, 1 << 30, u128::MAX];
833 const DATA_KEYSPACES: [KeyspaceId; 4] =
834 [KeyspaceId::ACCUMULATOR, KeyspaceId::BUFFER, KeyspaceId::RUNNING, KeyspaceId::CUSTOM_NOT_CACHED];
835 const IDENTITY_KEYSPACES: [KeyspaceId; 1] = [KeyspaceId::GUEST_ROW_MAPPING];
836
837 #[derive(Clone, Copy, PartialEq, Debug)]
838 enum Phase {
839 Data,
840 Identity,
841 }
842
843 const CENSUS: [(&str, KeyspaceId, Phase, bool); 44] = [
847 ("NODE_COUNTER", KeyspaceId::NODE_COUNTER, Phase::Identity, true),
848 ("SOURCE_WATERMARK", KeyspaceId::SOURCE_WATERMARK, Phase::Identity, true),
849 ("TIMER_WHEEL", KeyspaceId::TIMER_WHEEL, Phase::Identity, true),
850 ("TIMER_INDEX", KeyspaceId::TIMER_INDEX, Phase::Identity, true),
851 ("JOIN_ROW_MAPPING", KeyspaceId::JOIN_ROW_MAPPING, Phase::Identity, true),
852 ("GROUP_ROW_MAPPING", KeyspaceId::GROUP_ROW_MAPPING, Phase::Identity, true),
853 ("GUEST_ROW_MAPPING", KeyspaceId::GUEST_ROW_MAPPING, Phase::Identity, true),
854 ("ACCUMULATOR", KeyspaceId::ACCUMULATOR, Phase::Data, true),
855 ("BUFFER", KeyspaceId::BUFFER, Phase::Data, true),
856 ("RUNNING", KeyspaceId::RUNNING, Phase::Data, true),
857 ("EMIT", KeyspaceId::EMIT, Phase::Data, true),
858 ("ROLLING_EXPIRY", KeyspaceId::ROLLING_EXPIRY, Phase::Data, true),
859 ("COUNT", KeyspaceId::COUNT, Phase::Data, true),
860 ("ROW_INDEX", KeyspaceId::ROW_INDEX, Phase::Data, true),
861 ("SESSION", KeyspaceId::SESSION, Phase::Data, true),
862 ("ROLLING_META", KeyspaceId::ROLLING_META, Phase::Data, true),
863 ("ENGINE_META", KeyspaceId::ENGINE_META, Phase::Data, true),
864 ("DISTINCT_ENTRY", KeyspaceId::DISTINCT_ENTRY, Phase::Data, true),
865 ("WINDOW_META", KeyspaceId::WINDOW_META, Phase::Data, true),
866 ("JOIN_LEFT", KeyspaceId::JOIN_LEFT, Phase::Data, true),
867 ("JOIN_RIGHT", KeyspaceId::JOIN_RIGHT, Phase::Data, true),
868 ("JOIN_SCHEMA", KeyspaceId::JOIN_SCHEMA, Phase::Data, true),
869 ("RINGBUFFER_FORWARD", KeyspaceId::RINGBUFFER_FORWARD, Phase::Data, true),
870 ("RINGBUFFER_ENTRY", KeyspaceId::RINGBUFFER_ENTRY, Phase::Data, true),
871 ("GATE_VISIBILITY", KeyspaceId::GATE_VISIBILITY, Phase::Data, true),
872 ("DISTINCT_LAYOUT", KeyspaceId::DISTINCT_LAYOUT, Phase::Data, true),
873 ("RINGBUFFER_EXPIRY", KeyspaceId::RINGBUFFER_EXPIRY, Phase::Data, true),
874 ("RINGBUFFER_TTL_ARM", KeyspaceId::RINGBUFFER_TTL_ARM, Phase::Data, true),
875 ("SEAL_LEDGER", KeyspaceId::SEAL_LEDGER, Phase::Data, true),
876 ("JOIN_PUBLISHED", KeyspaceId::JOIN_PUBLISHED, Phase::Data, true),
877 ("JOIN_PIN", KeyspaceId::JOIN_PIN, Phase::Data, true),
878 ("RINGBUFFER_META", KeyspaceId::RINGBUFFER_META, Phase::Data, true),
879 ("REAP_QUEUE", KeyspaceId::REAP_QUEUE, Phase::Data, true),
880 ("JOIN_ROW_EXPIRY", KeyspaceId::JOIN_ROW_EXPIRY, Phase::Data, true),
881 ("JOIN_EXPIRY_DUE", KeyspaceId::JOIN_EXPIRY_DUE, Phase::Data, true),
882 ("GUEST_ACCUMULATOR", KeyspaceId::GUEST_ACCUMULATOR, Phase::Data, true),
883 ("GUEST_BUFFER", KeyspaceId::GUEST_BUFFER, Phase::Data, true),
884 ("GUEST_RUNNING", KeyspaceId::GUEST_RUNNING, Phase::Data, true),
885 ("TUMBLING_EXPIRY", KeyspaceId::TUMBLING_EXPIRY, Phase::Data, true),
886 ("PARTITIONED_RINGBUFFER_ENTRY", KeyspaceId::PARTITIONED_RINGBUFFER_ENTRY, Phase::Data, true),
887 ("PARTITIONED_RINGBUFFER_EXPIRY", KeyspaceId::PARTITIONED_RINGBUFFER_EXPIRY, Phase::Data, true),
888 ("PARTITIONED_RINGBUFFER_TTL_ARM", KeyspaceId::PARTITIONED_RINGBUFFER_TTL_ARM, Phase::Data, true),
889 ("PARTITIONED_RINGBUFFER_META", KeyspaceId::PARTITIONED_RINGBUFFER_META, Phase::Data, true),
890 ("CUSTOM_NOT_CACHED", KeyspaceId::CUSTOM_NOT_CACHED, Phase::Data, false),
891 ];
892
893 fn declared_keyspaces() -> usize {
896 let source = include_str!("state.rs");
897 let body = source
898 .split("impl KeyspaceId {")
899 .nth(1)
900 .expect("the KeyspaceId impl block is where the constants are declared");
901 let body = body.split("\n}\n").next().expect("the impl block is closed");
902 body.lines()
903 .filter(|line| {
904 let line = line.trim_start();
905 line.starts_with("pub const") && line.contains("Self(")
906 })
907 .count()
908 }
909
910 #[test]
911 fn a_bare_row_number_key_is_too_short_to_be_read_as_a_framed_key() {
912 let mut bare = KeySerializer::with_capacity(4);
914 bare.extend_u64(7u64);
915 let bare = bare.finish().as_ref().to_vec();
916
917 assert!(
918 bare.len() < group_inner_prefix(GroupId::hashed(Hash128(7))).len(),
919 "a bare row number cannot span a group"
920 );
921 assert!(OperatorStateKey::decode_inner(&bare).is_none());
922 assert!(!is_framed_inner(&bare));
923
924 let framed = OperatorStateKey::inner_encoded(
925 GroupId::ROOT,
926 KeyspaceId::CUSTOM_NOT_CACHED,
927 7u64.to_be_bytes(),
928 );
929 assert!(is_framed_inner(framed.as_slice()));
930 assert!(
931 !contains(&group_identity_inner_range(GroupId::hashed(Hash128(7))), framed.as_slice()),
932 "the framed form must sit outside every other group's range"
933 );
934 }
935
936 #[test]
937 fn the_empty_key_is_framing_because_it_sorts_below_every_group() {
938 let empty: &[u8] = &[];
940 assert!(is_framed_inner(empty));
941
942 for group in GROUPS {
943 let range = group_inner_range(GroupId::hashed(Hash128(group)));
944 assert!(
945 !contains(&range, empty),
946 "the empty key must sit outside group {group}'s range, not merely be unattributed"
947 );
948 }
949 }
950
951 #[test]
952 fn the_empty_key_is_not_guest_framing_even_though_it_is_host_framing() {
953 let empty: &[u8] = &[];
957 assert!(is_framed_inner(empty));
958 assert!(!is_guest_framed_inner(empty));
959 assert!(GroupStateKey::from_guest_framed(EncodedKey::new(Vec::new())).is_none());
960
961 assert!(is_guest_framed_inner(
962 custom_not_cached_key_in(GroupId::hashed(Hash128(3)), &[])
963 .expect("an empty id fits the keyspace")
964 .as_slice()
965 ));
966 assert!(
967 !is_guest_framed_inner(
968 OperatorStateKey::inner_encoded(
969 GroupId::hashed(Hash128(3)),
970 KeyspaceId::CUSTOM_NOT_CACHED,
971 []
972 )
973 .as_slice()
974 ),
975 "a suffix narrower than its keyspace declares must be refused at the wall, or it reaches the typed bucket and panics there instead"
976 );
977 }
978
979 #[test]
980 fn a_keyspace_this_substrate_never_defines_is_not_framing() {
981 let mut stray = KeySerializer::with_capacity(4);
983 stray.extend_u64(3u64).extend_u8(0x90u8);
984 assert!(!is_framed_inner(stray.finish().as_ref()));
985
986 for keyspace in DATA_KEYSPACES.iter().chain(IDENTITY_KEYSPACES.iter()) {
987 assert!(
988 is_framed_inner(
989 OperatorStateKey::inner_encoded(GroupId::hashed(Hash128(3)), *keyspace, [])
990 .as_slice()
991 ),
992 "keyspace {keyspace:?} is one the substrate writes and must pass"
993 );
994 }
995 }
996
997 fn contains(range: &EncodedKeyRange, key: &[u8]) -> bool {
998 let after_start = match &range.start {
999 Bound::Included(start) => key >= start.as_slice(),
1000 Bound::Excluded(start) => key > start.as_slice(),
1001 Bound::Unbounded => true,
1002 };
1003 let before_end = match &range.end {
1004 Bound::Included(end) => key <= end.as_slice(),
1005 Bound::Excluded(end) => key < end.as_slice(),
1006 Bound::Unbounded => true,
1007 };
1008 after_start && before_end
1009 }
1010
1011 fn population() -> Vec<OperatorStateKey> {
1012 let mut keys = Vec::new();
1013 for operator in NODES {
1014 for group in GROUPS {
1015 for keyspace in DATA_KEYSPACES.iter().chain(IDENTITY_KEYSPACES.iter()) {
1016 for coord in [0u64, 1, 999, u64::MAX] {
1017 keys.push(OperatorStateKey::new(
1018 OperatorId(operator),
1019 GroupId::hashed(Hash128(group)),
1020 *keyspace,
1021 coord.to_be_bytes().to_vec(),
1022 ));
1023 }
1024 }
1025 }
1026 keys.push(OperatorStateKey::root(
1027 OperatorId(operator),
1028 KeyspaceId::NODE_COUNTER,
1029 b"7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU".to_vec(),
1030 ));
1031 }
1032 keys
1033 }
1034
1035 #[test]
1036 fn a_group_range_contains_exactly_that_groups_keys() {
1037 let population = population();
1039 for operator in NODES {
1040 for group in GROUPS {
1041 let group_id = GroupId::hashed(Hash128(group));
1042 let range = group_range(OperatorId(operator), group_id).encode();
1043 for key in &population {
1044 let encoded = key.encode();
1045 let expected = key.operator.0 == operator && key.group == group_id;
1046 assert_eq!(
1047 contains(&range, encoded.as_slice()),
1048 expected,
1049 "operator {operator} group {group} range disagreed about a key of operator {} \
1050 group {}",
1051 key.operator.0,
1052 key.group
1053 );
1054 }
1055 }
1056 }
1057 }
1058
1059 #[test]
1060 fn variable_length_group_ids_cannot_prefix_one_another() {
1061 let encodings: Vec<Vec<u8>> = GROUPS
1064 .iter()
1065 .map(|group| {
1066 OperatorStateKey::new(
1067 OperatorId(1),
1068 GroupId::hashed(Hash128(*group)),
1069 KeyspaceId::ACCUMULATOR,
1070 vec![],
1071 )
1072 .encode()
1073 .as_slice()
1074 .to_vec()
1075 })
1076 .collect();
1077
1078 for (i, a) in encodings.iter().enumerate() {
1079 for (j, b) in encodings.iter().enumerate() {
1080 if i != j {
1081 assert!(
1082 !b.starts_with(a.as_slice()),
1083 "group {} encodes as a prefix of group {}",
1084 GROUPS[i],
1085 GROUPS[j]
1086 );
1087 }
1088 }
1089 }
1090 }
1091
1092 #[test]
1093 fn the_data_and_identity_ranges_partition_the_group() {
1094 for operator in NODES {
1096 for group in GROUPS {
1097 let group = GroupId::hashed(Hash128(group));
1098 let data = group_data_range(OperatorId(operator), group).encode();
1099 let identity = group_identity_range(OperatorId(operator), group).encode();
1100
1101 for keyspace in DATA_KEYSPACES {
1102 let key = OperatorStateKey::new(
1103 OperatorId(operator),
1104 group,
1105 keyspace,
1106 vec![7, 7],
1107 )
1108 .encode();
1109 assert!(
1110 contains(&data, key.as_slice()),
1111 "data keyspace {keyspace:?} must fall in the phase-1 range"
1112 );
1113 assert!(
1114 !contains(&identity, key.as_slice()),
1115 "data keyspace {keyspace:?} must not fall in the phase-2 range"
1116 );
1117 }
1118
1119 for keyspace in IDENTITY_KEYSPACES {
1120 let key = OperatorStateKey::new(
1121 OperatorId(operator),
1122 group,
1123 keyspace,
1124 vec![7, 7],
1125 )
1126 .encode();
1127 assert!(
1128 contains(&identity, key.as_slice()),
1129 "identity keyspace {keyspace:?} must fall in the phase-2 range"
1130 );
1131 assert!(
1132 !contains(&data, key.as_slice()),
1133 "identity keyspace {keyspace:?} must survive phase 1"
1134 );
1135 }
1136 }
1137 }
1138 }
1139
1140 #[test]
1141 fn every_declared_keyspace_names_itself_for_offline_attribution() {
1142 for (name, keyspace, _, _) in CENSUS {
1144 assert_eq!(
1145 keyspace.name(),
1146 name,
1147 "{name} ({:#04x}) does not name itself, so an offline census reports it as CUSTOM",
1148 keyspace.0
1149 );
1150 }
1151
1152 assert_eq!(
1153 KeyspaceId::CUSTOM_NOT_CACHED.name(),
1154 "CUSTOM_NOT_CACHED",
1155 "a custom keyspace names the admission side it sits on; there is no unnamed fallback to absorb it"
1156 );
1157 }
1158
1159 #[test]
1160 fn every_declared_keyspace_states_whether_it_may_be_range_cached() {
1161 for (name, keyspace, _, policy) in CENSUS {
1165 assert_eq!(
1166 keyspace.caches_ranges(),
1167 policy,
1168 "{name} ({:#04x}) is cached on a different side than the census records",
1169 keyspace.0
1170 );
1171 }
1172
1173 let uncached: Vec<&str> = CENSUS.iter().filter(|(_, _, _, p)| !*p).map(|(n, ..)| *n).collect();
1174 assert_eq!(
1175 uncached,
1176 ["CUSTOM_NOT_CACHED"],
1177 "widening the set the tier refuses turns that tier into an off switch and only shows up as a \
1178 throughput loss in a replay, so every move in or out is a measured decision"
1179 );
1180
1181 assert!(
1182 KeyspaceId(0x43).caches_ranges(),
1183 "an undeclared keyspace must default to cacheable, or a custom operator silently loses the \
1184 range tier"
1185 );
1186 }
1187
1188 #[test]
1189 fn every_declared_keyspace_is_distinct_framing_and_swept_by_exactly_one_phase() {
1190 assert_eq!(
1192 CENSUS.len(),
1193 declared_keyspaces(),
1194 "a keyspace was added to KeyspaceId without being added to the census, so nothing below \
1195 ever looks at its byte"
1196 );
1197
1198 let mut seen: Vec<(&str, u8)> = Vec::new();
1199 for (name, keyspace, phase, _) in CENSUS {
1200 if let Some((other, _)) = seen.iter().find(|(_, byte)| *byte == keyspace.0) {
1201 panic!("{name} and {other} both claim keyspace byte {:#04x}", keyspace.0);
1202 }
1203 seen.push((name, keyspace.0));
1204
1205 assert!(
1206 keyspace.is_known(),
1207 "{name} is declared but not framing, so the sweep panics on the first row it holds"
1208 );
1209
1210 let group = GroupId::hashed(Hash128(4));
1211 let key = OperatorStateKey::new(OperatorId(9), group, keyspace, vec![7, 7]).encode();
1212 let data = contains(&group_data_range(OperatorId(9), group).encode(), key.as_slice());
1213 let identity = contains(&group_identity_range(OperatorId(9), group).encode(), key.as_slice());
1214
1215 assert!(data != identity, "{name} must fall in exactly one phase, not {data} and {identity}");
1216 assert_eq!(
1217 data,
1218 phase == Phase::Data,
1219 "{name} is declared {phase:?} but the phase-1 range says data={data}"
1220 );
1221 assert_eq!(
1222 keyspace.is_data(),
1223 phase == Phase::Data,
1224 "{name} is declared {phase:?} but is_data says {}",
1225 keyspace.is_data()
1226 );
1227 }
1228 }
1229
1230 #[test]
1231 fn root_entries_sit_outside_every_group_range() {
1232 for operator in NODES {
1234 let counter = OperatorStateKey::root(
1235 OperatorId(operator),
1236 KeyspaceId::NODE_COUNTER,
1237 b"mint".to_vec(),
1238 )
1239 .encode();
1240 for group in GROUPS {
1241 let range = group_range(OperatorId(operator), GroupId::hashed(Hash128(group))).encode();
1242 assert!(
1243 !contains(&range, counter.as_slice()),
1244 "group {group} range must not contain the root group's counter"
1245 );
1246 }
1247 }
1248 }
1249
1250 #[test]
1251 fn a_node_range_contains_exactly_that_nodes_keys() {
1252 let population = population();
1254 for operator in NODES {
1255 let range = node_range(OperatorId(operator)).encode();
1256 for key in &population {
1257 let encoded = key.encode();
1258 assert_eq!(
1259 contains(&range, encoded.as_slice()),
1260 key.operator.0 == operator,
1261 "operator {operator} range disagreed about a key of operator {}",
1262 key.operator.0
1263 );
1264 }
1265 }
1266 }
1267
1268 #[test]
1269 fn a_keyspace_range_isolates_one_keyspace_of_one_group() {
1270 let operator = OperatorId(17);
1272 let group = GroupId::hashed(Hash128(42));
1273 let range = keyspace_range(operator, group, KeyspaceId::BUFFER).encode();
1274
1275 let inside = OperatorStateKey::new(operator, group, KeyspaceId::BUFFER, vec![1]).encode();
1276 assert!(contains(&range, inside.as_slice()));
1277
1278 for other in [KeyspaceId::ACCUMULATOR, KeyspaceId::RUNNING, KeyspaceId::GUEST_ROW_MAPPING] {
1279 let key = OperatorStateKey::new(operator, group, other, vec![1]).encode();
1280 assert!(!contains(&range, key.as_slice()), "keyspace {other:?} leaked into the buffer range");
1281 }
1282
1283 let other_group =
1284 OperatorStateKey::new(operator, GroupId::hashed(Hash128(43)), KeyspaceId::BUFFER, vec![1])
1285 .encode();
1286 assert!(!contains(&range, other_group.as_slice()), "another group's buffer leaked into the range");
1287 }
1288
1289 #[test]
1290 fn encode_decode_round_trips_every_component() {
1291 let key = OperatorStateKey::new(
1292 OperatorId(0xDEAD_BEEF),
1293 GroupId::hashed(Hash128(123_456)),
1294 KeyspaceId::CUSTOM_NOT_CACHED,
1295 vec![1, 2, 3, 4],
1296 );
1297 assert_eq!(OperatorStateKey::decode(&key.encode()), Some(key));
1298 }
1299
1300 #[test]
1301 fn keys_still_decode_as_operator_state_of_their_node() {
1302 let key = OperatorStateKey::new(
1304 OperatorId(9),
1305 GroupId::hashed(Hash128(4)),
1306 KeyspaceId::ACCUMULATOR,
1307 vec![1],
1308 )
1309 .encode();
1310
1311 let decoded = OperatorStateKey::decode(&key).expect("must remain decodable as its key kind");
1312 assert_eq!(decoded.operator, OperatorId(9));
1313 }
1314
1315 #[test]
1316 fn an_inner_key_composed_with_its_node_prefix_reproduces_the_full_key() {
1317 let key = OperatorStateKey::new(
1320 OperatorId(17),
1321 GroupId::hashed(Hash128(42)),
1322 KeyspaceId::BUFFER,
1323 vec![9, 9],
1324 );
1325
1326 let mut composed = node_prefix(OperatorId(17));
1327 composed.extend_from_slice(key.inner().as_slice());
1328
1329 assert_eq!(composed, key.encode().as_slice(), "inner key plus operator prefix must equal the full key");
1330 }
1331
1332 #[test]
1333 fn the_root_group_range_stays_inside_its_node() {
1334 let range = group_inner_range(GroupId::ROOT).with_prefix(EncodedKey::new(node_prefix(OperatorId(17))));
1336
1337 let own = OperatorStateKey::root(OperatorId(17), KeyspaceId::NODE_COUNTER, vec![1]).encode();
1338 assert!(contains(&range, own.as_slice()), "the operator's own counter must be in range");
1339
1340 for operator in NODES {
1341 if operator == 17 {
1342 continue;
1343 }
1344 for keyspace in [KeyspaceId::NODE_COUNTER, KeyspaceId::ACCUMULATOR] {
1345 let foreign =
1346 OperatorStateKey::new(OperatorId(operator), GroupId::ROOT, keyspace, vec![1])
1347 .encode();
1348 assert!(
1349 !contains(&range, foreign.as_slice()),
1350 "operator {operator} leaked into operator 17's root-group range"
1351 );
1352 }
1353 }
1354 }
1355
1356 #[test]
1357 fn inner_ranges_partition_the_group_like_their_full_key_counterparts() {
1358 let operator = OperatorId(17);
1361 let prefix = EncodedKey::new(node_prefix(operator));
1362 for group in GROUPS {
1363 let group = GroupId::hashed(Hash128(group));
1364 let data = group_data_inner_range(group).with_prefix(prefix.clone());
1365 let identity = group_identity_inner_range(group).with_prefix(prefix.clone());
1366
1367 for keyspace in DATA_KEYSPACES {
1368 let key = OperatorStateKey::new(operator, group, keyspace, vec![7]).encode();
1369 assert!(contains(&data, key.as_slice()));
1370 assert!(!contains(&identity, key.as_slice()));
1371 }
1372 for keyspace in IDENTITY_KEYSPACES {
1373 let key = OperatorStateKey::new(operator, group, keyspace, vec![7]).encode();
1374 assert!(contains(&identity, key.as_slice()));
1375 assert!(!contains(&data, key.as_slice()));
1376 }
1377 }
1378 }
1379
1380 #[test]
1381 fn decode_inner_round_trips_the_tail() {
1382 let key = OperatorStateKey::new(
1383 OperatorId(3),
1384 GroupId::hashed(Hash128(77)),
1385 KeyspaceId::EMIT,
1386 vec![4, 5, 6],
1387 );
1388 let inner = key.inner();
1389 let (group, keyspace, suffix) =
1390 OperatorStateKey::decode_inner(inner.as_slice()).expect("inner must decode");
1391
1392 assert_eq!(group, GroupId::hashed(Hash128(77)));
1393 assert_eq!(keyspace, KeyspaceId::EMIT);
1394 assert_eq!(suffix, [4, 5, 6]);
1395 }
1396
1397 #[test]
1398 fn a_state_key_stays_compact_however_long_the_group_key_is() {
1399 let long = b"7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU\
1401 So11111111111111111111111111111111111111112";
1402 let hashed = OperatorStateKey::new(
1403 OperatorId(17),
1404 GroupId::of(&EncodedKey::new(long.to_vec())),
1405 KeyspaceId::ACCUMULATOR,
1406 vec![0; 8],
1407 )
1408 .encode();
1409 let short = OperatorStateKey::new(
1410 OperatorId(17),
1411 GroupId::of(&EncodedKey::new(b"g".to_vec())),
1412 KeyspaceId::ACCUMULATOR,
1413 vec![0; 8],
1414 )
1415 .encode();
1416
1417 assert_eq!(hashed.as_slice().len(), short.as_slice().len(), "group key length must not reach the key");
1418 assert!(hashed.as_slice().len() * 2 < long.len() + 8, "and must stay far below embedding the bytes");
1419 }
1420
1421 #[test]
1422 fn the_ram_predicate_and_the_disk_range_agree_on_every_key() {
1423 for group in GROUPS.map(|group| GroupId::hashed(Hash128(group))) {
1426 let range = group_data_inner_range(group);
1427 for other in GROUPS.map(|group| GroupId::hashed(Hash128(group))) {
1428 for keyspace in DATA_KEYSPACES.iter().chain(IDENTITY_KEYSPACES.iter()) {
1429 let key = OperatorStateKey::inner_encoded(other, *keyspace, vec![7, 7]);
1430 let in_range = contains(&range, key.as_slice());
1431 let in_predicate = group_data_of_inner(key.as_slice()) == Some(group);
1432 assert_eq!(
1433 in_range, in_predicate,
1434 "disk range and RAM predicate disagree for group {group:?} on a \
1435 {keyspace:?} key of group {other:?}"
1436 );
1437 }
1438 }
1439 }
1440 }
1441
1442 #[test]
1443 fn the_ram_predicate_refuses_identity_keyspaces() {
1444 for keyspace in IDENTITY_KEYSPACES {
1446 let key = OperatorStateKey::inner_encoded(GroupId::hashed(Hash128(9)), keyspace, vec![1]);
1447 assert_eq!(
1448 group_data_of_inner(key.as_slice()),
1449 None,
1450 "{keyspace:?} must not be reported as reclaimable group data"
1451 );
1452 }
1453 }
1454
1455 #[test]
1456 fn a_key_too_short_to_carry_a_keyspace_is_refused() {
1457 assert_eq!(group_data_of_inner(&[]), None);
1459 assert_eq!(group_data_of_inner(&[0xAB]), None, "a group with no keyspace byte must not decode");
1460 }
1461
1462 #[test]
1463 fn the_predicate_agrees_with_the_disk_range_on_arbitrary_bytes() {
1464 let mut seed = 0x2545F4914F6CDD1Du64;
1466 let mut next = move || {
1467 seed ^= seed << 13;
1468 seed ^= seed >> 7;
1469 seed ^= seed << 17;
1470 seed
1471 };
1472
1473 for _ in 0..2000 {
1474 let len = (next() % 12) as usize;
1475 let key: Vec<u8> = (0..len).map(|_| (next() % 256) as u8).collect();
1476 let Some(group) = group_data_of_inner(&key) else {
1477 continue;
1478 };
1479 assert!(
1480 contains(&group_data_inner_range(group), &key),
1481 "predicate attributed {key:?} to {group:?} but the disk range excludes it"
1482 );
1483 }
1484 }
1485
1486 #[test]
1487 fn a_group_set_is_sorted_deduped_and_never_admits_root() {
1488 let two = GroupId::hashed(Hash128(2));
1490 let five = GroupId::hashed(Hash128(5));
1491 let nine = GroupId::hashed(Hash128(9));
1492 let set = GroupSet::new([nine, two, nine, GroupId::ROOT, five]);
1493
1494 assert_eq!(set.as_slice(), &[two, five, nine]);
1495 assert_eq!(set.len(), 3);
1496 assert!(set.contains(five));
1497 assert!(!set.contains(GroupId::hashed(Hash128(3))));
1498 assert!(!set.contains(GroupId::ROOT), "the root group must be filtered out, not merely unsorted");
1499 }
1500
1501 #[test]
1502 fn an_empty_group_set_matches_nothing() {
1503 let set = GroupSet::new([]);
1504
1505 assert!(set.is_empty());
1506 assert!(!set.contains(GroupId::FIRST_NON_ROOT));
1507 }
1508}
1509
1510impl KeyFields for OperatorStateKey {
1511 fn fields(&self) -> SmallVec<[Field<'_>; 6]> {
1512 smallvec![
1513 Field::UDesc(Width::U64, self.operator.0 as u128),
1514 Field::BytesDesc(ByteEncoding::Fixed, Cow::Borrowed(self.group.as_bytes())),
1515 Field::UDesc(Width::U8, self.keyspace.0 as u128),
1516 Field::RawAsc(RawEncoding::Verbatim, Cow::Borrowed(&self.suffix)),
1517 ]
1518 }
1519}