@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.
- package/dist/cli/commands.js +5 -2
- package/dist/cli/index.js +1 -1
- package/dist/create/cli.js +16 -1
- package/dist/create/create.js +30 -16
- package/dist/create/docker-compose-generator.js +48 -9
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/Cargo.lock +2238 -0
- package/dist/create/server-source/Cargo.toml +7 -0
- package/dist/create/server-source/crates/feltdb/Cargo.lock +175 -0
- package/dist/create/server-source/crates/feltdb/Cargo.toml +79 -0
- package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +370 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +589 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +259 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +446 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +272 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +378 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +414 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +486 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +273 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +587 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +513 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +395 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +469 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +409 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +627 -0
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +383 -0
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +298 -0
- package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +1698 -0
- package/dist/create/server-source/crates/feltdb/src/acquisition.rs +286 -0
- package/dist/create/server-source/crates/feltdb/src/admission.rs +192 -0
- package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +566 -0
- package/dist/create/server-source/crates/feltdb/src/analytics.rs +475 -0
- package/dist/create/server-source/crates/feltdb/src/application.rs +2244 -0
- package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +1070 -0
- package/dist/create/server-source/crates/feltdb/src/authorization.rs +1030 -0
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +266 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +8 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +482 -0
- package/dist/create/server-source/crates/feltdb/src/capability.rs +903 -0
- package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +261 -0
- package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +78 -0
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +2214 -0
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +194 -0
- package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +427 -0
- package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +453 -0
- package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +465 -0
- package/dist/create/server-source/crates/feltdb/src/convergence.rs +618 -0
- package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +380 -0
- package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +362 -0
- package/dist/create/server-source/crates/feltdb/src/cron.rs +294 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +474 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +1003 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +536 -0
- package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +364 -0
- package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +235 -0
- package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +207 -0
- package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +316 -0
- package/dist/create/server-source/crates/feltdb/src/execution.rs +426 -0
- package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +219 -0
- package/dist/create/server-source/crates/feltdb/src/indexing.rs +779 -0
- package/dist/create/server-source/crates/feltdb/src/lib.rs +2838 -0
- package/dist/create/server-source/crates/feltdb/src/materialization.rs +184 -0
- package/dist/create/server-source/crates/feltdb/src/metrics.rs +267 -0
- package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +311 -0
- package/dist/create/server-source/crates/feltdb/src/observability.rs +366 -0
- package/dist/create/server-source/crates/feltdb/src/operation.rs +251 -0
- package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +438 -0
- package/dist/create/server-source/crates/feltdb/src/operation_log.rs +344 -0
- package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +166 -0
- package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +261 -0
- package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +560 -0
- package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +3226 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +201 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +263 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +484 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +216 -0
- package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +281 -0
- package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +323 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +573 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +404 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +381 -0
- package/dist/create/server-source/crates/feltdb/src/phase_1c_three_node.rs +523 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +334 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +306 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +355 -0
- package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +395 -0
- package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +346 -0
- package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +430 -0
- package/dist/create/server-source/crates/feltdb/src/production_api.rs +400 -0
- package/dist/create/server-source/crates/feltdb/src/provenance.rs +207 -0
- package/dist/create/server-source/crates/feltdb/src/query_performance.rs +217 -0
- package/dist/create/server-source/crates/feltdb/src/references.rs +404 -0
- package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +401 -0
- package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +160 -0
- package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +132 -0
- package/dist/create/server-source/crates/feltdb/src/routing.rs +409 -0
- package/dist/create/server-source/crates/feltdb/src/sharding.rs +523 -0
- package/dist/create/server-source/crates/feltdb/src/state_contract.rs +3118 -0
- package/dist/create/server-source/crates/feltdb/src/state_hash.rs +291 -0
- package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +376 -0
- package/dist/create/server-source/crates/feltdb/src/storage.rs +267 -0
- package/dist/create/server-source/crates/feltdb/src/submission.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/sync.rs +483 -0
- package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +822 -0
- package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +366 -0
- package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +473 -0
- package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +949 -0
- package/dist/create/server-source/crates/feltdb/src/transactions.rs +646 -0
- package/dist/create/server-source/crates/feltdb/src/trigger.rs +390 -0
- package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +928 -0
- package/dist/create/server-source/crates/feltdb/src/workflow.rs +713 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +510 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +354 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +594 -0
- package/dist/create/server-source/crates/feltdb/src/workload.rs +1310 -0
- package/dist/create/server-source/crates/feltdb-server/Cargo.toml +23 -0
- package/dist/create/server-source/crates/feltdb-server/README.md +79 -0
- package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +73 -0
- package/dist/create/server-source/crates/feltdb-server/src/application_contract.rs +425 -0
- package/dist/create/server-source/crates/feltdb-server/src/artifacts.rs +449 -0
- package/dist/create/server-source/crates/feltdb-server/src/audit.rs +59 -0
- package/dist/create/server-source/crates/feltdb-server/src/auth.rs +308 -0
- package/dist/create/server-source/crates/feltdb-server/src/authorization.rs +228 -0
- package/dist/create/server-source/crates/feltdb-server/src/backup.rs +416 -0
- package/dist/create/server-source/crates/feltdb-server/src/causal.rs +218 -0
- package/dist/create/server-source/crates/feltdb-server/src/certification.rs +223 -0
- package/dist/create/server-source/crates/feltdb-server/src/clock.rs +132 -0
- package/dist/create/server-source/crates/feltdb-server/src/cluster.rs +165 -0
- package/dist/create/server-source/crates/feltdb-server/src/connections.rs +1044 -0
- package/dist/create/server-source/crates/feltdb-server/src/content.rs +111 -0
- package/dist/create/server-source/crates/feltdb-server/src/identity.rs +250 -0
- package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +78 -0
- package/dist/create/server-source/crates/feltdb-server/src/key_provider.rs +247 -0
- package/dist/create/server-source/crates/feltdb-server/src/leases.rs +123 -0
- package/dist/create/server-source/crates/feltdb-server/src/lib.rs +25 -0
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +8715 -0
- package/dist/create/server-source/crates/feltdb-server/src/metrics.rs +97 -0
- package/dist/create/server-source/crates/feltdb-server/src/portable_bundle.rs +350 -0
- package/dist/create/server-source/crates/feltdb-server/src/principals.rs +510 -0
- package/dist/create/server-source/crates/feltdb-server/src/providers.rs +269 -0
- package/dist/create/server-source/crates/feltdb-server/src/releases.rs +2563 -0
- package/dist/create/server-source/crates/feltdb-server/src/sessions.rs +156 -0
- package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +1097 -0
- package/dist/create/server-source/crates/feltdb-server/src/versions.rs +264 -0
- package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +31 -0
- package/dist/create/server-source/crates/feltdb-wasm/src/lib.rs +1086 -0
- package/dist/create/server-source/crates/feltdb-wasm/test.db +0 -0
- package/dist/flowspec.d.ts +2 -0
- package/dist/flowspec.d.ts.map +1 -1
- package/dist/flowspec.js +28 -4
- package/dist/state-contract.d.ts +7 -1
- package/dist/state-contract.d.ts.map +1 -1
- package/dist/studio/components/ApplicationDesigner.d.ts.map +1 -1
- package/dist/studio/components/index.js +1 -1
- package/dist/studio/{components-q43NSTTH.js → components-bHTARBin.js} +160 -89
- package/dist/studio/index.js +31 -28
- package/dist/studio-app/assets/{index-DZpBoVMp.js → index-BqKquLuU.js} +8 -8
- package/dist/studio-app/index.html +1 -1
- 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
|
+
}
|