qualia_core_db/sync.rs
1// no_std is declared at the crate level if needed
2
3use crate::NQuin;
4
5/// Represents a 12-byte structural pointer used for $O(N)$ Merkle DAG diffing.
6#[repr(C, packed)]
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct JumpTableEntry {
9 pub chunk_id: u64,
10 pub byte_offset: u32,
11}
12
13/// The Zero-Allocation CRDT Synchronizer for the Qualia Engine.
14/// Operates strictly within pre-allocated stack limits for offline-first mesh syncs.
15pub struct MerkleCrdtSynchronizer;
16
17impl MerkleCrdtSynchronizer {
18 /// Extracts the 12-bit Lamport clock integer from the 5th Vector (Metadata).
19 /// The Lamport clock is embedded in bits 32-43.
20 #[inline(always)]
21 pub fn extract_lamport_time(quin: &NQuin) -> u16 {
22 ((quin.metadata >> 32) & 0x0FFF) as u16
23 }
24
25 /// Compares two arrays of JumpTableEntry to find the divergent 128KB frames.
26 /// Returns a stack-allocated slice of byte offsets indicating which blocks to pull.
27 /// Operates in exactly $O(N)$ time with zero heap allocation.
28 pub fn diff_jump_tables<'a>(
29 local_table: &[JumpTableEntry],
30 remote_table: &[JumpTableEntry],
31 diff_buffer: &'a mut [u32],
32 ) -> &'a [u32] {
33 let mut local_idx = 0;
34 let mut remote_idx = 0;
35 let mut diff_count = 0;
36
37 // $O(N)$ linear scan comparing Virtual Chunk IDs (Merkle Hashes)
38 while local_idx < local_table.len()
39 && remote_idx < remote_table.len()
40 && diff_count < diff_buffer.len()
41 {
42 let local_chunk = local_table[local_idx].chunk_id;
43 let remote_chunk = remote_table[remote_idx].chunk_id;
44
45 if local_chunk == remote_chunk {
46 // Frames match, advance both pointers
47 local_idx += 1;
48 remote_idx += 1;
49 } else if local_chunk < remote_chunk {
50 local_idx += 1;
51 } else {
52 // Remote has a divergent frame
53 diff_buffer[diff_count] = remote_table[remote_idx].byte_offset;
54 diff_count += 1;
55 remote_idx += 1;
56 }
57 }
58
59 // Add any remaining remote frames
60 while remote_idx < remote_table.len() && diff_count < diff_buffer.len() {
61 diff_buffer[diff_count] = remote_table[remote_idx].byte_offset;
62 diff_count += 1;
63 remote_idx += 1;
64 }
65
66 &diff_buffer[..diff_count]
67 }
68
69 /// Resolves structural conflicts between an incoming 128KB divergent frame and the local frame.
70 /// Follows a strict selectable compaction policy triggered by the context metadata.
71 pub fn resolve_frame_conflict(
72 local_frame: &mut [NQuin],
73 incoming_frame: &[NQuin],
74 compaction_policy_metadata: u16,
75 ) {
76 const MASK_STRICT_HISTORY: u16 = 0x0010;
77 const MASK_EPOCH_COMPACT: u16 = 0x0020;
78
79 if (compaction_policy_metadata & MASK_EPOCH_COMPACT) != 0 {
80 // Epoch Compaction: Zero-out Tombstone Quins to shrink the active data footprint
81 for incoming in incoming_frame.iter() {
82 // In an epoch compact, we look for tombstones (e.g. Quins with metadata flags marking deletion)
83 let is_tombstone = (incoming.metadata & 0x1) != 0; // Simulated tombstone flag
84 if is_tombstone {
85 for local in local_frame.iter_mut() {
86 if local.subject == incoming.subject
87 && local.predicate == incoming.predicate
88 && local.object == incoming.object
89 {
90 // Match found. Zero-out both to compress the dataset.
91 local.subject = 0;
92 local.predicate = 0;
93 local.object = 0;
94 local.context = 0;
95 local.metadata = 0;
96 local.parity = 0;
97 break;
98 }
99 }
100 } else {
101 // Regular merge logic via Lamport clock comparison
102 // Find empty slot or matching subject/predicate
103 for local in local_frame.iter_mut() {
104 if local.subject == incoming.subject
105 && local.predicate == incoming.predicate
106 {
107 let local_time = Self::extract_lamport_time(local);
108 let incoming_time = Self::extract_lamport_time(incoming);
109
110 // Keep the Quin with the higher Lamport clock
111 if incoming_time > local_time {
112 *local = *incoming;
113 }
114 break;
115 } else if local.subject == 0 {
116 // Empty slot found, insert
117 *local = *incoming;
118 break;
119 }
120 }
121 }
122 }
123 } else if (compaction_policy_metadata & MASK_STRICT_HISTORY) != 0 {
124 // Strict History: Append Tombstone Quins (never delete)
125 for incoming in incoming_frame.iter() {
126 // Find empty slot in local frame to append to
127 for local in local_frame.iter_mut() {
128 if local.subject == 0 {
129 // 0 denotes empty slot
130 *local = *incoming;
131 break;
132 }
133 }
134 }
135 }
136 }
137}