@feltdb/core 0.4.12 → 0.4.14

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 (165) hide show
  1. package/dist/cli/commands.js +42 -25
  2. package/dist/cli/index.js +1 -1
  3. package/dist/create/cli.js +39 -4
  4. package/dist/create/create.js +30 -18
  5. package/dist/create/docker-compose-generator.js +68 -11
  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/ConflictExplorer.d.ts.map +1 -1
  160. package/dist/studio/components/index.js +1 -1
  161. package/dist/studio/{components-Q0Nx6gLE.js → components-9kDSWiGL.js} +163 -47
  162. package/dist/studio/index.js +31 -28
  163. package/dist/studio-app/assets/{index-BHOmLZF-.js → index-DVdvmf69.js} +9 -9
  164. package/dist/studio-app/index.html +1 -1
  165. package/package.json +1 -1
@@ -0,0 +1,513 @@
1
+ /// Gate 14A-SYNC: Synchronization Economics Measurement
2
+ ///
3
+ /// Objective: Characterize the cost of the current mutex-based write path.
4
+ /// Measure whether lock contention or critical-section work dominates.
5
+ ///
6
+ /// FROZEN WORKLOAD (identical to Gate 14A/RC/RC2):
7
+ /// - 1000 operations per client
8
+ /// - 10,000 record dataset
9
+ /// - 70% reads, 30% writes (seed: 42)
10
+ /// - Consensus: Causal
11
+ ///
12
+ /// MEASUREMENTS (across concurrency 1 → 2 → 4 → 8 → 16 → 32 → 64):
13
+ /// - Lock acquisition attempts (try_lock calls)
14
+ /// - Successful acquisitions (first try + retries)
15
+ /// - Failed acquisitions (retry exhaustion)
16
+ /// - Lock hold duration (critical section time)
17
+ /// - Lock wait duration (retry loops, backoff time)
18
+ /// - Operations per successful lock acquisition
19
+ /// - Retry distribution (0, 1, 2, 3+ attempts)
20
+ /// - Rejection rate (%)
21
+ /// - Throughput (ops/sec)
22
+ /// - p50/p95/p99 latencies
23
+ ///
24
+ /// KEY ANALYSIS:
25
+ /// Ratio = lock_wait_time / total_operation_time
26
+ /// If ratio is high (lock dominates) → admission architecture is bottleneck
27
+ /// If ratio is low (lock is cheap) → other subsystem is constrained
28
+
29
+ use criterion::{criterion_group, criterion_main, Criterion};
30
+ use feltdb::Operation;
31
+ use serde_json::json;
32
+ use std::sync::Arc;
33
+ use std::time::{Instant, Duration};
34
+
35
+ // ============================================================================
36
+ // FROZEN WORKLOAD DEFINITION
37
+ // ============================================================================
38
+
39
+ const OPERATIONS_PER_CLIENT: usize = 1000;
40
+ const RECORD_COUNT: usize = 10_000;
41
+ const READ_WRITE_RATIO: f64 = 0.7;
42
+ const RANDOM_SEED: u64 = 42;
43
+ const CONCURRENCY_LEVELS: &[usize] = &[1, 2, 4, 8, 16, 32, 64];
44
+ const TRIALS_PER_LEVEL: usize = 3;
45
+
46
+ /// Seeded random number generator
47
+ struct SeededRng {
48
+ state: u64,
49
+ }
50
+
51
+ impl SeededRng {
52
+ fn new(seed: u64) -> Self {
53
+ SeededRng { state: seed }
54
+ }
55
+
56
+ fn next_u64(&mut self) -> u64 {
57
+ self.state ^= self.state << 13;
58
+ self.state ^= self.state >> 7;
59
+ self.state ^= self.state << 17;
60
+ self.state
61
+ }
62
+
63
+ fn next_f64(&mut self) -> f64 {
64
+ ((self.next_u64() >> 11) as f64) / (1u64 << 53) as f64
65
+ }
66
+
67
+ fn next_range(&mut self, min: usize, max: usize) -> usize {
68
+ min + ((self.next_u64() as usize) % (max - min + 1))
69
+ }
70
+ }
71
+
72
+ // ============================================================================
73
+ // WORKLOAD GENERATION
74
+ // ============================================================================
75
+
76
+ fn generate_operation(
77
+ rng: &mut SeededRng,
78
+ op_id: u64,
79
+ sequence: u64,
80
+ instance_id: &str,
81
+ ) -> Operation {
82
+ let record_key = format!("record_{}", rng.next_range(0, RECORD_COUNT - 1));
83
+ let is_write = rng.next_f64() >= READ_WRITE_RATIO;
84
+
85
+ let value = if is_write {
86
+ json!({ "timestamp": rng.next_u64(), "data": format!("write_{}", op_id) })
87
+ } else {
88
+ json!({ "read": true })
89
+ };
90
+
91
+ Operation::insert(
92
+ op_id,
93
+ instance_id.to_string(),
94
+ sequence,
95
+ record_key,
96
+ value,
97
+ "json".to_string(),
98
+ "default".to_string(),
99
+ )
100
+ }
101
+
102
+ fn generate_frozen_workload(instance_id: &str, client_id: usize) -> Vec<Operation> {
103
+ let mut rng = SeededRng::new(RANDOM_SEED.wrapping_add(client_id as u64));
104
+ let mut operations = Vec::with_capacity(OPERATIONS_PER_CLIENT);
105
+
106
+ for seq in 0..OPERATIONS_PER_CLIENT as u64 {
107
+ let op_id = (client_id as u64 * OPERATIONS_PER_CLIENT as u64) + seq;
108
+ operations.push(generate_operation(&mut rng, op_id, seq, instance_id));
109
+ }
110
+
111
+ operations
112
+ }
113
+
114
+ // ============================================================================
115
+ // LOCK ECONOMICS TRACKING
116
+ // ============================================================================
117
+
118
+ #[derive(Clone)]
119
+ struct LockOperation {
120
+ op_id: u64,
121
+ operation_latency_us: u64,
122
+ lock_wait_us: u64,
123
+ lock_hold_us: u64,
124
+ acquisition_attempts: usize,
125
+ retry_count: usize,
126
+ success: bool,
127
+ }
128
+
129
+ #[derive(Clone, Default)]
130
+ struct LockStatistics {
131
+ total_operations: usize,
132
+ successful_operations: usize,
133
+ rejected_operations: usize,
134
+ total_acquisition_attempts: usize,
135
+ total_lock_wait_us: u64,
136
+ total_lock_hold_us: u64,
137
+ ops_per_acquisition: f64,
138
+ retry_distribution: [usize; 5], // [0 retries, 1, 2, 3, 4+]
139
+ throughput_ops_per_sec: f64,
140
+ p50_operation_latency_us: u64,
141
+ p95_operation_latency_us: u64,
142
+ p99_operation_latency_us: u64,
143
+ lock_wait_ratio: f64, // lock_wait_time / total_operation_time
144
+ critical_section_ratio: f64, // lock_hold_time / total_operation_time
145
+ }
146
+
147
+ impl LockStatistics {
148
+ fn from_operations(ops: &[LockOperation], wall_clock_ms: f64) -> Self {
149
+ let total = ops.len();
150
+ let successful = ops.iter().filter(|o| o.success).count();
151
+ let rejected = total - successful;
152
+
153
+ let total_attempts: usize = ops.iter().map(|o| o.acquisition_attempts).sum();
154
+ let total_wait: u64 = ops.iter().map(|o| o.lock_wait_us).sum();
155
+ let total_hold: u64 = ops.iter().map(|o| o.lock_hold_us).sum();
156
+
157
+ let ops_per_acq = if total_attempts > 0 {
158
+ successful as f64 / total_attempts as f64
159
+ } else {
160
+ 0.0
161
+ };
162
+
163
+ // Retry distribution
164
+ let mut retry_dist = [0; 5];
165
+ for op in ops {
166
+ if op.success {
167
+ let idx = op.retry_count.min(4);
168
+ retry_dist[idx] += 1;
169
+ }
170
+ }
171
+
172
+ // Latency percentiles
173
+ let mut latencies: Vec<u64> = ops.iter().map(|o| o.operation_latency_us).collect();
174
+ latencies.sort_unstable();
175
+
176
+ let p50 = if !latencies.is_empty() {
177
+ latencies[latencies.len() / 2]
178
+ } else {
179
+ 0
180
+ };
181
+ let p95 = if !latencies.is_empty() {
182
+ latencies[(latencies.len() * 95) / 100]
183
+ } else {
184
+ 0
185
+ };
186
+ let p99 = if !latencies.is_empty() {
187
+ latencies[(latencies.len() * 99) / 100]
188
+ } else {
189
+ 0
190
+ };
191
+
192
+ let total_operation_time_us: u64 = ops.iter().map(|o| o.operation_latency_us).sum();
193
+ let throughput = if wall_clock_ms > 0.0 {
194
+ (successful as f64 / wall_clock_ms) * 1000.0
195
+ } else {
196
+ 0.0
197
+ };
198
+
199
+ let wait_ratio = if total_operation_time_us > 0 {
200
+ total_wait as f64 / total_operation_time_us as f64
201
+ } else {
202
+ 0.0
203
+ };
204
+
205
+ let hold_ratio = if total_operation_time_us > 0 {
206
+ total_hold as f64 / total_operation_time_us as f64
207
+ } else {
208
+ 0.0
209
+ };
210
+
211
+ LockStatistics {
212
+ total_operations: total,
213
+ successful_operations: successful,
214
+ rejected_operations: rejected,
215
+ total_acquisition_attempts: total_attempts,
216
+ total_lock_wait_us: total_wait,
217
+ total_lock_hold_us: total_hold,
218
+ ops_per_acquisition: ops_per_acq,
219
+ retry_distribution: retry_dist,
220
+ throughput_ops_per_sec: throughput,
221
+ p50_operation_latency_us: p50,
222
+ p95_operation_latency_us: p95,
223
+ p99_operation_latency_us: p99,
224
+ lock_wait_ratio: wait_ratio,
225
+ critical_section_ratio: hold_ratio,
226
+ }
227
+ }
228
+ }
229
+
230
+ // ============================================================================
231
+ // MEASUREMENT WITH LOCK INSTRUMENTATION
232
+ // ============================================================================
233
+
234
+ async fn measure_synchronization_economics(concurrency: usize) -> (LockStatistics, usize) {
235
+ let operation_log = Arc::new(tokio::sync::Mutex::new(Vec::new()));
236
+ let measurements = Arc::new(tokio::sync::Mutex::new(Vec::new()));
237
+ let start_time = Instant::now();
238
+ let mut handles = vec![];
239
+
240
+ for client_id in 0..concurrency {
241
+ let log = Arc::clone(&operation_log);
242
+ let meas = Arc::clone(&measurements);
243
+ let instance_id = format!("node_{}", client_id);
244
+
245
+ let handle = tokio::spawn(async move {
246
+ let operations = generate_frozen_workload(&instance_id, client_id);
247
+
248
+ for op in operations.iter() {
249
+ let op_id = op.op_id;
250
+ let op_start = Instant::now();
251
+ let mut total_wait_us = 0u64;
252
+ let mut total_hold_us = 0u64;
253
+ let mut acquisition_attempts = 0;
254
+ let mut retry_count = 0;
255
+ let mut success = false;
256
+
257
+ // Try once without waiting
258
+ let try_start = Instant::now();
259
+ if let Ok(mut log_guard) = log.try_lock() {
260
+ let hold_start = Instant::now();
261
+ log_guard.push(op.clone());
262
+ total_hold_us = hold_start.elapsed().as_micros() as u64;
263
+ acquisition_attempts = 1;
264
+ success = true;
265
+ } else {
266
+ // Record initial attempt failure
267
+ total_wait_us += try_start.elapsed().as_micros() as u64;
268
+ acquisition_attempts = 1;
269
+
270
+ // Retry with exponential backoff (matching Gate 14A: 3 retries)
271
+ for attempt in 1..=3 {
272
+ let backoff_us = 100_u64 * (2_u64).saturating_pow(attempt as u32);
273
+ let sleep_start = Instant::now();
274
+ tokio::time::sleep(Duration::from_micros(backoff_us)).await;
275
+ total_wait_us += sleep_start.elapsed().as_micros() as u64;
276
+
277
+ let try_start = Instant::now();
278
+ if let Ok(mut log_guard) = log.try_lock() {
279
+ let hold_start = Instant::now();
280
+ log_guard.push(op.clone());
281
+ total_hold_us = hold_start.elapsed().as_micros() as u64;
282
+ acquisition_attempts += 1;
283
+ retry_count = attempt;
284
+ success = true;
285
+ break;
286
+ } else {
287
+ total_wait_us += try_start.elapsed().as_micros() as u64;
288
+ acquisition_attempts += 1;
289
+ }
290
+ }
291
+ }
292
+
293
+ let operation_latency_us = op_start.elapsed().as_micros() as u64;
294
+
295
+ let lock_op = LockOperation {
296
+ op_id,
297
+ operation_latency_us,
298
+ lock_wait_us: total_wait_us,
299
+ lock_hold_us: total_hold_us,
300
+ acquisition_attempts,
301
+ retry_count,
302
+ success,
303
+ };
304
+
305
+ {
306
+ let mut m = meas.lock().await;
307
+ m.push(lock_op);
308
+ }
309
+ }
310
+ });
311
+
312
+ handles.push(handle);
313
+ }
314
+
315
+ for handle in handles {
316
+ let _ = handle.await;
317
+ }
318
+
319
+ let wall_clock_ms = start_time.elapsed().as_secs_f64() * 1000.0;
320
+ let final_log = operation_log.lock().await;
321
+ let ingested_count = final_log.len();
322
+
323
+ let measurements_guard = measurements.lock().await;
324
+ let stats = LockStatistics::from_operations(&measurements_guard, wall_clock_ms);
325
+
326
+ (stats, ingested_count)
327
+ }
328
+
329
+ // ============================================================================
330
+ // BENCHMARK HARNESS
331
+ // ============================================================================
332
+
333
+ fn gate_14a_sync_economics(c: &mut Criterion) {
334
+ let mut group = c.benchmark_group("gate14a_sync_economics");
335
+ group.sample_size(10);
336
+ group.measurement_time(Duration::from_secs(5));
337
+
338
+ let rt = tokio::runtime::Runtime::new().unwrap();
339
+
340
+ println!("\n═══════════════════════════════════════════════════════════════════");
341
+ println!("Gate 14A-SYNC: Synchronization Economics Measurement");
342
+ println!("═══════════════════════════════════════════════════════════════════");
343
+ println!("\nFROZEN WORKLOAD:");
344
+ println!(" Operations per client: {}", OPERATIONS_PER_CLIENT);
345
+ println!(" Record count: {}", RECORD_COUNT);
346
+ println!(" Read/write ratio: 70% / 30%");
347
+ println!(" Random seed: {}", RANDOM_SEED);
348
+ println!("\nKEY MEASUREMENTS:");
349
+ println!(" • Lock acquisition attempts (try_lock calls)");
350
+ println!(" • Successful vs rejected acquisitions");
351
+ println!(" • Lock hold duration (critical section time)");
352
+ println!(" • Lock wait duration (retry + backoff)");
353
+ println!(" • Critical ratio = lock_hold_time / total_operation_time");
354
+ println!(" • Wait ratio = lock_wait_time / total_operation_time");
355
+ println!("\nINTERPRETATION:");
356
+ println!(" High wait ratio → admission contention is bottleneck");
357
+ println!(" High hold ratio → critical section work is bottleneck");
358
+ println!("\n───────────────────────────────────────────────────────────────────");
359
+
360
+ let mut all_results: Vec<(usize, LockStatistics)> = Vec::new();
361
+
362
+ println!("\nCONCURRENCY SCALING:");
363
+ println!(
364
+ "{:8} │ {:8} │ {:8} │ {:8} │ {:6} │ {:6} │ {:6} │ {:8}",
365
+ "Writers", "Success", "Rejected", "Attempts", "Wait%", "Hold%", "Ops/acq", "Ops/sec"
366
+ );
367
+ println!("{}", "─".repeat(87));
368
+
369
+ for &concurrency in CONCURRENCY_LEVELS {
370
+ let mut trial_stats = Vec::new();
371
+
372
+ for _trial in 0..TRIALS_PER_LEVEL {
373
+ let (stats, _) = rt.block_on(measure_synchronization_economics(concurrency));
374
+ trial_stats.push(stats);
375
+ }
376
+
377
+ // Average across trials
378
+ let avg_success: usize = trial_stats.iter().map(|s| s.successful_operations).sum::<usize>()
379
+ / trial_stats.len();
380
+ let avg_rejected: usize = trial_stats.iter().map(|s| s.rejected_operations).sum::<usize>()
381
+ / trial_stats.len();
382
+ let avg_attempts: usize =
383
+ trial_stats.iter().map(|s| s.total_acquisition_attempts).sum::<usize>()
384
+ / trial_stats.len();
385
+ let avg_wait_ratio: f64 = trial_stats.iter().map(|s| s.lock_wait_ratio).sum::<f64>()
386
+ / trial_stats.len() as f64;
387
+ let avg_hold_ratio: f64 = trial_stats.iter().map(|s| s.critical_section_ratio).sum::<f64>()
388
+ / trial_stats.len() as f64;
389
+ let avg_ops_per_acq: f64 = trial_stats.iter().map(|s| s.ops_per_acquisition).sum::<f64>()
390
+ / trial_stats.len() as f64;
391
+ let avg_throughput: f64 =
392
+ trial_stats.iter().map(|s| s.throughput_ops_per_sec).sum::<f64>()
393
+ / trial_stats.len() as f64;
394
+
395
+ println!(
396
+ "{:8} │ {:8} │ {:8} │ {:8} │ {:5.1}% │ {:5.1}% │ {:6.2} │ {:8.0}",
397
+ concurrency, avg_success, avg_rejected, avg_attempts,
398
+ avg_wait_ratio * 100.0,
399
+ avg_hold_ratio * 100.0,
400
+ avg_ops_per_acq,
401
+ avg_throughput
402
+ );
403
+
404
+ // Store first trial for detailed analysis
405
+ all_results.push((concurrency, trial_stats[0].clone()));
406
+ }
407
+
408
+ println!("─────────────────────────────────────────────────────────────────");
409
+
410
+ // =========================================================================
411
+ // DETAILED ANALYSIS AT KEY CONCURRENCY POINTS
412
+ // =========================================================================
413
+
414
+ println!("\nDETAILED ANALYSIS:");
415
+ println!("\n┌─ Concurrency Boundary Analysis ─────────────────────────────────┐");
416
+
417
+ if let Some((_, stats_1)) = all_results.iter().find(|(c, _)| *c == 1) {
418
+ if let Some((_, stats_8)) = all_results.iter().find(|(c, _)| *c == 8) {
419
+ println!("│ Single writer (baseline):");
420
+ println!(
421
+ "│ Wait ratio: {:.2}% | Hold ratio: {:.2}% | Throughput: {:.0} ops/sec",
422
+ stats_1.lock_wait_ratio * 100.0,
423
+ stats_1.critical_section_ratio * 100.0,
424
+ stats_1.throughput_ops_per_sec
425
+ );
426
+ println!("│");
427
+ println!("│ Eight writers (scaling challenge):");
428
+ println!(
429
+ "│ Wait ratio: {:.2}% | Hold ratio: {:.2}% | Throughput: {:.0} ops/sec",
430
+ stats_8.lock_wait_ratio * 100.0,
431
+ stats_8.critical_section_ratio * 100.0,
432
+ stats_8.throughput_ops_per_sec
433
+ );
434
+ println!("│");
435
+
436
+ let wait_increase = stats_8.lock_wait_ratio / stats_1.lock_wait_ratio;
437
+ let hold_increase = stats_8.critical_section_ratio / stats_1.critical_section_ratio;
438
+
439
+ println!("│ Ratio increase from 1→8 writers:");
440
+ println!("│ Lock wait contention: {:.1}x", wait_increase);
441
+ println!("│ Critical section: {:.1}x", hold_increase);
442
+
443
+ if wait_increase > hold_increase * 2.0 {
444
+ println!("│");
445
+ println!("│ ⚠ BOTTLENECK IDENTIFIED:");
446
+ println!("│ Lock acquisition contention dominates");
447
+ println!("│ (wait ratio increase >> hold ratio increase)");
448
+ } else if hold_increase > wait_increase * 2.0 {
449
+ println!("│");
450
+ println!("│ ⚠ BOTTLENECK IDENTIFIED:");
451
+ println!("│ Critical section work dominates");
452
+ println!("│ (hold ratio increase >> wait ratio increase)");
453
+ } else {
454
+ println!("│");
455
+ println!("│ ✓ BALANCED CONTENTION:");
456
+ println!("│ Both lock wait and hold scale proportionally");
457
+ }
458
+ }
459
+ }
460
+
461
+ println!("└──────────────────────────────────────────────────────────────┘");
462
+
463
+ // =========================================================================
464
+ // RETRY DISTRIBUTION AT HIGH CONCURRENCY
465
+ // =========================================================================
466
+
467
+ println!("\nRETRY DISTRIBUTION (at 64 writers):");
468
+ if let Some((_, stats_64)) = all_results.iter().find(|(c, _)| *c == 64) {
469
+ let total_successful = stats_64.retry_distribution.iter().sum::<usize>();
470
+ if total_successful > 0 {
471
+ println!(
472
+ " 0 retries: {} ({:.1}%)",
473
+ stats_64.retry_distribution[0],
474
+ (stats_64.retry_distribution[0] as f64 / total_successful as f64) * 100.0
475
+ );
476
+ for i in 1..4 {
477
+ if stats_64.retry_distribution[i] > 0 {
478
+ println!(
479
+ " {} retries: {} ({:.1}%)",
480
+ i,
481
+ stats_64.retry_distribution[i],
482
+ (stats_64.retry_distribution[i] as f64 / total_successful as f64) * 100.0
483
+ );
484
+ }
485
+ }
486
+ }
487
+ }
488
+
489
+ println!("\n───────────────────────────────────────────────────────────────────");
490
+ println!("SYNCHRONIZATION ECONOMICS SUMMARY:");
491
+ println!("───────────────────────────────────────────────────────────────────");
492
+ println!("\nBottleneck Analysis:");
493
+ println!(" If lock_wait_ratio grows faster than critical_section_ratio");
494
+ println!(" → Admission architecture is the bottleneck");
495
+ println!(" → Consider: bounded queue, batching, or actor model");
496
+ println!(" → Current mutex may not be appropriate for this concurrency");
497
+ println!(" ");
498
+ println!(" If critical_section_ratio grows faster than lock_wait_ratio");
499
+ println!(" → Critical section work is the bottleneck");
500
+ println!(" → Consider: reduce operations per transaction, lazy evaluation");
501
+ println!(" → Mutex is not the primary constraint");
502
+ println!(" ");
503
+ println!(" If both grow proportionally");
504
+ println!(" → Contention is unavoidable; consider load reduction");
505
+ println!(" → Or verify that behavior matches concurrency theory");
506
+
507
+ println!("\n═══════════════════════════════════════════════════════════════════\n");
508
+
509
+ group.finish();
510
+ }
511
+
512
+ criterion_group!(benches, gate_14a_sync_economics);
513
+ criterion_main!(benches);