nodedb_types/namespace.rs
1// SPDX-License-Identifier: Apache-2.0
2
3//! Storage namespace identifiers for the blob KV store.
4//!
5//! Both SQLite (native) and OPFS (WASM) backends use the same namespace
6//! scheme to partition data by engine.
7
8use serde::{Deserialize, Serialize};
9
10/// Storage namespace. Each engine writes to its own namespace in the
11/// blob KV store, preventing key collisions.
12#[derive(
13 Debug,
14 Clone,
15 Copy,
16 PartialEq,
17 Eq,
18 Hash,
19 Serialize,
20 Deserialize,
21 rkyv::Archive,
22 rkyv::Serialize,
23 rkyv::Deserialize,
24)]
25#[repr(u8)]
26#[non_exhaustive]
27pub enum Namespace {
28 /// Database metadata: schema version, config, Shape subscriptions.
29 Meta = 0,
30 /// Vector engine: HNSW graph layers, vector data.
31 Vector = 1,
32 /// Graph engine: CSR arrays, node/label interning tables.
33 Graph = 2,
34 /// CRDT deltas: unsent mutations awaiting sync.
35 Crdt = 3,
36 /// Loro state snapshots: compacted CRDT state for fast cold-start.
37 LoroState = 4,
38 /// Spatial engine: R-tree checkpoints, geohash indexes.
39 Spatial = 5,
40 /// Strict document engine: Binary Tuple rows keyed by PK.
41 Strict = 6,
42 /// Columnar engine: compressed segments, delete bitmaps, segment metadata.
43 Columnar = 7,
44 /// KV engine: direct key-value storage (bypasses Loro CRDT).
45 /// Used when sync is disabled or for the local-only KV fast path.
46 Kv = 8,
47 /// Array engine: ND sparse arrays, catalog, manifests, segment bytes.
48 Array = 9,
49 /// Array CRDT op-log: append-only ops awaiting sync + GC.
50 ArrayOpLog = 10,
51 /// Array sync pending queue: ops waiting for transport delivery.
52 ArrayDelta = 11,
53 /// Full-text search engine: posting lists, doc-length maps, BM25 stats,
54 /// fieldnorm blobs, segment bytes, and surrogate maps.
55 Fts = 12,
56 /// Bitemporal history table for strict document collections.
57 ///
58 /// Keys: `{collection}:{system_from_ms_8be}:{pk_bytes}` — value is the
59 /// full Binary Tuple followed by an 8-byte big-endian `system_to_ms`
60 /// (u64::MAX = open / still-current at time of supersession).
61 StrictHistory = 13,
62 /// Bitemporal history table for graph edge collections.
63 ///
64 /// Keys: `{collection}:{edge_id_8be}:{system_from_ms_8be}` — value is
65 /// the MessagePack-encoded edge props followed by an 8-byte big-endian
66 /// `system_to_ms` (u64::MAX = current / not yet deleted).
67 GraphHistory = 14,
68 /// Bitemporal history table for schemaless document collections.
69 ///
70 /// Keys: `{collection}:{doc_id}\x00{system_from_ms:020}` — value is
71 /// `[tag:u8][valid_from_ms:i64 LE][valid_until_ms:i64 LE][body_msgpack...]`.
72 /// `tag = 0x00` (live), `0xFF` (tombstone), `0xFE` (GDPR erased).
73 DocumentHistory = 15,
74 /// O(1) pointer to the currently-live DocumentHistory version.
75 ///
76 /// Keys: `{collection}:{doc_id}` — value is the `system_from_ms` of the
77 /// live row encoded as a 20-digit zero-padded ASCII decimal (matching the
78 /// suffix used in `DocumentHistory` keys). Absent when no live version
79 /// exists (document never written, tombstoned, or GDPR-erased).
80 ///
81 /// Written atomically alongside every `DocumentHistory` mutation so that
82 /// `versioned_get_current` can resolve the current version with one index
83 /// lookup + one history fetch instead of a full prefix scan.
84 LatestVersion = 16,
85 /// Durable FIFO queue of outbound columnar row batches waiting for
86 /// transport to Origin. Keys are big-endian monotonic u64 IDs; values are
87 /// zerompk-encoded `PendingColumnarBatch` payloads.
88 ColumnarPending = 17,
89 /// Durable FIFO queue of outbound timeseries row batches waiting for
90 /// transport to Origin. Keys are big-endian monotonic u64 IDs; values are
91 /// zerompk-encoded `PendingTimeseriesBatch` payloads.
92 TimeseriesPending = 18,
93 /// Durable FIFO queue of outbound vector insert operations waiting for
94 /// transport to Origin. Keys are big-endian monotonic u64 IDs; values are
95 /// zerompk-encoded `PendingVectorInsert` payloads.
96 VectorInsertPending = 19,
97 /// Durable FIFO queue of outbound vector delete operations waiting for
98 /// transport to Origin. Keys are big-endian monotonic u64 IDs; values are
99 /// zerompk-encoded `PendingVectorDelete` payloads.
100 VectorDeletePending = 20,
101 /// Durable FIFO queue of outbound FTS index operations waiting for
102 /// transport to Origin. Keys are big-endian monotonic u64 IDs; values are
103 /// zerompk-encoded `PendingFtsIndex` payloads.
104 FtsIndexPending = 21,
105 /// Durable FIFO queue of outbound FTS delete operations waiting for
106 /// transport to Origin. Keys are big-endian monotonic u64 IDs; values are
107 /// zerompk-encoded `PendingFtsDelete` payloads.
108 FtsDeletePending = 22,
109 /// Durable FIFO queue of outbound spatial insert operations waiting for
110 /// transport to Origin. Keys are big-endian monotonic u64 IDs; values are
111 /// zerompk-encoded `PendingSpatialInsert` payloads.
112 SpatialInsertPending = 23,
113 /// Durable FIFO queue of outbound spatial delete operations waiting for
114 /// transport to Origin. Keys are big-endian monotonic u64 IDs; values are
115 /// zerompk-encoded `PendingSpatialDelete` payloads.
116 SpatialDeletePending = 24,
117 /// Durable FIFO queue of outbound KV writes waiting for transport to
118 /// Origin. Keys are big-endian monotonic u64 IDs; values are
119 /// zerompk-encoded `PendingKvWrite` payloads.
120 KvPushPending = 25,
121}
122
123impl Namespace {
124 /// Convert from raw u8 (for storage layer deserialization).
125 pub fn from_u8(v: u8) -> Option<Self> {
126 match v {
127 0 => Some(Self::Meta),
128 1 => Some(Self::Vector),
129 2 => Some(Self::Graph),
130 3 => Some(Self::Crdt),
131 4 => Some(Self::LoroState),
132 5 => Some(Self::Spatial),
133 6 => Some(Self::Strict),
134 7 => Some(Self::Columnar),
135 8 => Some(Self::Kv),
136 9 => Some(Self::Array),
137 10 => Some(Self::ArrayOpLog),
138 11 => Some(Self::ArrayDelta),
139 12 => Some(Self::Fts),
140 13 => Some(Self::StrictHistory),
141 14 => Some(Self::GraphHistory),
142 15 => Some(Self::DocumentHistory),
143 16 => Some(Self::LatestVersion),
144 17 => Some(Self::ColumnarPending),
145 18 => Some(Self::TimeseriesPending),
146 19 => Some(Self::VectorInsertPending),
147 20 => Some(Self::VectorDeletePending),
148 21 => Some(Self::FtsIndexPending),
149 22 => Some(Self::FtsDeletePending),
150 23 => Some(Self::SpatialInsertPending),
151 24 => Some(Self::SpatialDeletePending),
152 25 => Some(Self::KvPushPending),
153 _ => None,
154 }
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 #[test]
163 fn namespace_roundtrip() {
164 for v in 0u8..=25 {
165 let ns = Namespace::from_u8(v).unwrap();
166 assert_eq!(ns as u8, v);
167 }
168 assert!(Namespace::from_u8(26).is_none());
169 }
170}