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
//! # DonaDbX — Lock-Free Storage Engine for Blockchain Validator State
//!
//! DonaDbX is a high-performance, append-only key-value store built for
//! blockchain validator state. It combines a lock-free write path, atomic
//! N-shard double-buffering, parallel BLAKE3 Merkle folding, and crash-safe
//! segment rotation into a single coherent API surface.
//!
//! ## Architecture
//!
//! The engine is composed of five cooperating subsystems:
//!
//! ```text
//! ┌──────────────────────────────────────────────────────────────┐
//! │ DonaDbX API │
//! └───────────┬──────────────────────────────────┬───────────────┘
//! │ │
//! ┌─────────▼──────────┐ ┌──────────▼──────────┐
//! │ 1. ExecutionFrame │ │ 3. DualBufferEngine │
//! │ Isolated write │ │ N-shard ArcSwap; │
//! │ arena; rollback │ │ atomic buffer swap │
//! └─────────┬──────────┘ └──────┬───────────────┘
//! │ │
//! │ ┌──────────┼──────────────┐
//! │ │ │ │
//! ┌─────────▼──────────┐ ┌────▼───────┐ ┌▼────────────┐
//! │ 2. CommutativeLog │ │ 4. Rayon │ │ 5. Segment │
//! │ Lock-free mmap │ │ fold │ │ Manager │
//! │ fetch_add + │ │ Parallel │ │ Rotation, │
//! │ memcpy append │ │ BLAKE3 + │ │ manifest, │
//! │ posix_fallocate │ │ XOR root │ │ recovery │
//! └────────────────────┘ └────────────┘ └─────────────┘
//! ```
//!
//! | # | Subsystem | Role |
//! |---|-----------|------|
//! | 1 | [`ExecutionFrame`] | Isolated write arena with zero-copy rollback. Writes are visible via [`DonaDbX::get`] immediately; visible via the index after [`ExecutionFrame::commit`]. |
//! | 2 | [`commutative::CommutativeLog`] | Memory-mapped append log. One `fetch_add` reserves space; one `memcpy` fills it. `posix_fallocate` pre-allocates physical blocks so disk-full surfaces at segment creation, not mid-write. |
//! | 3 | `DualBufferEngine` | N shards (one per logical CPU), each with monotonically-growing logs. [`DonaDbX::commit`] snapshots all shards and launches parallel fold without blocking writers. |
//! | 4 | Rayon fold pool | After each commit, runs parallel `BLAKE3(value)` hashing across all shards simultaneously. Maintains a commutative XOR accumulator `key XOR BLAKE3(value)` for the state root. |
//! | 5 | `SegmentManager` | Rotates the active log to a sealed segment at the fill threshold. Writes a crash-safe JSON manifest via atomic `write-tmp → rename`. Replays on reopen. |
//!
//! ## Key design decisions
//!
//! **Lock-free writes.** [`DonaDbX::put`] performs a single `fetch_add` on the
//! shard's `write_offset` atomic to reserve a slot, then copies the payload in
//! with `memcpy`. No mutex is acquired on the hot write path.
//!
//! **Parallel fold.** [`DonaDbX::commit`] snapshots all shard write frontiers
//! and dispatches them to a Rayon thread pool for parallel processing. Each
//! shard is folded independently, maximizing CPU utilization.
//!
//! **Commutative Merkle root.** The state root is maintained as an XOR
//! accumulator over `key XOR BLAKE3(value)` for every key. Incremental updates
//! are O(1): XOR out the old contribution, XOR in the new one. The final root
//! is `BLAKE3(accumulator)`.
//!
//! **Immediate read visibility.** [`DonaDbX::get`] checks three sources in
//! order: (1) the shard index (O(1), covers folded writes), (2) an active-log
//! scan over the current unflushed batch (covers writes since the last fold),
//! (3) sealed segments (covers rotated history). In-batch reads are visible
//! immediately without waiting for the next `commit()`.
//!
//! **Crash recovery.** The first 8 bytes of `seg_active.log` store
//! `committed_offset` as a little-endian `u64`. On reopen, the engine scans
//! only the range `[8, committed_offset)`, rebuilding the index and XOR
//! accumulator from scratch. Partial writes above `committed_offset` are
//! silently discarded. No separate write-ahead log is needed.
//!
//! **Disk-full protection.** `posix_fallocate(2)` is called at segment
//! creation time. If the filesystem cannot allocate the required space,
//! [`DbError::Io`]`(ENOSPC)` is returned immediately — never as a `SIGBUS`
//! mid-write inside a validation loop.
//!
//! ## Quick start
//!
//! ```no_run
//! use donadb_x::{DonaDbX, Config};
//!
//! let db = DonaDbX::open("./state", Config::default()).unwrap();
//!
//! let key = [1u8; 32];
//! db.put(key, b"hello").unwrap();
//!
//! // commit() swaps the active buffer and launches an async fold.
//! let ack = db.commit(1).unwrap();
//!
//! // wait() blocks until the fold completes and returns the 32-byte state root.
//! let root = ack.wait();
//!
//! assert_eq!(db.get(&key).unwrap(), b"hello");
//! println!("state root: {}", hex::encode(root));
//! ```
//!
//! ## Multi-threaded writes with [`BlockWriter`]
//!
//! For high-throughput ingestion, acquire one [`BlockWriter`] per thread per
//! block. Each writer holds a direct `Arc<CommutativeLog>`, so writers on
//! different shards contend only on their own shard's `write_offset` atomic —
//! never on each other.
//!
//! ```no_run
//! use donadb_x::{DonaDbX, Config};
//! use std::sync::Arc;
//!
//! let db = Arc::new(DonaDbX::open("./state", Config::default()).unwrap());
//!
//! let handles: Vec<_> = (0..4).map(|shard_id| {
//! let db = Arc::clone(&db);
//! std::thread::spawn(move || {
//! let writer = db.writer(shard_id);
//! for i in 0u8..64 {
//! let mut key = [0u8; 32];
//! key[0] = shard_id as u8;
//! key[1] = i;
//! writer.put(key, &[i; 8]).unwrap();
//! }
//! })
//! }).collect();
//!
//! for h in handles { h.join().unwrap(); }
//! let root = db.commit(2).unwrap().wait();
//! println!("block 2 state root: {}", hex::encode(root));
//! ```
//!
//! ## Complexity summary
//!
//! | Operation | Complexity | Notes |
//! |-----------|------------|-------|
//! | [`put()`][DonaDbX::put] | O(1) | One `fetch_add` + one `memcpy`; no locks |
//! | [`get()`][DonaDbX::get] | O(1) + O(u) | O(1) index hit; O(u) unflushed scan on miss, where u = records in current batch |
//! | [`get_at()`][DonaDbX::get_at] | O(v) | MVCC chain walk over v versions of the key |
//! | [`commit()`][DonaDbX::commit] | O(1) enqueue | Swap is instantaneous; fold is async |
//! | [`state_root()`][DonaDbX::state_root] | O(1) | Reads the pre-maintained XOR accumulator |
//! | Segment rotation | O(n) amortised | Runs once at fill threshold per segment |
//! | Crash recovery | O(r) | Replays r committed records from the active log |
use Error;
// ── Error type ────────────────────────────────────────────────────────────────
/// The unified error type for all DonaDbX operations.
///
/// All public methods return `DbResult<T>`, which is an alias for
/// `Result<T, DbError>`.
/// Convenience alias for `Result<T, DbError>`.
pub type DbResult<T> = ;
// ── Modules ───────────────────────────────────────────────────────────────────
/// Public index API: sharded hash-map for key → log-offset lookups.
/// Public commutative-log API: lock-free, memory-mapped append log.
/// In-process value cache — bounded DashMap populated by the fold thread.
pub
/// String prefix index — secondary BTreeMap for lexicographic prefix scans.
/// Segment management: rotation, manifest persistence, sealed-segment reads.
pub
/// Double-buffering engine: atomic buffer swap and async Rayon fold pool.
pub
/// Top-level engine: `DonaDbX`, `Config`, `CommitAck`, `ExecutionFrame`.
// ── Public re-exports ─────────────────────────────────────────────────────────
pub use ;
pub use MmapRef;
pub use StringIndex;
// ── Tests ─────────────────────────────────────────────────────────────────────