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}
118
119impl Namespace {
120 /// Convert from raw u8 (for storage layer deserialization).
121 pub fn from_u8(v: u8) -> Option<Self> {
122 match v {
123 0 => Some(Self::Meta),
124 1 => Some(Self::Vector),
125 2 => Some(Self::Graph),
126 3 => Some(Self::Crdt),
127 4 => Some(Self::LoroState),
128 5 => Some(Self::Spatial),
129 6 => Some(Self::Strict),
130 7 => Some(Self::Columnar),
131 8 => Some(Self::Kv),
132 9 => Some(Self::Array),
133 10 => Some(Self::ArrayOpLog),
134 11 => Some(Self::ArrayDelta),
135 12 => Some(Self::Fts),
136 13 => Some(Self::StrictHistory),
137 14 => Some(Self::GraphHistory),
138 15 => Some(Self::DocumentHistory),
139 16 => Some(Self::LatestVersion),
140 17 => Some(Self::ColumnarPending),
141 18 => Some(Self::TimeseriesPending),
142 19 => Some(Self::VectorInsertPending),
143 20 => Some(Self::VectorDeletePending),
144 21 => Some(Self::FtsIndexPending),
145 22 => Some(Self::FtsDeletePending),
146 23 => Some(Self::SpatialInsertPending),
147 24 => Some(Self::SpatialDeletePending),
148 _ => None,
149 }
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn namespace_roundtrip() {
159 for v in 0u8..=24 {
160 let ns = Namespace::from_u8(v).unwrap();
161 assert_eq!(ns as u8, v);
162 }
163 assert!(Namespace::from_u8(25).is_none());
164 }
165}