@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,366 @@
|
|
|
1
|
+
/// TCP-based replication transport
|
|
2
|
+
///
|
|
3
|
+
/// Implements ProtocolTransport over real TCP sockets using message framing.
|
|
4
|
+
///
|
|
5
|
+
/// Wire Format: serde_json
|
|
6
|
+
/// - Chosen for compatibility with Operation::command.fields (serde_json::Value)
|
|
7
|
+
/// - bincode incompatible with untagged enums used by serde_json internally
|
|
8
|
+
/// - JSON is self-describing and provides stable framing for protocol evolution
|
|
9
|
+
/// - Length-prefix framing: 4-byte big-endian length + JSON payload
|
|
10
|
+
///
|
|
11
|
+
/// Transport Guarantees:
|
|
12
|
+
/// - TCP connection establishment/closure
|
|
13
|
+
/// - Message framing (length prefix + payload)
|
|
14
|
+
/// - Ordered delivery within a single TCP connection (TCP's byte-stream ordering)
|
|
15
|
+
/// - Serialization integrity (JSON encoder/decoder with bincode-compatible semantics)
|
|
16
|
+
/// - Connection state tracking (connect, disconnect, is_connected)
|
|
17
|
+
/// - Bounded buffers (prevent unbounded growth)
|
|
18
|
+
///
|
|
19
|
+
/// Deduplication/idempotency/retry logic is the protocol's responsibility via DistributedTransactionExecutor.
|
|
20
|
+
|
|
21
|
+
use crate::distributed_transactions::ReplicationMessage;
|
|
22
|
+
use crate::replication_protocol::{ProtocolError, ProtocolMetrics, ProtocolTransport};
|
|
23
|
+
use std::sync::atomic::{AtomicBool, Ordering};
|
|
24
|
+
use std::sync::Arc;
|
|
25
|
+
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
26
|
+
use tokio::net::{TcpListener, TcpStream};
|
|
27
|
+
use tokio::sync::Mutex;
|
|
28
|
+
|
|
29
|
+
const MESSAGE_BUFFER_SIZE: usize = 100;
|
|
30
|
+
|
|
31
|
+
/// TCP-based transport for ReplicationMessage
|
|
32
|
+
#[derive(Clone)]
|
|
33
|
+
pub struct TcpTransport {
|
|
34
|
+
local_addr: String,
|
|
35
|
+
peer_addr: Arc<Mutex<Option<String>>>,
|
|
36
|
+
stream: Arc<Mutex<Option<TcpStream>>>,
|
|
37
|
+
metrics: Arc<ProtocolMetrics>,
|
|
38
|
+
is_connected: Arc<AtomicBool>,
|
|
39
|
+
receive_buffer: Arc<Mutex<Vec<ReplicationMessage>>>,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
impl TcpTransport {
|
|
43
|
+
/// Create a new TCP transport that will listen on the given address
|
|
44
|
+
pub fn new(local_addr: String) -> Self {
|
|
45
|
+
Self {
|
|
46
|
+
local_addr,
|
|
47
|
+
peer_addr: Arc::new(Mutex::new(None)),
|
|
48
|
+
stream: Arc::new(Mutex::new(None)),
|
|
49
|
+
metrics: Arc::new(ProtocolMetrics::new()),
|
|
50
|
+
is_connected: Arc::new(AtomicBool::new(false)),
|
|
51
|
+
receive_buffer: Arc::new(Mutex::new(Vec::with_capacity(MESSAGE_BUFFER_SIZE))),
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/// Listen for incoming TCP connections
|
|
56
|
+
pub async fn listen(&mut self) -> Result<(), ProtocolError> {
|
|
57
|
+
let listener = TcpListener::bind(&self.local_addr)
|
|
58
|
+
.await
|
|
59
|
+
.map_err(|e| ProtocolError::ConnectionError(e.to_string()))?;
|
|
60
|
+
|
|
61
|
+
let stream = listener
|
|
62
|
+
.accept()
|
|
63
|
+
.await
|
|
64
|
+
.map_err(|e| ProtocolError::ConnectionError(e.to_string()))?
|
|
65
|
+
.0;
|
|
66
|
+
|
|
67
|
+
*self.stream.lock().await = Some(stream);
|
|
68
|
+
self.is_connected.store(true, Ordering::Relaxed);
|
|
69
|
+
self.metrics.record_connection_state_change();
|
|
70
|
+
|
|
71
|
+
Ok(())
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
pub fn metrics(&self) -> &ProtocolMetrics {
|
|
75
|
+
&self.metrics
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#[async_trait::async_trait]
|
|
80
|
+
impl ProtocolTransport for TcpTransport {
|
|
81
|
+
async fn send(&self, message: ReplicationMessage) -> Result<(), ProtocolError> {
|
|
82
|
+
let mut stream_guard = self.stream.lock().await;
|
|
83
|
+
let stream = stream_guard
|
|
84
|
+
.as_mut()
|
|
85
|
+
.ok_or(ProtocolError::ConnectionError("not connected".to_string()))?;
|
|
86
|
+
|
|
87
|
+
// Serialize message using serde_json (bincode has issues with serde_json::Value)
|
|
88
|
+
let payload = serde_json::to_vec(&message)
|
|
89
|
+
.map_err(|e| ProtocolError::SerializationError(e.to_string()))?;
|
|
90
|
+
|
|
91
|
+
let payload_len = payload.len() as u32;
|
|
92
|
+
|
|
93
|
+
// Send length prefix (4 bytes, big-endian)
|
|
94
|
+
stream
|
|
95
|
+
.write_all(&payload_len.to_be_bytes())
|
|
96
|
+
.await
|
|
97
|
+
.map_err(|e| ProtocolError::TransportError(e.to_string()))?;
|
|
98
|
+
|
|
99
|
+
// Send payload
|
|
100
|
+
stream
|
|
101
|
+
.write_all(&payload)
|
|
102
|
+
.await
|
|
103
|
+
.map_err(|e| ProtocolError::TransportError(e.to_string()))?;
|
|
104
|
+
|
|
105
|
+
stream
|
|
106
|
+
.flush()
|
|
107
|
+
.await
|
|
108
|
+
.map_err(|e| ProtocolError::TransportError(e.to_string()))?;
|
|
109
|
+
|
|
110
|
+
self.metrics.record_send(4 + payload.len());
|
|
111
|
+
|
|
112
|
+
Ok(())
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async fn receive(&self) -> Result<Vec<ReplicationMessage>, ProtocolError> {
|
|
116
|
+
let mut buffer = self.receive_buffer.lock().await;
|
|
117
|
+
|
|
118
|
+
// If we have buffered messages, return them
|
|
119
|
+
if !buffer.is_empty() {
|
|
120
|
+
let messages = std::mem::take(&mut *buffer);
|
|
121
|
+
return Ok(messages);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Try to receive one message from the socket
|
|
125
|
+
let mut stream_guard = self.stream.lock().await;
|
|
126
|
+
let stream = stream_guard
|
|
127
|
+
.as_mut()
|
|
128
|
+
.ok_or(ProtocolError::ConnectionError("not connected".to_string()))?;
|
|
129
|
+
|
|
130
|
+
// Set non-blocking read
|
|
131
|
+
let mut len_bytes = [0u8; 4];
|
|
132
|
+
match stream.read_exact(&mut len_bytes).await {
|
|
133
|
+
Ok(0) => {
|
|
134
|
+
// Connection closed
|
|
135
|
+
return Err(ProtocolError::ConnectionError(
|
|
136
|
+
"connection closed by peer".to_string(),
|
|
137
|
+
));
|
|
138
|
+
}
|
|
139
|
+
Ok(_) => {
|
|
140
|
+
let payload_len = u32::from_be_bytes(len_bytes) as usize;
|
|
141
|
+
|
|
142
|
+
if payload_len > 1024 * 1024 {
|
|
143
|
+
// Sanity check: don't allow messages larger than 1MB
|
|
144
|
+
return Err(ProtocolError::TransportError(
|
|
145
|
+
"message too large".to_string(),
|
|
146
|
+
));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
let mut payload = vec![0u8; payload_len];
|
|
150
|
+
stream
|
|
151
|
+
.read_exact(&mut payload)
|
|
152
|
+
.await
|
|
153
|
+
.map_err(|e| ProtocolError::TransportError(e.to_string()))?;
|
|
154
|
+
|
|
155
|
+
let message: ReplicationMessage = serde_json::from_slice(&payload)
|
|
156
|
+
.map_err(|e| ProtocolError::SerializationError(e.to_string()))?;
|
|
157
|
+
|
|
158
|
+
self.metrics.record_receive(4 + payload_len);
|
|
159
|
+
|
|
160
|
+
Ok(vec![message])
|
|
161
|
+
}
|
|
162
|
+
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
|
163
|
+
// No data available right now
|
|
164
|
+
Ok(Vec::new())
|
|
165
|
+
}
|
|
166
|
+
Err(e) => Err(ProtocolError::TransportError(e.to_string())),
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async fn connect(&mut self, peer_addr: &str) -> Result<(), ProtocolError> {
|
|
171
|
+
let stream = TcpStream::connect(peer_addr)
|
|
172
|
+
.await
|
|
173
|
+
.map_err(|e| ProtocolError::ConnectionError(e.to_string()))?;
|
|
174
|
+
|
|
175
|
+
*self.stream.lock().await = Some(stream);
|
|
176
|
+
*self.peer_addr.lock().await = Some(peer_addr.to_string());
|
|
177
|
+
self.is_connected.store(true, Ordering::Relaxed);
|
|
178
|
+
self.metrics.record_connection_state_change();
|
|
179
|
+
|
|
180
|
+
Ok(())
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async fn disconnect(&mut self) -> Result<(), ProtocolError> {
|
|
184
|
+
*self.stream.lock().await = None;
|
|
185
|
+
self.is_connected.store(false, Ordering::Relaxed);
|
|
186
|
+
self.metrics.record_connection_state_change();
|
|
187
|
+
|
|
188
|
+
Ok(())
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
fn is_connected(&self) -> bool {
|
|
192
|
+
self.is_connected.load(Ordering::Relaxed)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
#[cfg(test)]
|
|
197
|
+
mod tests {
|
|
198
|
+
use super::*;
|
|
199
|
+
use tokio::task;
|
|
200
|
+
|
|
201
|
+
#[tokio::test]
|
|
202
|
+
async fn tcp_bidirectional_message_exchange() {
|
|
203
|
+
let server_addr = "127.0.0.1:19001";
|
|
204
|
+
|
|
205
|
+
let mut server = TcpTransport::new(server_addr.to_string());
|
|
206
|
+
let mut client = TcpTransport::new("127.0.0.1:19002".to_string());
|
|
207
|
+
|
|
208
|
+
// Spawn server listening task
|
|
209
|
+
let _server_handle = {
|
|
210
|
+
let mut srv = server.clone();
|
|
211
|
+
task::spawn(async move {
|
|
212
|
+
srv.listen().await.expect("listen");
|
|
213
|
+
})
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// Give server time to start listening
|
|
217
|
+
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
|
|
218
|
+
|
|
219
|
+
// Client connects
|
|
220
|
+
client
|
|
221
|
+
.connect(server_addr)
|
|
222
|
+
.await
|
|
223
|
+
.expect("client connect");
|
|
224
|
+
|
|
225
|
+
// Wait for server to process connection
|
|
226
|
+
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
|
|
227
|
+
|
|
228
|
+
// Create a test message
|
|
229
|
+
let msg = ReplicationMessage::new(
|
|
230
|
+
crate::distributed_transactions::TransactionEnvelope::new(
|
|
231
|
+
"test_node".to_string(),
|
|
232
|
+
1,
|
|
233
|
+
"tx-1".to_string(),
|
|
234
|
+
vec![],
|
|
235
|
+
crate::transactions::ConsistencyContract::local(),
|
|
236
|
+
),
|
|
237
|
+
"test_node".to_string(),
|
|
238
|
+
"peer_node".to_string(),
|
|
239
|
+
1,
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
// Client sends
|
|
243
|
+
client.send(msg.clone()).await.expect("send");
|
|
244
|
+
|
|
245
|
+
// Server receives (wait briefly for message to arrive)
|
|
246
|
+
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
|
|
247
|
+
let received = server.receive().await.expect("receive");
|
|
248
|
+
|
|
249
|
+
println!("Server received {} messages", received.len());
|
|
250
|
+
assert_eq!(received.len(), 1);
|
|
251
|
+
assert_eq!(received[0].from_node, "test_node");
|
|
252
|
+
assert_eq!(received[0].to_node, "peer_node");
|
|
253
|
+
|
|
254
|
+
// Now try bidirectional: server sends back to client
|
|
255
|
+
let response = ReplicationMessage::new(
|
|
256
|
+
crate::distributed_transactions::TransactionEnvelope::new(
|
|
257
|
+
"server_node".to_string(),
|
|
258
|
+
1,
|
|
259
|
+
"tx-2".to_string(),
|
|
260
|
+
vec![],
|
|
261
|
+
crate::transactions::ConsistencyContract::local(),
|
|
262
|
+
),
|
|
263
|
+
"server_node".to_string(),
|
|
264
|
+
"client_node".to_string(),
|
|
265
|
+
1,
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
server.send(response.clone()).await.expect("server send");
|
|
269
|
+
|
|
270
|
+
// Client receives (wait briefly for message to arrive)
|
|
271
|
+
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
|
|
272
|
+
let client_received = client.receive().await.expect("client receive");
|
|
273
|
+
|
|
274
|
+
println!("Client received {} messages", client_received.len());
|
|
275
|
+
assert_eq!(client_received.len(), 1);
|
|
276
|
+
assert_eq!(client_received[0].from_node, "server_node");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
#[tokio::test]
|
|
280
|
+
async fn tcp_connection_status_tracked() {
|
|
281
|
+
let mut transport = TcpTransport::new("127.0.0.1:19003".to_string());
|
|
282
|
+
|
|
283
|
+
assert!(!transport.is_connected());
|
|
284
|
+
|
|
285
|
+
transport
|
|
286
|
+
.connect("127.0.0.1:9999")
|
|
287
|
+
.await
|
|
288
|
+
.expect_err("should fail - nobody listening");
|
|
289
|
+
|
|
290
|
+
assert!(!transport.is_connected());
|
|
291
|
+
assert_eq!(transport.metrics().get_connection_state_changes(), 0);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
#[test]
|
|
295
|
+
fn bincode_serialization_roundtrip() {
|
|
296
|
+
let msg = ReplicationMessage::new(
|
|
297
|
+
crate::distributed_transactions::TransactionEnvelope::new(
|
|
298
|
+
"test_node".to_string(),
|
|
299
|
+
1,
|
|
300
|
+
"tx-1".to_string(),
|
|
301
|
+
vec![],
|
|
302
|
+
crate::transactions::ConsistencyContract::local(),
|
|
303
|
+
),
|
|
304
|
+
"test_node".to_string(),
|
|
305
|
+
"peer_node".to_string(),
|
|
306
|
+
1,
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
let serialized = serde_json::to_vec(&msg).expect("serialize");
|
|
310
|
+
let deserialized: ReplicationMessage = serde_json::from_slice(&serialized).expect("deserialize");
|
|
311
|
+
|
|
312
|
+
assert_eq!(msg.from_node, deserialized.from_node);
|
|
313
|
+
assert_eq!(msg.to_node, deserialized.to_node);
|
|
314
|
+
assert_eq!(msg.sequence_number, deserialized.sequence_number);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
#[test]
|
|
318
|
+
fn bincode_serialization_with_operation() {
|
|
319
|
+
use crate::convergence::VectorClock;
|
|
320
|
+
use crate::transactions::{Operation, OperationCommand, OperationId, StateVersion};
|
|
321
|
+
use std::collections::HashMap;
|
|
322
|
+
use serde_json::json;
|
|
323
|
+
|
|
324
|
+
let mut fields = HashMap::new();
|
|
325
|
+
fields.insert("key1".to_string(), json!("value1"));
|
|
326
|
+
|
|
327
|
+
let mut parent_vc = VectorClock::new();
|
|
328
|
+
parent_vc.increment("node_a");
|
|
329
|
+
let parent_version = StateVersion::new(parent_vc, "hash_initial_a".to_string());
|
|
330
|
+
|
|
331
|
+
let op = Operation::new(
|
|
332
|
+
OperationId::new("node_a".to_string(), 1),
|
|
333
|
+
parent_version.clone(),
|
|
334
|
+
"set_operation".to_string(),
|
|
335
|
+
OperationCommand {
|
|
336
|
+
op_type: "set".to_string(),
|
|
337
|
+
collection: "items".to_string(),
|
|
338
|
+
record_id: "item1".to_string(),
|
|
339
|
+
fields,
|
|
340
|
+
},
|
|
341
|
+
"node_a".to_string(),
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
let msg = ReplicationMessage::new(
|
|
345
|
+
crate::distributed_transactions::TransactionEnvelope::new(
|
|
346
|
+
"node_a".to_string(),
|
|
347
|
+
1,
|
|
348
|
+
"tx-1".to_string(),
|
|
349
|
+
vec![op],
|
|
350
|
+
crate::transactions::ConsistencyContract::local(),
|
|
351
|
+
),
|
|
352
|
+
"node_a".to_string(),
|
|
353
|
+
"node_b".to_string(),
|
|
354
|
+
1,
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
let serialized = serde_json::to_vec(&msg).expect("serialize");
|
|
358
|
+
println!("Serialized {} bytes", serialized.len());
|
|
359
|
+
|
|
360
|
+
let deserialized: ReplicationMessage = serde_json::from_slice(&serialized).expect("deserialize");
|
|
361
|
+
|
|
362
|
+
assert_eq!(msg.from_node, deserialized.from_node);
|
|
363
|
+
assert_eq!(msg.to_node, deserialized.to_node);
|
|
364
|
+
assert_eq!(deserialized.envelope.operations.len(), 1);
|
|
365
|
+
}
|
|
366
|
+
}
|