Skip to main content

reifydb_core/key/operator/
state.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use 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	/// Every keyspace the substrate declares, with the phase allowed to erase it and the tiers it may
844	/// be cached in. Both are written down rather than read back from `is_data` and `caches_ranges`, or
845	/// a keyspace changing sides would pass unremarked.
846	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	/// Counts `KeyspaceId` constants from the source text. There is no reflection over associated
894	/// constants, so this is the only way the census can notice a keyspace nobody listed.
895	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		// a bare u64 is half a group prefix, so the framing check must decline it rather than read past its end
913		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		// an empty inner key must sort below every group's prefix, or a reclaim phase could reach it
939		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		// the host reads an empty inner key as a sentinel sorting below every group, but a guest bound of
954		// zero length used to inherit that and open a scan at the very bottom of the operator's keyspace,
955		// sweeping every host keyspace on the way up; a guest key must name its keyspace or be refused
956		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		// a two-byte group+keyspace pair must not be framing unless the keyspace is one the substrate declares
982		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		// a group range must contain exactly that operator+group's keys, or reclaim destroys or leaks state
1038		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		// no group id's varint encoding may prefix another's, or reclaiming the shorter erases the longer's
1062		// keys
1063		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		// data and identity keyspaces must fall in exactly one reclamation phase, never both or neither
1095		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		// every declared keyspace must name itself, or an offline census misattributes it as CUSTOM
1143		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		// The census names the policy so a keyspace moving out of the range tier has to be moved here
1162		// too. A wrong side is silent: the tier just declines every span and the keyspace reads sqlite
1163		// forever, which reads as a cold cache rather than as a policy mistake.
1164		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		// every declared keyspace must have a unique byte and belong to exactly one reclamation phase
1191		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		// the root-scoped counter must sit outside every group range, or reclaiming a group erases it
1233		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		// a node range must contain exactly its own operator's keys, since drop_operator deletes by range
1253		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		// a keyspace range must isolate exactly one keyspace of one group, or scans mix incompatible payloads
1271		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		// every key of this kind must still decode to its own operator, or state is misrouted into the CDC log
1303		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		// inner key plus node prefix must reproduce the full key, or state written through the API is
1318		// unreachable
1319		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		// group 0's inner range has no byte-wise successor, so it must stay bounded by the operator prefix
1335		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		// inner data/identity ranges must partition a group like their full-key counterparts, since reclamation
1359		// uses them
1360		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		// a hashed group id must keep the state key fixed-width, never embedding the raw group bytes
1400		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		// the RAM predicate and the disk range must agree on every key, or a phase-1 delete ghosts or strands a
1424		// row
1425		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		// the RAM predicate must never report an identity keyspace as reclaimable group data
1445		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		// a key without both a group and a keyspace byte must not decode as group data
1458		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		// the predicate and the disk range must agree even on arbitrary bytes no encoder produced
1465		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		// a group set must stay sorted and deduped for binary_search, and must never admit the root group
1489		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}