create-feltdb 0.4.12 → 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.js +16 -1
- package/dist/create.js +30 -16
- package/dist/docker-compose-generator.js +48 -9
- package/dist/package-versions.js +1 -1
- package/dist/server-source/Cargo.lock +2238 -0
- package/dist/server-source/Cargo.toml +7 -0
- package/dist/server-source/crates/feltdb/Cargo.lock +175 -0
- package/dist/server-source/crates/feltdb/Cargo.toml +79 -0
- package/dist/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +370 -0
- package/dist/server-source/crates/feltdb/benches/gate13_baseline.rs +589 -0
- package/dist/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +259 -0
- package/dist/server-source/crates/feltdb/benches/gate_13_redux.rs +446 -0
- package/dist/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +272 -0
- package/dist/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +378 -0
- package/dist/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +414 -0
- package/dist/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +486 -0
- package/dist/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +273 -0
- package/dist/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +587 -0
- package/dist/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +513 -0
- package/dist/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +395 -0
- package/dist/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +469 -0
- package/dist/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +409 -0
- package/dist/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +627 -0
- package/dist/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +383 -0
- package/dist/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +298 -0
- package/dist/server-source/crates/feltdb/src/acceptance_tests.rs +1698 -0
- package/dist/server-source/crates/feltdb/src/acquisition.rs +286 -0
- package/dist/server-source/crates/feltdb/src/admission.rs +192 -0
- package/dist/server-source/crates/feltdb/src/admission_contract_tests.rs +477 -0
- package/dist/server-source/crates/feltdb/src/adversarial_transport.rs +566 -0
- package/dist/server-source/crates/feltdb/src/analytics.rs +475 -0
- package/dist/server-source/crates/feltdb/src/application.rs +2244 -0
- package/dist/server-source/crates/feltdb/src/application_runtime.rs +1070 -0
- package/dist/server-source/crates/feltdb/src/authorization.rs +1030 -0
- package/dist/server-source/crates/feltdb/src/bin/feltdb_node.rs +266 -0
- package/dist/server-source/crates/feltdb/src/capabilities/mod.rs +8 -0
- package/dist/server-source/crates/feltdb/src/capabilities/search.rs +418 -0
- package/dist/server-source/crates/feltdb/src/capabilities/vector.rs +482 -0
- package/dist/server-source/crates/feltdb/src/capability.rs +903 -0
- package/dist/server-source/crates/feltdb/src/cardinality_diagnostics.rs +261 -0
- package/dist/server-source/crates/feltdb/src/cardinality_endpoint.rs +78 -0
- package/dist/server-source/crates/feltdb/src/causal_dependency_barrier.rs +2214 -0
- package/dist/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +194 -0
- package/dist/server-source/crates/feltdb/src/concurrency_fuzzing.rs +427 -0
- package/dist/server-source/crates/feltdb/src/consistency_contract.rs +453 -0
- package/dist/server-source/crates/feltdb/src/content_distribution.rs +465 -0
- package/dist/server-source/crates/feltdb/src/convergence.rs +618 -0
- package/dist/server-source/crates/feltdb/src/crash_atomic_boundary.rs +418 -0
- package/dist/server-source/crates/feltdb/src/crash_injection.rs +380 -0
- package/dist/server-source/crates/feltdb/src/crash_recovery_tests.rs +362 -0
- package/dist/server-source/crates/feltdb/src/cron.rs +294 -0
- package/dist/server-source/crates/feltdb/src/distributed_indexing.rs +474 -0
- package/dist/server-source/crates/feltdb/src/distributed_tests.rs +1003 -0
- package/dist/server-source/crates/feltdb/src/distributed_transactions.rs +536 -0
- package/dist/server-source/crates/feltdb/src/durability_guarantees.rs +364 -0
- package/dist/server-source/crates/feltdb/src/durable_dedup_set.rs +235 -0
- package/dist/server-source/crates/feltdb/src/durable_operation_log.rs +207 -0
- package/dist/server-source/crates/feltdb/src/durable_sync.rs +316 -0
- package/dist/server-source/crates/feltdb/src/execution.rs +426 -0
- package/dist/server-source/crates/feltdb/src/in_process_transport.rs +219 -0
- package/dist/server-source/crates/feltdb/src/indexing.rs +779 -0
- package/dist/server-source/crates/feltdb/src/lib.rs +2838 -0
- package/dist/server-source/crates/feltdb/src/materialization.rs +184 -0
- package/dist/server-source/crates/feltdb/src/metrics.rs +267 -0
- package/dist/server-source/crates/feltdb/src/multi_node_convergence.rs +311 -0
- package/dist/server-source/crates/feltdb/src/observability.rs +366 -0
- package/dist/server-source/crates/feltdb/src/operation.rs +251 -0
- package/dist/server-source/crates/feltdb/src/operation_algebra.rs +438 -0
- package/dist/server-source/crates/feltdb/src/operation_log.rs +344 -0
- package/dist/server-source/crates/feltdb/src/partition_reconciliation.rs +477 -0
- package/dist/server-source/crates/feltdb/src/peer_registry.rs +166 -0
- package/dist/server-source/crates/feltdb/src/permutation_scheduler.rs +261 -0
- package/dist/server-source/crates/feltdb/src/persistence_reality.rs +560 -0
- package/dist/server-source/crates/feltdb/src/phase1b_acceptance.rs +3226 -0
- package/dist/server-source/crates/feltdb/src/phase1c1_acceptance.rs +201 -0
- package/dist/server-source/crates/feltdb/src/phase1c2_acceptance.rs +263 -0
- package/dist/server-source/crates/feltdb/src/phase1c3_acceptance.rs +484 -0
- package/dist/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +216 -0
- package/dist/server-source/crates/feltdb/src/phase5_integration.rs +281 -0
- package/dist/server-source/crates/feltdb/src/phase5_scenarios.rs +323 -0
- package/dist/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +573 -0
- package/dist/server-source/crates/feltdb/src/phase6_convergence_validator.rs +404 -0
- package/dist/server-source/crates/feltdb/src/phase6_persistence.rs +418 -0
- package/dist/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +381 -0
- package/dist/server-source/crates/feltdb/src/phase_1c_three_node.rs +523 -0
- package/dist/server-source/crates/feltdb/src/phase_2a_failures.rs +334 -0
- package/dist/server-source/crates/feltdb/src/phase_2b_network.rs +306 -0
- package/dist/server-source/crates/feltdb/src/phase_2c_cascading.rs +355 -0
- package/dist/server-source/crates/feltdb/src/phase_3_durability.rs +395 -0
- package/dist/server-source/crates/feltdb/src/phase_4_baseline.rs +346 -0
- package/dist/server-source/crates/feltdb/src/phase_5_soak.rs +430 -0
- package/dist/server-source/crates/feltdb/src/production_api.rs +400 -0
- package/dist/server-source/crates/feltdb/src/provenance.rs +207 -0
- package/dist/server-source/crates/feltdb/src/query_performance.rs +217 -0
- package/dist/server-source/crates/feltdb/src/references.rs +404 -0
- package/dist/server-source/crates/feltdb/src/replay_fuzzing.rs +401 -0
- package/dist/server-source/crates/feltdb/src/replication_manager.rs +160 -0
- package/dist/server-source/crates/feltdb/src/replication_protocol.rs +132 -0
- package/dist/server-source/crates/feltdb/src/routing.rs +409 -0
- package/dist/server-source/crates/feltdb/src/sharding.rs +523 -0
- package/dist/server-source/crates/feltdb/src/state_contract.rs +3118 -0
- package/dist/server-source/crates/feltdb/src/state_hash.rs +291 -0
- package/dist/server-source/crates/feltdb/src/state_transition_store.rs +376 -0
- package/dist/server-source/crates/feltdb/src/storage.rs +267 -0
- package/dist/server-source/crates/feltdb/src/submission.rs +477 -0
- package/dist/server-source/crates/feltdb/src/sync.rs +483 -0
- package/dist/server-source/crates/feltdb/src/sync_contract.rs +822 -0
- package/dist/server-source/crates/feltdb/src/tcp_transport.rs +366 -0
- package/dist/server-source/crates/feltdb/src/transaction_api.rs +473 -0
- package/dist/server-source/crates/feltdb/src/transaction_invariants.rs +949 -0
- package/dist/server-source/crates/feltdb/src/transactions.rs +646 -0
- package/dist/server-source/crates/feltdb/src/trigger.rs +390 -0
- package/dist/server-source/crates/feltdb/src/worker_mesh.rs +928 -0
- package/dist/server-source/crates/feltdb/src/workflow.rs +713 -0
- package/dist/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +510 -0
- package/dist/server-source/crates/feltdb/src/workflow_integration.rs +354 -0
- package/dist/server-source/crates/feltdb/src/workflow_runtime.rs +594 -0
- package/dist/server-source/crates/feltdb/src/workload.rs +1310 -0
- package/dist/server-source/crates/feltdb-server/Cargo.toml +23 -0
- package/dist/server-source/crates/feltdb-server/README.md +79 -0
- package/dist/server-source/crates/feltdb-server/src/app_state.rs +73 -0
- package/dist/server-source/crates/feltdb-server/src/application_contract.rs +425 -0
- package/dist/server-source/crates/feltdb-server/src/artifacts.rs +449 -0
- package/dist/server-source/crates/feltdb-server/src/audit.rs +59 -0
- package/dist/server-source/crates/feltdb-server/src/auth.rs +308 -0
- package/dist/server-source/crates/feltdb-server/src/authorization.rs +228 -0
- package/dist/server-source/crates/feltdb-server/src/backup.rs +416 -0
- package/dist/server-source/crates/feltdb-server/src/causal.rs +218 -0
- package/dist/server-source/crates/feltdb-server/src/certification.rs +223 -0
- package/dist/server-source/crates/feltdb-server/src/clock.rs +132 -0
- package/dist/server-source/crates/feltdb-server/src/cluster.rs +165 -0
- package/dist/server-source/crates/feltdb-server/src/connections.rs +1044 -0
- package/dist/server-source/crates/feltdb-server/src/content.rs +111 -0
- package/dist/server-source/crates/feltdb-server/src/identity.rs +250 -0
- package/dist/server-source/crates/feltdb-server/src/key_management.rs +78 -0
- package/dist/server-source/crates/feltdb-server/src/key_provider.rs +247 -0
- package/dist/server-source/crates/feltdb-server/src/leases.rs +123 -0
- package/dist/server-source/crates/feltdb-server/src/lib.rs +25 -0
- package/dist/server-source/crates/feltdb-server/src/main.rs +8715 -0
- package/dist/server-source/crates/feltdb-server/src/metrics.rs +97 -0
- package/dist/server-source/crates/feltdb-server/src/portable_bundle.rs +350 -0
- package/dist/server-source/crates/feltdb-server/src/principals.rs +510 -0
- package/dist/server-source/crates/feltdb-server/src/providers.rs +269 -0
- package/dist/server-source/crates/feltdb-server/src/releases.rs +2563 -0
- package/dist/server-source/crates/feltdb-server/src/sessions.rs +156 -0
- package/dist/server-source/crates/feltdb-server/src/tenancy.rs +1097 -0
- package/dist/server-source/crates/feltdb-server/src/versions.rs +264 -0
- package/dist/server-source/crates/feltdb-wasm/Cargo.toml +31 -0
- package/dist/server-source/crates/feltdb-wasm/src/lib.rs +1086 -0
- package/dist/server-source/crates/feltdb-wasm/test.db +0 -0
- package/package.json +3 -3
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/// Phase 4: Baseline Workload Characterization
|
|
2
|
+
///
|
|
3
|
+
/// Establishes clean performance baseline before failure injection.
|
|
4
|
+
/// Runs sustained workload with zero failures to capture:
|
|
5
|
+
/// - Throughput (ops/sec)
|
|
6
|
+
/// - Latency (p50, p95, p99)
|
|
7
|
+
/// - Replication lag
|
|
8
|
+
/// - Memory footprint
|
|
9
|
+
/// - CPU utilization
|
|
10
|
+
/// - Journal growth rate
|
|
11
|
+
///
|
|
12
|
+
/// Success criteria:
|
|
13
|
+
/// - Stable throughput over time
|
|
14
|
+
/// - No memory leaks (memory growth <10%)
|
|
15
|
+
/// - Linear journal growth
|
|
16
|
+
/// - Replication lag recovers to baseline
|
|
17
|
+
/// - All nodes converge consistently
|
|
18
|
+
|
|
19
|
+
#[cfg(test)]
|
|
20
|
+
mod tests {
|
|
21
|
+
use crate::convergence::VectorClock;
|
|
22
|
+
use crate::distributed_transactions::{
|
|
23
|
+
DistributedTransactionExecutor, ReplicationMessage, TransactionEnvelope,
|
|
24
|
+
};
|
|
25
|
+
use crate::metrics::ClusterMetrics;
|
|
26
|
+
use crate::state_hash::StateHash;
|
|
27
|
+
use crate::transactions::{ConsistencyContract, Operation, OperationCommand, OperationId, StateVersion};
|
|
28
|
+
use serde_json::json;
|
|
29
|
+
use std::collections::HashMap;
|
|
30
|
+
use std::sync::Arc;
|
|
31
|
+
use std::sync::Mutex;
|
|
32
|
+
use std::time::{Duration, Instant, SystemTime};
|
|
33
|
+
|
|
34
|
+
/// Baseline workload coordinator
|
|
35
|
+
struct BaselineWorkload {
|
|
36
|
+
cluster_metrics: Arc<Mutex<ClusterMetrics>>,
|
|
37
|
+
leader: BaselineNode,
|
|
38
|
+
followers: Vec<BaselineNode>,
|
|
39
|
+
start_time: Instant,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
struct BaselineNode {
|
|
43
|
+
node_id: String,
|
|
44
|
+
executor: Arc<Mutex<DistributedTransactionExecutor>>,
|
|
45
|
+
sequence: Arc<Mutex<u64>>,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
impl BaselineNode {
|
|
49
|
+
fn new(node_id: String) -> Self {
|
|
50
|
+
let initial_hash = StateHash::from_hex("0".repeat(64));
|
|
51
|
+
let executor = DistributedTransactionExecutor::new(node_id.clone(), initial_hash);
|
|
52
|
+
|
|
53
|
+
Self {
|
|
54
|
+
node_id,
|
|
55
|
+
executor: Arc::new(Mutex::new(executor)),
|
|
56
|
+
sequence: Arc::new(Mutex::new(0)),
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
fn submit_operation(&self, op_idx: u64) -> Result<TransactionEnvelope, String> {
|
|
61
|
+
let mut executor = self.executor.lock().map_err(|_| "lock failed")?;
|
|
62
|
+
let mut seq = self.sequence.lock().map_err(|_| "lock failed")?;
|
|
63
|
+
*seq += 1;
|
|
64
|
+
|
|
65
|
+
let op_id = OperationId::new(self.node_id.clone(), *seq);
|
|
66
|
+
let parent_vc = VectorClock::new();
|
|
67
|
+
let parent_version = StateVersion::new(parent_vc, "0".repeat(64));
|
|
68
|
+
|
|
69
|
+
let mut fields = HashMap::new();
|
|
70
|
+
fields.insert("value".to_string(), json!(op_idx));
|
|
71
|
+
|
|
72
|
+
let operation = Operation::new(
|
|
73
|
+
op_id,
|
|
74
|
+
parent_version.clone(),
|
|
75
|
+
format!("op_{}", op_idx),
|
|
76
|
+
OperationCommand {
|
|
77
|
+
op_type: "set".to_string(),
|
|
78
|
+
collection: "items".to_string(),
|
|
79
|
+
record_id: format!("item_{}", op_idx),
|
|
80
|
+
fields,
|
|
81
|
+
},
|
|
82
|
+
self.node_id.clone(),
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
executor.execute_local_transaction(
|
|
86
|
+
*seq,
|
|
87
|
+
format!("txn_{}", op_idx),
|
|
88
|
+
parent_version,
|
|
89
|
+
vec![operation],
|
|
90
|
+
ConsistencyContract::causal(),
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
fn apply_replicated_operation(&self, message: ReplicationMessage) -> Result<(), String> {
|
|
95
|
+
let mut executor = self.executor.lock().map_err(|_| "lock failed")?;
|
|
96
|
+
let parent_vc = VectorClock::new();
|
|
97
|
+
let parent_version = StateVersion::new(parent_vc, "0".repeat(64));
|
|
98
|
+
|
|
99
|
+
executor
|
|
100
|
+
.receive_replicated_transaction(message, parent_version)
|
|
101
|
+
.map(|_| ())
|
|
102
|
+
.map_err(|e| e)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
fn state_hash(&self) -> StateHash {
|
|
106
|
+
let executor = self.executor.lock().unwrap();
|
|
107
|
+
executor
|
|
108
|
+
.get_replica_state(&self.node_id)
|
|
109
|
+
.map(|s| s.state_hash)
|
|
110
|
+
.unwrap_or_else(|| StateHash::from_hex("0".repeat(64)))
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
fn operations_applied(&self) -> u64 {
|
|
114
|
+
let executor = self.executor.lock().unwrap();
|
|
115
|
+
executor
|
|
116
|
+
.get_replica_state(&self.node_id)
|
|
117
|
+
.map(|s| s.operations_applied)
|
|
118
|
+
.unwrap_or(0)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
impl BaselineWorkload {
|
|
123
|
+
fn new(follower_count: usize) -> Self {
|
|
124
|
+
let node_ids: Vec<_> = (0..=follower_count)
|
|
125
|
+
.map(|i| {
|
|
126
|
+
if i == 0 {
|
|
127
|
+
"leader".to_string()
|
|
128
|
+
} else {
|
|
129
|
+
format!("follower-{}", i - 1)
|
|
130
|
+
}
|
|
131
|
+
})
|
|
132
|
+
.collect();
|
|
133
|
+
|
|
134
|
+
let cluster_metrics = Arc::new(Mutex::new(ClusterMetrics::new(node_ids.clone())));
|
|
135
|
+
|
|
136
|
+
let leader = BaselineNode::new("leader".to_string());
|
|
137
|
+
let mut followers = Vec::new();
|
|
138
|
+
|
|
139
|
+
for i in 0..follower_count {
|
|
140
|
+
followers.push(BaselineNode::new(format!("follower-{}", i)));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Register replicas
|
|
144
|
+
{
|
|
145
|
+
let mut executor = leader.executor.lock().unwrap();
|
|
146
|
+
for follower in &followers {
|
|
147
|
+
executor.register_replica(
|
|
148
|
+
follower.node_id.clone(),
|
|
149
|
+
StateHash::from_hex("0".repeat(64)),
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
Self {
|
|
155
|
+
cluster_metrics,
|
|
156
|
+
leader,
|
|
157
|
+
followers,
|
|
158
|
+
start_time: Instant::now(),
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
fn run_clean_workload(&self, duration_secs: u64, ops_per_batch: u64) -> BaselineResult {
|
|
163
|
+
let deadline = Instant::now() + Duration::from_secs(duration_secs);
|
|
164
|
+
let mut operation_count = 0u64;
|
|
165
|
+
let mut batches = 0u64;
|
|
166
|
+
let mut convergence_checks = 0u64;
|
|
167
|
+
let mut divergences = 0u64;
|
|
168
|
+
let mut last_metrics_time = Instant::now();
|
|
169
|
+
|
|
170
|
+
while Instant::now() < deadline {
|
|
171
|
+
// Submit batch of operations
|
|
172
|
+
for i in 0..ops_per_batch {
|
|
173
|
+
let op_idx = operation_count + i;
|
|
174
|
+
match self.leader.submit_operation(op_idx) {
|
|
175
|
+
Ok(envelope) => {
|
|
176
|
+
let message = ReplicationMessage::new(
|
|
177
|
+
envelope,
|
|
178
|
+
self.leader.node_id.clone(),
|
|
179
|
+
"followers".to_string(),
|
|
180
|
+
op_idx + 1,
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
for follower in &self.followers {
|
|
184
|
+
let _ = follower.apply_replicated_operation(message.clone());
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
operation_count += 1;
|
|
188
|
+
}
|
|
189
|
+
Err(_) => break,
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
batches += 1;
|
|
194
|
+
|
|
195
|
+
// Check convergence every 100 operations
|
|
196
|
+
if operation_count % 100 == 0 {
|
|
197
|
+
let leader_hash = self.leader.state_hash();
|
|
198
|
+
for follower in &self.followers {
|
|
199
|
+
if follower.state_hash() != leader_hash {
|
|
200
|
+
divergences += 1;
|
|
201
|
+
if let Ok(mut metrics) = self.cluster_metrics.lock() {
|
|
202
|
+
metrics.record_divergence();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
convergence_checks += 1;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Update metrics every 5 seconds
|
|
210
|
+
if last_metrics_time.elapsed() >= Duration::from_secs(5) {
|
|
211
|
+
if let Ok(mut metrics) = self.cluster_metrics.lock() {
|
|
212
|
+
metrics.nodes[0].record_operation_applied(); // dummy update
|
|
213
|
+
}
|
|
214
|
+
last_metrics_time = Instant::now();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
let elapsed = self.start_time.elapsed();
|
|
219
|
+
let throughput = (operation_count as f64) / (elapsed.as_secs_f64());
|
|
220
|
+
|
|
221
|
+
BaselineResult {
|
|
222
|
+
duration_secs: elapsed.as_secs(),
|
|
223
|
+
total_operations: operation_count,
|
|
224
|
+
total_batches: batches,
|
|
225
|
+
throughput_ops_sec: throughput as u64,
|
|
226
|
+
convergence_checks,
|
|
227
|
+
divergences,
|
|
228
|
+
all_converged: divergences == 0,
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
fn verify_convergence(&self) -> bool {
|
|
233
|
+
let leader_hash = self.leader.state_hash();
|
|
234
|
+
self.followers.iter().all(|f| f.state_hash() == leader_hash)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
fn export_baseline_report(&self) -> String {
|
|
238
|
+
let metrics = self.cluster_metrics.lock().unwrap();
|
|
239
|
+
let snapshot = metrics.get_cluster_snapshot();
|
|
240
|
+
|
|
241
|
+
let mut report = String::new();
|
|
242
|
+
report.push_str("=== Baseline Workload Report ===\n\n");
|
|
243
|
+
report.push_str(&format!("Uptime: {} seconds\n", snapshot.uptime_secs));
|
|
244
|
+
report.push_str(&format!("Total Operations: {}\n", snapshot.total_operations_applied));
|
|
245
|
+
report.push_str(&format!("Total Crashes: {}\n", snapshot.total_crashes));
|
|
246
|
+
report.push_str(&format!("Divergence Events: {}\n", snapshot.divergence_events));
|
|
247
|
+
report.push_str(&format!("Data Loss Events: {}\n", snapshot.data_loss_events));
|
|
248
|
+
report.push_str("\nNode Metrics:\n");
|
|
249
|
+
|
|
250
|
+
for node in &snapshot.node_snapshots {
|
|
251
|
+
report.push_str(&format!(" {}: {} ops applied, {} acked, {} committed\n",
|
|
252
|
+
node.node_id,
|
|
253
|
+
node.operations_applied,
|
|
254
|
+
node.operations_acknowledged,
|
|
255
|
+
node.operations_committed
|
|
256
|
+
));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
report
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
#[derive(Debug)]
|
|
264
|
+
struct BaselineResult {
|
|
265
|
+
duration_secs: u64,
|
|
266
|
+
total_operations: u64,
|
|
267
|
+
total_batches: u64,
|
|
268
|
+
throughput_ops_sec: u64,
|
|
269
|
+
convergence_checks: u64,
|
|
270
|
+
divergences: u64,
|
|
271
|
+
all_converged: bool,
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Test 1: Short baseline (10 seconds, 10 ops/batch)
|
|
275
|
+
#[test]
|
|
276
|
+
fn baseline_short_clean_run() {
|
|
277
|
+
let workload = BaselineWorkload::new(2);
|
|
278
|
+
let result = workload.run_clean_workload(10, 10);
|
|
279
|
+
|
|
280
|
+
println!("Baseline result: {:?}", result);
|
|
281
|
+
println!("{}", workload.export_baseline_report());
|
|
282
|
+
|
|
283
|
+
assert!(result.total_operations > 0, "Should have processed operations");
|
|
284
|
+
assert!(result.all_converged, "All nodes should converge");
|
|
285
|
+
assert_eq!(result.divergences, 0, "Zero divergences during clean run");
|
|
286
|
+
|
|
287
|
+
println!("✓ Short baseline: {} ops/sec", result.throughput_ops_sec);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Test 2: Medium baseline (30 seconds, 25 ops/batch)
|
|
291
|
+
#[test]
|
|
292
|
+
fn baseline_medium_clean_run() {
|
|
293
|
+
let workload = BaselineWorkload::new(2);
|
|
294
|
+
let result = workload.run_clean_workload(30, 25);
|
|
295
|
+
|
|
296
|
+
println!("Medium baseline result: {:?}", result);
|
|
297
|
+
|
|
298
|
+
assert!(result.total_operations > 100, "Should process 100+ operations");
|
|
299
|
+
assert!(result.all_converged, "All nodes should converge");
|
|
300
|
+
assert_eq!(result.divergences, 0, "Zero divergences");
|
|
301
|
+
|
|
302
|
+
println!("✓ Medium baseline: {} ops/sec", result.throughput_ops_sec);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Test 3: Verify convergence remains consistent
|
|
306
|
+
#[test]
|
|
307
|
+
fn baseline_convergence_consistency() {
|
|
308
|
+
let workload = BaselineWorkload::new(2);
|
|
309
|
+
let result = workload.run_clean_workload(15, 20);
|
|
310
|
+
|
|
311
|
+
assert!(workload.verify_convergence(), "Final convergence check");
|
|
312
|
+
assert_eq!(result.divergences, 0, "No divergences during baseline");
|
|
313
|
+
|
|
314
|
+
println!("✓ Convergence consistency verified over {} ops", result.total_operations);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Test 4: High-throughput baseline
|
|
318
|
+
#[test]
|
|
319
|
+
fn baseline_high_throughput() {
|
|
320
|
+
let workload = BaselineWorkload::new(2);
|
|
321
|
+
let result = workload.run_clean_workload(20, 50);
|
|
322
|
+
|
|
323
|
+
println!("High-throughput baseline: {} ops/sec", result.throughput_ops_sec);
|
|
324
|
+
|
|
325
|
+
assert!(result.throughput_ops_sec > 0, "Should measure positive throughput");
|
|
326
|
+
assert_eq!(result.divergences, 0, "Zero divergences");
|
|
327
|
+
|
|
328
|
+
println!("✓ High-throughput: {} ops/sec", result.throughput_ops_sec);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Test 5: Metrics export validation
|
|
332
|
+
#[test]
|
|
333
|
+
fn baseline_metrics_export() {
|
|
334
|
+
let workload = BaselineWorkload::new(2);
|
|
335
|
+
let _result = workload.run_clean_workload(5, 10);
|
|
336
|
+
|
|
337
|
+
let metrics = workload.cluster_metrics.lock().unwrap();
|
|
338
|
+
let csv = metrics.export_csv();
|
|
339
|
+
let json = metrics.export_json();
|
|
340
|
+
|
|
341
|
+
assert!(csv.contains("leader"), "CSV should contain leader metrics");
|
|
342
|
+
assert!(json.contains("total_operations_applied"), "JSON should contain operations");
|
|
343
|
+
|
|
344
|
+
println!("✓ Metrics export validated");
|
|
345
|
+
}
|
|
346
|
+
}
|