reddb-io-server 1.1.0

RedDB server-side engine: storage, runtime, replication, MCP, AI, and the gRPC/HTTP/RedWire/PG-wire dispatchers. Re-exported by the umbrella `reddb` crate.
Documentation
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
//! Unified ID Types for Storage Layer
//!
//! This module provides type-safe ID wrappers for all storage concepts.
//! Using newtype wrappers prevents accidental mixing of semantically
//! different IDs (e.g., using a NodeId where a VectorId was expected).
//!
//! # Design Rationale
//!
//! Previously, IDs were scattered across modules as simple type aliases:
//! - `NodeId` was defined in both btree/node.rs and engine/hnsw.rs
//! - `TxnId` was duplicated 5 times across transaction modules
//! - `VectorId` existed in both deprecated vector/ and engine/vector_store.rs
//!
//! This centralization provides:
//! 1. Single source of truth
//! 2. Type safety (cannot accidentally mix ID types)
//! 3. Easy to add traits uniformly (Display, Hash, etc.)
//!
//! The wrappers support arithmetic operations for practical usage while
//! maintaining type distinction between different ID domains.

use std::fmt;
use std::ops::{Add, AddAssign, Sub, SubAssign};
use std::sync::atomic::{AtomicU64, Ordering};

// ============================================================================
// B+ Tree IDs
// ============================================================================

/// Node ID for B+ tree nodes (internal and leaf nodes).
///
/// B+ tree nodes form a hierarchical structure with internal nodes
/// containing keys and child pointers, and leaf nodes containing
/// the actual key-value pairs.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[repr(transparent)]
pub struct BTreeNodeId(pub u64);

impl BTreeNodeId {
    /// Create a new BTreeNodeId
    pub const fn new(id: u64) -> Self {
        Self(id)
    }

    /// Get the raw u64 value
    pub const fn get(self) -> u64 {
        self.0
    }
}

impl fmt::Display for BTreeNodeId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "btree:{}", self.0)
    }
}

impl From<u64> for BTreeNodeId {
    fn from(id: u64) -> Self {
        Self(id)
    }
}

impl From<BTreeNodeId> for u64 {
    fn from(id: BTreeNodeId) -> Self {
        id.0
    }
}

/// Global counter for B+ tree node IDs
static BTREE_NODE_ID_COUNTER: AtomicU64 = AtomicU64::new(1);

/// Generate next B+ tree node ID
pub fn next_btree_node_id() -> BTreeNodeId {
    BTreeNodeId(BTREE_NODE_ID_COUNTER.fetch_add(1, Ordering::SeqCst))
}

// ============================================================================
// HNSW Graph IDs
// ============================================================================

/// Node ID for HNSW (Hierarchical Navigable Small World) graph nodes.
///
/// HNSW nodes represent vectors in the approximate nearest neighbor
/// search structure. Each node exists in one or more layers of the
/// hierarchical graph.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[repr(transparent)]
pub struct HnswNodeId(pub u64);

impl HnswNodeId {
    /// Create a new HnswNodeId
    pub const fn new(id: u64) -> Self {
        Self(id)
    }

    /// Get the raw u64 value
    pub const fn get(self) -> u64 {
        self.0
    }
}

impl fmt::Display for HnswNodeId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "hnsw:{}", self.0)
    }
}

impl From<u64> for HnswNodeId {
    fn from(id: u64) -> Self {
        Self(id)
    }
}

impl From<HnswNodeId> for u64 {
    fn from(id: HnswNodeId) -> Self {
        id.0
    }
}

// ============================================================================
// Transaction IDs
// ============================================================================

/// Transaction ID for MVCC (Multi-Version Concurrency Control).
///
/// Transaction IDs are monotonically increasing and used to:
/// - Identify which transaction created/modified a version
/// - Determine version visibility during reads
/// - Coordinate distributed transactions
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[repr(transparent)]
pub struct TxnId(pub u64);

impl TxnId {
    /// Create a new TxnId
    pub const fn new(id: u64) -> Self {
        Self(id)
    }

    /// The null/initial transaction ID
    pub const ZERO: TxnId = TxnId(0);

    /// Get the raw u64 value
    pub const fn get(self) -> u64 {
        self.0
    }

    /// Check if this is the null/initial transaction
    pub const fn is_zero(self) -> bool {
        self.0 == 0
    }
}

impl fmt::Display for TxnId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "txn:{}", self.0)
    }
}

impl From<u64> for TxnId {
    fn from(id: u64) -> Self {
        Self(id)
    }
}

impl From<TxnId> for u64 {
    fn from(id: TxnId) -> Self {
        id.0
    }
}

// Arithmetic operations for TxnId
impl Add<u64> for TxnId {
    type Output = TxnId;
    fn add(self, rhs: u64) -> TxnId {
        TxnId(self.0 + rhs)
    }
}

impl AddAssign<u64> for TxnId {
    fn add_assign(&mut self, rhs: u64) {
        self.0 += rhs;
    }
}

impl Sub<u64> for TxnId {
    type Output = TxnId;
    fn sub(self, rhs: u64) -> TxnId {
        TxnId(self.0 - rhs)
    }
}

/// Global counter for transaction IDs
static TXN_ID_COUNTER: AtomicU64 = AtomicU64::new(1);

/// Generate next transaction ID
pub fn next_txn_id() -> TxnId {
    TxnId(TXN_ID_COUNTER.fetch_add(1, Ordering::SeqCst))
}

// ============================================================================
// Vector IDs
// ============================================================================

/// Vector ID for vector storage and similarity search.
///
/// Each vector in the storage engine has a unique VectorId that
/// persists across index rebuilds and can be used to retrieve
/// the original vector data.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[repr(transparent)]
pub struct VectorId(pub u64);

impl VectorId {
    /// Create a new VectorId
    pub const fn new(id: u64) -> Self {
        Self(id)
    }

    /// Get the raw u64 value
    pub const fn get(self) -> u64 {
        self.0
    }
}

impl fmt::Display for VectorId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "vec:{}", self.0)
    }
}

impl From<u64> for VectorId {
    fn from(id: u64) -> Self {
        Self(id)
    }
}

impl From<VectorId> for u64 {
    fn from(id: VectorId) -> Self {
        id.0
    }
}

// ============================================================================
// Segment IDs
// ============================================================================

/// Segment ID for data segment identification.
///
/// Segments are logical partitions of data used for:
/// - Organizing related records together
/// - Enabling targeted queries
/// - Supporting segment-level operations (compaction, gc)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[repr(transparent)]
pub struct SegmentId(pub u64);

impl SegmentId {
    /// Create a new SegmentId
    pub const fn new(id: u64) -> Self {
        Self(id)
    }

    /// Get the raw u64 value
    pub const fn get(self) -> u64 {
        self.0
    }
}

impl fmt::Display for SegmentId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "seg:{}", self.0)
    }
}

impl From<u64> for SegmentId {
    fn from(id: u64) -> Self {
        Self(id)
    }
}

impl From<SegmentId> for u64 {
    fn from(id: SegmentId) -> Self {
        id.0
    }
}

// ============================================================================
// Page IDs
// ============================================================================

/// Page ID for storage page identification.
///
/// Pages are the fundamental unit of storage I/O. Each page has
/// a fixed size (typically 4KB or 8KB) and contains records or
/// index data.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[repr(transparent)]
pub struct PageId(pub u64);

impl PageId {
    /// Create a new PageId
    pub const fn new(id: u64) -> Self {
        Self(id)
    }

    /// The null page ID (no page)
    pub const NULL: PageId = PageId(0);

    /// Get the raw u64 value
    pub const fn get(self) -> u64 {
        self.0
    }

    /// Check if this is the null page
    pub const fn is_null(self) -> bool {
        self.0 == 0
    }
}

impl fmt::Display for PageId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "page:{}", self.0)
    }
}

impl From<u64> for PageId {
    fn from(id: u64) -> Self {
        Self(id)
    }
}

impl From<PageId> for u64 {
    fn from(id: PageId) -> Self {
        id.0
    }
}

// ============================================================================
// Entity IDs (graph/relational)
// ============================================================================

/// Entity ID for graph nodes and relational entities.
///
/// Used in the graph storage layer to identify vertices
/// and their relationships.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[repr(transparent)]
pub struct EntityId(pub u64);

impl EntityId {
    /// Create a new EntityId
    pub const fn new(id: u64) -> Self {
        Self(id)
    }

    /// Get the raw u64 value
    pub const fn get(self) -> u64 {
        self.0
    }
}

impl fmt::Display for EntityId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "entity:{}", self.0)
    }
}

impl From<u64> for EntityId {
    fn from(id: u64) -> Self {
        Self(id)
    }
}

impl From<EntityId> for u64 {
    fn from(id: EntityId) -> Self {
        id.0
    }
}

// ============================================================================
// Timestamp (logical clock)
// ============================================================================

/// Logical timestamp for MVCC versioning.
///
/// Timestamps are monotonically increasing values used to
/// order events and determine version visibility.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
#[repr(transparent)]
pub struct Timestamp(pub u64);

impl Timestamp {
    /// Create a new Timestamp
    pub const fn new(ts: u64) -> Self {
        Self(ts)
    }

    /// The epoch (time zero)
    pub const EPOCH: Timestamp = Timestamp(0);

    /// Maximum timestamp
    pub const MAX: Timestamp = Timestamp(u64::MAX);

    /// Get the raw u64 value
    pub const fn get(self) -> u64 {
        self.0
    }

    /// Check if this is the epoch
    pub const fn is_epoch(self) -> bool {
        self.0 == 0
    }
}

impl fmt::Display for Timestamp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "ts:{}", self.0)
    }
}

impl From<u64> for Timestamp {
    fn from(ts: u64) -> Self {
        Self(ts)
    }
}

impl From<Timestamp> for u64 {
    fn from(ts: Timestamp) -> Self {
        ts.0
    }
}

// Arithmetic operations for Timestamp
impl Add<u64> for Timestamp {
    type Output = Timestamp;
    fn add(self, rhs: u64) -> Timestamp {
        Timestamp(self.0 + rhs)
    }
}

impl Add<Timestamp> for Timestamp {
    type Output = Timestamp;
    fn add(self, rhs: Timestamp) -> Timestamp {
        Timestamp(self.0 + rhs.0)
    }
}

impl AddAssign<u64> for Timestamp {
    fn add_assign(&mut self, rhs: u64) {
        self.0 += rhs;
    }
}

impl Sub<u64> for Timestamp {
    type Output = Timestamp;
    fn sub(self, rhs: u64) -> Timestamp {
        Timestamp(self.0 - rhs)
    }
}

impl Sub<Timestamp> for Timestamp {
    type Output = Timestamp;
    fn sub(self, rhs: Timestamp) -> Timestamp {
        Timestamp(self.0 - rhs.0)
    }
}

impl SubAssign<u64> for Timestamp {
    fn sub_assign(&mut self, rhs: u64) {
        self.0 -= rhs;
    }
}

impl Timestamp {
    /// Saturating subtraction
    pub const fn saturating_sub(self, rhs: Self) -> Self {
        Timestamp(self.0.saturating_sub(rhs.0))
    }

    /// Minimum of two timestamps
    pub fn min(self, other: Self) -> Self {
        Timestamp(self.0.min(other.0))
    }

    /// Maximum of two timestamps
    pub fn max(self, other: Self) -> Self {
        Timestamp(self.0.max(other.0))
    }
}

/// Global logical timestamp counter
static GLOBAL_TIMESTAMP: AtomicU64 = AtomicU64::new(1);

/// Get next timestamp
pub fn next_timestamp() -> Timestamp {
    Timestamp(GLOBAL_TIMESTAMP.fetch_add(1, Ordering::SeqCst))
}

/// Get current timestamp without incrementing
pub fn current_timestamp() -> Timestamp {
    Timestamp(GLOBAL_TIMESTAMP.load(Ordering::SeqCst))
}

// ============================================================================
// Tests
// ============================================================================

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_btree_node_id() {
        let id1 = BTreeNodeId::new(42);
        let id2 = BTreeNodeId::from(42u64);
        assert_eq!(id1, id2);
        assert_eq!(id1.get(), 42);
        assert_eq!(format!("{}", id1), "btree:42");
    }

    #[test]
    fn test_hnsw_node_id() {
        let id = HnswNodeId::new(100);
        assert_eq!(id.get(), 100);
        assert_eq!(format!("{}", id), "hnsw:100");
    }

    #[test]
    fn test_txn_id() {
        assert!(TxnId::ZERO.is_zero());
        let id = TxnId::new(5);
        assert!(!id.is_zero());
        assert_eq!(format!("{}", id), "txn:5");
    }

    #[test]
    fn test_vector_id() {
        let id = VectorId::new(999);
        assert_eq!(id.get(), 999);
        assert_eq!(u64::from(id), 999);
    }

    #[test]
    fn test_page_id() {
        assert!(PageId::NULL.is_null());
        let id = PageId::new(1);
        assert!(!id.is_null());
    }

    #[test]
    fn test_timestamp() {
        assert!(Timestamp::EPOCH.is_epoch());
        let ts = Timestamp::new(100);
        assert!(!ts.is_epoch());
        assert!(ts < Timestamp::MAX);
    }

    #[test]
    fn test_id_generation() {
        let id1 = next_btree_node_id();
        let id2 = next_btree_node_id();
        assert!(id2.get() > id1.get());

        let txn1 = next_txn_id();
        let txn2 = next_txn_id();
        assert!(txn2.get() > txn1.get());

        let ts1 = next_timestamp();
        let ts2 = next_timestamp();
        assert!(ts2.get() > ts1.get());
    }

    #[test]
    fn test_type_safety() {
        // These types should NOT be interchangeable at compile time
        // (This is a conceptual test - actual type errors are compile-time)
        let btree_id = BTreeNodeId::new(1);
        let hnsw_id = HnswNodeId::new(1);
        let txn_id = TxnId::new(1);

        // They have the same underlying value but are different types
        assert_eq!(btree_id.get(), hnsw_id.get());
        assert_eq!(btree_id.get(), txn_id.get());

        // But they format differently, showing their semantic meaning
        assert_ne!(format!("{}", btree_id), format!("{}", hnsw_id));
        assert_ne!(format!("{}", btree_id), format!("{}", txn_id));
    }
}