@feltdb/core 0.4.11 → 0.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/cli/commands.js +5 -2
  2. package/dist/cli/index.js +1 -1
  3. package/dist/create/cli.js +16 -1
  4. package/dist/create/create.js +30 -16
  5. package/dist/create/docker-compose-generator.js +48 -9
  6. package/dist/create/package-versions.js +1 -1
  7. package/dist/create/server-source/Cargo.lock +2238 -0
  8. package/dist/create/server-source/Cargo.toml +7 -0
  9. package/dist/create/server-source/crates/feltdb/Cargo.lock +175 -0
  10. package/dist/create/server-source/crates/feltdb/Cargo.toml +79 -0
  11. package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +370 -0
  12. package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +589 -0
  13. package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +259 -0
  14. package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +446 -0
  15. package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +272 -0
  16. package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +378 -0
  17. package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +414 -0
  18. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +486 -0
  19. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +273 -0
  20. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +587 -0
  21. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +513 -0
  22. package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +395 -0
  23. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +469 -0
  24. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +409 -0
  25. package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +627 -0
  26. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +383 -0
  27. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +298 -0
  28. package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +1698 -0
  29. package/dist/create/server-source/crates/feltdb/src/acquisition.rs +286 -0
  30. package/dist/create/server-source/crates/feltdb/src/admission.rs +192 -0
  31. package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +477 -0
  32. package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +566 -0
  33. package/dist/create/server-source/crates/feltdb/src/analytics.rs +475 -0
  34. package/dist/create/server-source/crates/feltdb/src/application.rs +2244 -0
  35. package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +1070 -0
  36. package/dist/create/server-source/crates/feltdb/src/authorization.rs +1030 -0
  37. package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +266 -0
  38. package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +8 -0
  39. package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +418 -0
  40. package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +482 -0
  41. package/dist/create/server-source/crates/feltdb/src/capability.rs +903 -0
  42. package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +261 -0
  43. package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +78 -0
  44. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +2214 -0
  45. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +194 -0
  46. package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +427 -0
  47. package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +453 -0
  48. package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +465 -0
  49. package/dist/create/server-source/crates/feltdb/src/convergence.rs +618 -0
  50. package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +418 -0
  51. package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +380 -0
  52. package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +362 -0
  53. package/dist/create/server-source/crates/feltdb/src/cron.rs +294 -0
  54. package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +474 -0
  55. package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +1003 -0
  56. package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +536 -0
  57. package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +364 -0
  58. package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +235 -0
  59. package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +207 -0
  60. package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +316 -0
  61. package/dist/create/server-source/crates/feltdb/src/execution.rs +426 -0
  62. package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +219 -0
  63. package/dist/create/server-source/crates/feltdb/src/indexing.rs +779 -0
  64. package/dist/create/server-source/crates/feltdb/src/lib.rs +2838 -0
  65. package/dist/create/server-source/crates/feltdb/src/materialization.rs +184 -0
  66. package/dist/create/server-source/crates/feltdb/src/metrics.rs +267 -0
  67. package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +311 -0
  68. package/dist/create/server-source/crates/feltdb/src/observability.rs +366 -0
  69. package/dist/create/server-source/crates/feltdb/src/operation.rs +251 -0
  70. package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +438 -0
  71. package/dist/create/server-source/crates/feltdb/src/operation_log.rs +344 -0
  72. package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +477 -0
  73. package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +166 -0
  74. package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +261 -0
  75. package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +560 -0
  76. package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +3226 -0
  77. package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +201 -0
  78. package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +263 -0
  79. package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +484 -0
  80. package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +216 -0
  81. package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +281 -0
  82. package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +323 -0
  83. package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +573 -0
  84. package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +404 -0
  85. package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +418 -0
  86. package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +381 -0
  87. package/dist/create/server-source/crates/feltdb/src/phase_1c_three_node.rs +523 -0
  88. package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +334 -0
  89. package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +306 -0
  90. package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +355 -0
  91. package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +395 -0
  92. package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +346 -0
  93. package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +430 -0
  94. package/dist/create/server-source/crates/feltdb/src/production_api.rs +400 -0
  95. package/dist/create/server-source/crates/feltdb/src/provenance.rs +207 -0
  96. package/dist/create/server-source/crates/feltdb/src/query_performance.rs +217 -0
  97. package/dist/create/server-source/crates/feltdb/src/references.rs +404 -0
  98. package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +401 -0
  99. package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +160 -0
  100. package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +132 -0
  101. package/dist/create/server-source/crates/feltdb/src/routing.rs +409 -0
  102. package/dist/create/server-source/crates/feltdb/src/sharding.rs +523 -0
  103. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +3118 -0
  104. package/dist/create/server-source/crates/feltdb/src/state_hash.rs +291 -0
  105. package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +376 -0
  106. package/dist/create/server-source/crates/feltdb/src/storage.rs +267 -0
  107. package/dist/create/server-source/crates/feltdb/src/submission.rs +477 -0
  108. package/dist/create/server-source/crates/feltdb/src/sync.rs +483 -0
  109. package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +822 -0
  110. package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +366 -0
  111. package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +473 -0
  112. package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +949 -0
  113. package/dist/create/server-source/crates/feltdb/src/transactions.rs +646 -0
  114. package/dist/create/server-source/crates/feltdb/src/trigger.rs +390 -0
  115. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +928 -0
  116. package/dist/create/server-source/crates/feltdb/src/workflow.rs +713 -0
  117. package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +510 -0
  118. package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +354 -0
  119. package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +594 -0
  120. package/dist/create/server-source/crates/feltdb/src/workload.rs +1310 -0
  121. package/dist/create/server-source/crates/feltdb-server/Cargo.toml +23 -0
  122. package/dist/create/server-source/crates/feltdb-server/README.md +79 -0
  123. package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +73 -0
  124. package/dist/create/server-source/crates/feltdb-server/src/application_contract.rs +425 -0
  125. package/dist/create/server-source/crates/feltdb-server/src/artifacts.rs +449 -0
  126. package/dist/create/server-source/crates/feltdb-server/src/audit.rs +59 -0
  127. package/dist/create/server-source/crates/feltdb-server/src/auth.rs +308 -0
  128. package/dist/create/server-source/crates/feltdb-server/src/authorization.rs +228 -0
  129. package/dist/create/server-source/crates/feltdb-server/src/backup.rs +416 -0
  130. package/dist/create/server-source/crates/feltdb-server/src/causal.rs +218 -0
  131. package/dist/create/server-source/crates/feltdb-server/src/certification.rs +223 -0
  132. package/dist/create/server-source/crates/feltdb-server/src/clock.rs +132 -0
  133. package/dist/create/server-source/crates/feltdb-server/src/cluster.rs +165 -0
  134. package/dist/create/server-source/crates/feltdb-server/src/connections.rs +1044 -0
  135. package/dist/create/server-source/crates/feltdb-server/src/content.rs +111 -0
  136. package/dist/create/server-source/crates/feltdb-server/src/identity.rs +250 -0
  137. package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +78 -0
  138. package/dist/create/server-source/crates/feltdb-server/src/key_provider.rs +247 -0
  139. package/dist/create/server-source/crates/feltdb-server/src/leases.rs +123 -0
  140. package/dist/create/server-source/crates/feltdb-server/src/lib.rs +25 -0
  141. package/dist/create/server-source/crates/feltdb-server/src/main.rs +8715 -0
  142. package/dist/create/server-source/crates/feltdb-server/src/metrics.rs +97 -0
  143. package/dist/create/server-source/crates/feltdb-server/src/portable_bundle.rs +350 -0
  144. package/dist/create/server-source/crates/feltdb-server/src/principals.rs +510 -0
  145. package/dist/create/server-source/crates/feltdb-server/src/providers.rs +269 -0
  146. package/dist/create/server-source/crates/feltdb-server/src/releases.rs +2563 -0
  147. package/dist/create/server-source/crates/feltdb-server/src/sessions.rs +156 -0
  148. package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +1097 -0
  149. package/dist/create/server-source/crates/feltdb-server/src/versions.rs +264 -0
  150. package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +31 -0
  151. package/dist/create/server-source/crates/feltdb-wasm/src/lib.rs +1086 -0
  152. package/dist/create/server-source/crates/feltdb-wasm/test.db +0 -0
  153. package/dist/flowspec.d.ts +2 -0
  154. package/dist/flowspec.d.ts.map +1 -1
  155. package/dist/flowspec.js +28 -4
  156. package/dist/state-contract.d.ts +7 -1
  157. package/dist/state-contract.d.ts.map +1 -1
  158. package/dist/studio/components/ApplicationDesigner.d.ts.map +1 -1
  159. package/dist/studio/components/index.js +1 -1
  160. package/dist/studio/{components-q43NSTTH.js → components-bHTARBin.js} +160 -89
  161. package/dist/studio/index.js +31 -28
  162. package/dist/studio-app/assets/{index-DZpBoVMp.js → index-BqKquLuU.js} +8 -8
  163. package/dist/studio-app/index.html +1 -1
  164. package/package.json +1 -1
@@ -0,0 +1,474 @@
1
+ /**
2
+ * Distributed Indexing - Multi-node index replication and synchronization
3
+ *
4
+ * Extends the local indexing layer with distributed capabilities:
5
+ * - Index replication across peers
6
+ * - Consistency protocols based on vector clocks
7
+ * - Remote index state tracking
8
+ * - Query routing and distribution
9
+ * - Index merging strategies
10
+ */
11
+
12
+ use serde::{Deserialize, Serialize};
13
+ use std::collections::{HashMap, HashSet, BTreeMap};
14
+
15
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
16
+ pub struct PeerId(pub String);
17
+
18
+ #[derive(Debug, Clone, Serialize, Deserialize)]
19
+ pub struct IndexVectorClock {
20
+ pub clock: BTreeMap<String, u64>,
21
+ }
22
+
23
+ impl IndexVectorClock {
24
+ pub fn new() -> Self {
25
+ IndexVectorClock {
26
+ clock: BTreeMap::new(),
27
+ }
28
+ }
29
+
30
+ pub fn increment(&mut self, node_id: &str) {
31
+ *self.clock.entry(node_id.to_string()).or_insert(0) += 1;
32
+ }
33
+
34
+ pub fn merge(&mut self, other: &IndexVectorClock) {
35
+ for (node, timestamp) in &other.clock {
36
+ let current = self.clock.entry(node.clone()).or_insert(0);
37
+ *current = (*current).max(*timestamp);
38
+ }
39
+ }
40
+
41
+ pub fn happens_before(&self, other: &IndexVectorClock) -> bool {
42
+ let mut less = false;
43
+ for (node, timestamp) in &self.clock {
44
+ let other_ts = other.clock.get(node).copied().unwrap_or(0);
45
+ if timestamp > &other_ts {
46
+ return false;
47
+ }
48
+ if timestamp < &other_ts {
49
+ less = true;
50
+ }
51
+ }
52
+ less
53
+ }
54
+
55
+ pub fn concurrent_with(&self, other: &IndexVectorClock) -> bool {
56
+ !self.happens_before(other) && !other.happens_before(self)
57
+ }
58
+ }
59
+
60
+ #[derive(Debug, Clone, Serialize, Deserialize)]
61
+ pub struct IndexReplicationState {
62
+ pub index_name: String,
63
+ pub local_version: IndexVectorClock,
64
+ pub peer_versions: HashMap<String, IndexVectorClock>,
65
+ pub replicated_peers: HashSet<String>,
66
+ pub pending_sync: Vec<IndexOperation>,
67
+ }
68
+
69
+ #[derive(Debug, Clone, Serialize, Deserialize)]
70
+ pub enum IndexOperation {
71
+ CreateIndex {
72
+ name: String,
73
+ field: String,
74
+ index_type: String,
75
+ },
76
+ UpdateIndex {
77
+ name: String,
78
+ record_id: String,
79
+ value: String,
80
+ },
81
+ DeleteIndex {
82
+ name: String,
83
+ },
84
+ }
85
+
86
+ #[derive(Debug, Clone, Serialize, Deserialize)]
87
+ pub struct IndexSyncMessage {
88
+ pub source_peer: String,
89
+ pub target_peer: String,
90
+ pub index_name: String,
91
+ pub version: IndexVectorClock,
92
+ pub operations: Vec<IndexOperation>,
93
+ pub timestamp: u64,
94
+ }
95
+
96
+ #[derive(Debug, Clone, Serialize, Deserialize)]
97
+ pub struct RemoteIndexState {
98
+ pub peer_id: String,
99
+ pub indexes: HashMap<String, RemoteIndexMetadata>,
100
+ pub last_sync: u64,
101
+ pub reachable: bool,
102
+ }
103
+
104
+ #[derive(Debug, Clone, Serialize, Deserialize)]
105
+ pub struct RemoteIndexMetadata {
106
+ pub name: String,
107
+ pub version: IndexVectorClock,
108
+ pub entry_count: usize,
109
+ pub avg_query_time_ms: f64,
110
+ pub last_updated: u64,
111
+ }
112
+
113
+ /// Distributed index manager - coordinates indexes across peers
114
+ pub struct DistributedIndexManager {
115
+ local_peer_id: String,
116
+ replication_states: HashMap<String, IndexReplicationState>,
117
+ peer_states: HashMap<String, RemoteIndexState>,
118
+ pending_operations: Vec<IndexSyncMessage>,
119
+ consistency_protocol: ConsistencyProtocol,
120
+ }
121
+
122
+ #[derive(Debug, Clone, Copy, PartialEq)]
123
+ pub enum ConsistencyProtocol {
124
+ EventualConsistency,
125
+ StrongConsistency,
126
+ CausalConsistency,
127
+ }
128
+
129
+ impl DistributedIndexManager {
130
+ pub fn new(local_peer_id: String) -> Self {
131
+ DistributedIndexManager {
132
+ local_peer_id,
133
+ replication_states: HashMap::new(),
134
+ peer_states: HashMap::new(),
135
+ pending_operations: Vec::new(),
136
+ consistency_protocol: ConsistencyProtocol::CausalConsistency,
137
+ }
138
+ }
139
+
140
+ /// Create a local index and prepare for replication
141
+ pub fn create_replicated_index(
142
+ &mut self,
143
+ name: String,
144
+ field: String,
145
+ index_type: String,
146
+ ) -> Result<(), String> {
147
+ let mut version = IndexVectorClock::new();
148
+ version.increment(&self.local_peer_id);
149
+
150
+ let replication_state = IndexReplicationState {
151
+ index_name: name.clone(),
152
+ local_version: version,
153
+ peer_versions: HashMap::new(),
154
+ replicated_peers: HashSet::new(),
155
+ pending_sync: vec![IndexOperation::CreateIndex {
156
+ name: name.clone(),
157
+ field,
158
+ index_type,
159
+ }],
160
+ };
161
+
162
+ self.replication_states.insert(name, replication_state);
163
+ Ok(())
164
+ }
165
+
166
+ /// Track a remote peer's index state
167
+ pub fn register_peer(&mut self, peer_id: String) {
168
+ self.peer_states.insert(
169
+ peer_id.clone(),
170
+ RemoteIndexState {
171
+ peer_id,
172
+ indexes: HashMap::new(),
173
+ last_sync: current_time_ms(),
174
+ reachable: true,
175
+ },
176
+ );
177
+ }
178
+
179
+ /// Update remote peer's index metadata after sync
180
+ pub fn update_peer_index_metadata(
181
+ &mut self,
182
+ peer_id: &str,
183
+ index_name: String,
184
+ metadata: RemoteIndexMetadata,
185
+ ) -> Result<(), String> {
186
+ if let Some(peer_state) = self.peer_states.get_mut(peer_id) {
187
+ peer_state.indexes.insert(index_name.clone(), metadata);
188
+ peer_state.last_sync = current_time_ms();
189
+ Ok(())
190
+ } else {
191
+ Err(format!("Peer {} not found", peer_id))
192
+ }
193
+ }
194
+
195
+ /// Enqueue a sync message to a peer
196
+ pub fn enqueue_sync(&mut self, message: IndexSyncMessage) {
197
+ self.pending_operations.push(message);
198
+ }
199
+
200
+ /// Get pending operations for a peer
201
+ pub fn get_pending_for_peer(&self, peer_id: &str) -> Vec<IndexSyncMessage> {
202
+ self.pending_operations
203
+ .iter()
204
+ .filter(|msg| msg.target_peer == peer_id)
205
+ .cloned()
206
+ .collect()
207
+ }
208
+
209
+ /// Acknowledge sync from peer
210
+ pub fn acknowledge_sync(&mut self, peer_id: &str, index_name: &str) -> Result<(), String> {
211
+ if let Some(replication_state) = self.replication_states.get_mut(index_name) {
212
+ replication_state.replicated_peers.insert(peer_id.to_string());
213
+ Ok(())
214
+ } else {
215
+ Err(format!("Index {} not found", index_name))
216
+ }
217
+ }
218
+
219
+ /// Check replication status
220
+ pub fn get_replication_status(&self, index_name: &str) -> Option<ReplicationStatus> {
221
+ self.replication_states.get(index_name).map(|state| {
222
+ let replicated_count = state.replicated_peers.len();
223
+ let total_peers = self.peer_states.len();
224
+ let reachable_peers = self.peer_states.values().filter(|p| p.reachable).count();
225
+
226
+ ReplicationStatus {
227
+ index_name: index_name.to_string(),
228
+ replicated_to: replicated_count,
229
+ total_peers,
230
+ reachable_peers,
231
+ pending_syncs: state.pending_sync.len(),
232
+ consistency_level: self.calculate_consistency_level(index_name),
233
+ }
234
+ })
235
+ }
236
+
237
+ /// Calculate current consistency level for an index
238
+ fn calculate_consistency_level(&self, index_name: &str) -> ConsistencyLevel {
239
+ if let Some(replication_state) = self.replication_states.get(index_name) {
240
+ let total = self.peer_states.len();
241
+ let replicated = replication_state.replicated_peers.len();
242
+
243
+ if replicated == total {
244
+ ConsistencyLevel::Strong
245
+ } else if replicated > total / 2 {
246
+ ConsistencyLevel::Causal
247
+ } else {
248
+ ConsistencyLevel::Eventual
249
+ }
250
+ } else {
251
+ ConsistencyLevel::Local
252
+ }
253
+ }
254
+
255
+ /// Get list of peers where index needs replication
256
+ pub fn get_replication_targets(&self, index_name: &str) -> Vec<String> {
257
+ if let Some(replication_state) = self.replication_states.get(index_name) {
258
+ self.peer_states
259
+ .keys()
260
+ .filter(|peer_id| {
261
+ peer_id != &&self.local_peer_id && !replication_state.replicated_peers.contains(*peer_id)
262
+ })
263
+ .cloned()
264
+ .collect()
265
+ } else {
266
+ Vec::new()
267
+ }
268
+ }
269
+
270
+ /// Detect conflicts between peer versions
271
+ pub fn detect_conflicts(&self, index_name: &str) -> Vec<VersionConflict> {
272
+ let mut conflicts = Vec::new();
273
+
274
+ if let Some(replication_state) = self.replication_states.get(index_name) {
275
+ for (peer_id, peer_version) in &replication_state.peer_versions {
276
+ if replication_state.local_version.concurrent_with(peer_version) {
277
+ conflicts.push(VersionConflict {
278
+ index_name: index_name.to_string(),
279
+ local_version: replication_state.local_version.clone(),
280
+ remote_peer: peer_id.clone(),
281
+ remote_version: peer_version.clone(),
282
+ });
283
+ }
284
+ }
285
+ }
286
+
287
+ conflicts
288
+ }
289
+
290
+ /// Merge concurrent versions using CRDT strategy
291
+ pub fn merge_versions(&mut self, index_name: &str) -> Result<(), String> {
292
+ if let Some(replication_state) = self.replication_states.get_mut(index_name) {
293
+ for peer_version in replication_state.peer_versions.values() {
294
+ replication_state.local_version.merge(peer_version);
295
+ }
296
+ Ok(())
297
+ } else {
298
+ Err(format!("Index {} not found", index_name))
299
+ }
300
+ }
301
+
302
+ /// Set peer reachability
303
+ pub fn set_peer_reachable(&mut self, peer_id: &str, reachable: bool) {
304
+ if let Some(peer_state) = self.peer_states.get_mut(peer_id) {
305
+ peer_state.reachable = reachable;
306
+ }
307
+ }
308
+
309
+ /// Get synchronization status across all indexes
310
+ pub fn get_sync_status(&self) -> DistributedSyncStatus {
311
+ let total_indexes = self.replication_states.len();
312
+ let fully_replicated = self
313
+ .replication_states
314
+ .values()
315
+ .filter(|state| state.replicated_peers.len() == self.peer_states.len())
316
+ .count();
317
+
318
+ let pending_total: usize = self
319
+ .replication_states
320
+ .values()
321
+ .map(|state| state.pending_sync.len())
322
+ .sum();
323
+
324
+ DistributedSyncStatus {
325
+ total_indexes,
326
+ fully_replicated,
327
+ partially_replicated: total_indexes - fully_replicated,
328
+ pending_operations: pending_total,
329
+ unreachable_peers: self
330
+ .peer_states
331
+ .values()
332
+ .filter(|p| !p.reachable)
333
+ .count(),
334
+ }
335
+ }
336
+ }
337
+
338
+ #[derive(Debug, Clone, Serialize, Deserialize)]
339
+ pub enum ConsistencyLevel {
340
+ Local,
341
+ Eventual,
342
+ Causal,
343
+ Strong,
344
+ }
345
+
346
+ #[derive(Debug, Clone, Serialize, Deserialize)]
347
+ pub struct ReplicationStatus {
348
+ pub index_name: String,
349
+ pub replicated_to: usize,
350
+ pub total_peers: usize,
351
+ pub reachable_peers: usize,
352
+ pub pending_syncs: usize,
353
+ pub consistency_level: ConsistencyLevel,
354
+ }
355
+
356
+ #[derive(Debug, Clone, Serialize, Deserialize)]
357
+ pub struct VersionConflict {
358
+ pub index_name: String,
359
+ pub local_version: IndexVectorClock,
360
+ pub remote_peer: String,
361
+ pub remote_version: IndexVectorClock,
362
+ }
363
+
364
+ #[derive(Debug, Clone, Serialize, Deserialize)]
365
+ pub struct DistributedSyncStatus {
366
+ pub total_indexes: usize,
367
+ pub fully_replicated: usize,
368
+ pub partially_replicated: usize,
369
+ pub pending_operations: usize,
370
+ pub unreachable_peers: usize,
371
+ }
372
+
373
+ fn current_time_ms() -> u64 {
374
+ std::time::SystemTime::now()
375
+ .duration_since(std::time::UNIX_EPOCH)
376
+ .map(|d| d.as_millis() as u64)
377
+ .unwrap_or(0)
378
+ }
379
+
380
+ #[cfg(test)]
381
+ mod tests {
382
+ use super::*;
383
+
384
+ #[test]
385
+ fn test_vector_clock_increment() {
386
+ let mut clock = IndexVectorClock::new();
387
+ clock.increment("node1");
388
+ assert_eq!(clock.clock.get("node1"), Some(&1));
389
+ }
390
+
391
+ #[test]
392
+ fn test_vector_clock_merge() {
393
+ let mut clock1 = IndexVectorClock::new();
394
+ clock1.increment("node1");
395
+ clock1.increment("node1");
396
+
397
+ let mut clock2 = IndexVectorClock::new();
398
+ clock2.increment("node2");
399
+ clock2.increment("node2");
400
+
401
+ clock1.merge(&clock2);
402
+ assert_eq!(clock1.clock.get("node1"), Some(&2));
403
+ assert_eq!(clock1.clock.get("node2"), Some(&2));
404
+ }
405
+
406
+ #[test]
407
+ fn test_vector_clock_happens_before() {
408
+ let mut clock1 = IndexVectorClock::new();
409
+ clock1.increment("node1");
410
+
411
+ let mut clock2 = IndexVectorClock::new();
412
+ clock2.increment("node1");
413
+ clock2.increment("node1");
414
+
415
+ assert!(clock1.happens_before(&clock2));
416
+ assert!(!clock2.happens_before(&clock1));
417
+ }
418
+
419
+ #[test]
420
+ fn test_concurrent_detection() {
421
+ let mut clock1 = IndexVectorClock::new();
422
+ clock1.increment("node1");
423
+
424
+ let mut clock2 = IndexVectorClock::new();
425
+ clock2.increment("node2");
426
+
427
+ assert!(clock1.concurrent_with(&clock2));
428
+ }
429
+
430
+ #[test]
431
+ fn test_distributed_manager_creation() {
432
+ let mut manager = DistributedIndexManager::new("node1".to_string());
433
+ manager.register_peer("node2".to_string());
434
+
435
+ assert!(manager.create_replicated_index(
436
+ "status_idx".to_string(),
437
+ "status".to_string(),
438
+ "hash".to_string()
439
+ ).is_ok());
440
+
441
+ let status = manager.get_replication_status("status_idx");
442
+ assert!(status.is_some());
443
+ }
444
+
445
+ #[test]
446
+ fn test_replication_targets() {
447
+ let mut manager = DistributedIndexManager::new("node1".to_string());
448
+ manager.register_peer("node2".to_string());
449
+ manager.register_peer("node3".to_string());
450
+
451
+ manager
452
+ .create_replicated_index("idx1".to_string(), "field".to_string(), "hash".to_string())
453
+ .ok();
454
+
455
+ let targets = manager.get_replication_targets("idx1");
456
+ assert_eq!(targets.len(), 2);
457
+ }
458
+
459
+ #[test]
460
+ fn test_sync_status() {
461
+ let mut manager = DistributedIndexManager::new("node1".to_string());
462
+ manager.register_peer("node2".to_string());
463
+
464
+ manager
465
+ .create_replicated_index("idx1".to_string(), "field".to_string(), "hash".to_string())
466
+ .ok();
467
+ manager
468
+ .create_replicated_index("idx2".to_string(), "field".to_string(), "hash".to_string())
469
+ .ok();
470
+
471
+ let status = manager.get_sync_status();
472
+ assert_eq!(status.total_indexes, 2);
473
+ }
474
+ }