1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// SPDX-License-Identifier: Apache-2.0
//! Plane-neutral row identity.
//!
//! [`KeyRepr`] is the single representation of a row's identity within a
//! collection, shared across planes and crates: the Data-Plane per-core
//! write-version index keys committed writes by it, the Control-Plane
//! transaction read-set keys observed reads by it, and the replicated Calvin
//! `TxClass` carries it in its versioned read-set. Because read keys and write
//! keys must compare in one namespace — and because that namespace now travels
//! over the sequencer Raft log — the type lives in the shared `nodedb-types`
//! crate: a pure `Send + Sync` value type with no plane affiliation.
use serde::{Deserialize, Serialize};
/// Identity of a row within a collection.
///
/// The engine that owns the row chooses the representation:
/// - `Surrogate` for the cross-engine `u32` surrogate (schemaless + strict
/// document rows, and vector-by-document upserts keyed on the owning doc).
/// - `KvKey` for the raw Key-Value engine key bytes.
/// - `Edge` for a graph edge, whose identity is the `(src, label, dst)` tuple
/// rather than a surrogate.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum KeyRepr {
/// Cross-engine `u32` surrogate identity.
Surrogate(u32),
/// Raw Key-Value engine key bytes.
KvKey(Box<[u8]>),
/// Graph edge identity: `(source node, edge label, destination node)`.
Edge {
src: Box<str>,
label: Box<str>,
dst: Box<str>,
},
}
// Manual MessagePack impls: `KeyRepr` carries `Box<[u8]>` / `Box<str>` fields
// which the derive cannot handle (zerompk has no impl for unsized-boxed
// slices/strings), and keeping the boxed representation is a deliberate
// footprint choice for the Data-Plane write index. The wire form is a
// self-consistent `[tag, payload]` array mirroring how the derive encodes a
// data enum.
const KEY_REPR_TAG_SURROGATE: u32 = 0;
const KEY_REPR_TAG_KV: u32 = 1;
const KEY_REPR_TAG_EDGE: u32 = 2;
impl zerompk::ToMessagePack for KeyRepr {
fn write<W: zerompk::Write>(&self, writer: &mut W) -> zerompk::Result<()> {
writer.write_array_len(2)?;
match self {
KeyRepr::Surrogate(v) => {
writer.write_u32(KEY_REPR_TAG_SURROGATE)?;
writer.write_u32(*v)?;
}
KeyRepr::KvKey(bytes) => {
writer.write_u32(KEY_REPR_TAG_KV)?;
writer.write_binary(bytes)?;
}
KeyRepr::Edge { src, label, dst } => {
writer.write_u32(KEY_REPR_TAG_EDGE)?;
writer.write_array_len(3)?;
writer.write_string(src)?;
writer.write_string(label)?;
writer.write_string(dst)?;
}
}
Ok(())
}
}
impl<'de> zerompk::FromMessagePack<'de> for KeyRepr {
fn read<R: zerompk::Read<'de>>(reader: &mut R) -> zerompk::Result<Self> {
let outer = reader.read_array_len()?;
if outer != 2 {
return Err(zerompk::Error::InvalidMarker(0));
}
let tag = reader.read_u32()?;
match tag {
KEY_REPR_TAG_SURROGATE => Ok(KeyRepr::Surrogate(reader.read_u32()?)),
KEY_REPR_TAG_KV => {
let bytes = reader.read_binary()?;
Ok(KeyRepr::KvKey(Box::from(bytes.as_ref())))
}
KEY_REPR_TAG_EDGE => {
let inner = reader.read_array_len()?;
if inner != 3 {
return Err(zerompk::Error::InvalidMarker(0));
}
let src = reader.read_string()?;
let label = reader.read_string()?;
let dst = reader.read_string()?;
Ok(KeyRepr::Edge {
src: Box::from(src.as_ref()),
label: Box::from(label.as_ref()),
dst: Box::from(dst.as_ref()),
})
}
_ => Err(zerompk::Error::InvalidMarker(0)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn roundtrip(k: &KeyRepr) -> KeyRepr {
let bytes = zerompk::to_msgpack_vec(k).expect("encode KeyRepr");
zerompk::from_msgpack(&bytes).expect("decode KeyRepr")
}
#[test]
fn surrogate_roundtrips() {
let k = KeyRepr::Surrogate(0xDEAD_BEEF);
assert_eq!(roundtrip(&k), k);
}
#[test]
fn kv_key_roundtrips() {
let k = KeyRepr::KvKey(Box::from(&b"\x00\x01\xffhello"[..]));
assert_eq!(roundtrip(&k), k);
}
#[test]
fn edge_roundtrips() {
let k = KeyRepr::Edge {
src: Box::from("alice"),
label: Box::from("FOLLOWS"),
dst: Box::from("bob"),
};
assert_eq!(roundtrip(&k), k);
}
}