1use crate::sim::rng::{sim_random_range, sim_random_range_or_default};
2use std::ops::Range;
3use std::time::Duration;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
10pub enum ConnectFailureMode {
11 #[default]
13 Disabled,
14 AlwaysFail,
16 Probabilistic,
18}
19
20impl ConnectFailureMode {
21 pub fn random_for_seed() -> Self {
23 match sim_random_range(0..3) {
24 0 => Self::Disabled,
25 1 => Self::AlwaysFail,
26 _ => Self::Probabilistic,
27 }
28 }
29}
30
31#[derive(Debug, Clone)]
36pub struct ChaosConfiguration {
37 pub clog_probability: f64,
39 pub clog_duration: Range<Duration>,
41
42 pub partition_probability: f64,
44 pub partition_duration: Range<Duration>,
46
47 pub bit_flip_probability: f64,
49 pub bit_flip_min_bits: u32,
51 pub bit_flip_max_bits: u32,
53 pub bit_flip_cooldown: Duration,
55
56 pub partial_write_max_bytes: usize,
59
60 pub random_close_probability: f64,
63
64 pub random_close_cooldown: Duration,
67
68 pub random_close_explicit_ratio: f64,
71
72 pub packet_loss_probability: f64,
77
78 pub clock_drift_enabled: bool,
82
83 pub clock_drift_max: Duration,
86
87 pub buggified_delay_enabled: bool,
91
92 pub buggified_delay_max: Duration,
96
97 pub buggified_delay_probability: f64,
99
100 pub connect_failure_mode: ConnectFailureMode,
103
104 pub connect_failure_probability: f64,
106}
107
108impl Default for ChaosConfiguration {
109 fn default() -> Self {
110 Self {
111 clog_probability: 0.0,
112 clog_duration: Duration::from_millis(100)..Duration::from_millis(300),
113 partition_probability: 0.0,
114 partition_duration: Duration::from_millis(200)..Duration::from_secs(2),
115 bit_flip_probability: 0.0001, bit_flip_min_bits: 1,
117 bit_flip_max_bits: 32,
118 bit_flip_cooldown: Duration::ZERO, partial_write_max_bytes: 1000, random_close_probability: 0.00001, random_close_cooldown: Duration::from_secs(5), random_close_explicit_ratio: 0.3, packet_loss_probability: 0.0, clock_drift_enabled: true, clock_drift_max: Duration::from_millis(100), buggified_delay_enabled: true, buggified_delay_max: Duration::from_millis(100), buggified_delay_probability: 0.25, connect_failure_mode: ConnectFailureMode::Probabilistic, connect_failure_probability: 0.5, }
132 }
133}
134
135impl ChaosConfiguration {
136 pub fn disabled() -> Self {
138 Self {
139 clog_probability: 0.0,
140 clog_duration: Duration::ZERO..Duration::ZERO,
141 partition_probability: 0.0,
142 partition_duration: Duration::ZERO..Duration::ZERO,
143 bit_flip_probability: 0.0,
144 bit_flip_min_bits: 1,
145 bit_flip_max_bits: 32,
146 bit_flip_cooldown: Duration::ZERO,
147 partial_write_max_bytes: 1000,
148 random_close_probability: 0.0,
149 random_close_cooldown: Duration::ZERO,
150 random_close_explicit_ratio: 0.3,
151 packet_loss_probability: 0.0,
152 clock_drift_enabled: false,
153 clock_drift_max: Duration::from_millis(100),
154 buggified_delay_enabled: false,
155 buggified_delay_max: Duration::from_millis(100),
156 buggified_delay_probability: 0.25,
157 connect_failure_mode: ConnectFailureMode::Disabled,
158 connect_failure_probability: 0.5,
159 }
160 }
161
162 pub fn random_for_seed() -> Self {
164 Self {
165 clog_probability: sim_random_range(0..20) as f64 / 100.0, clog_duration: Duration::from_micros(sim_random_range(50000..300000))
167 ..Duration::from_micros(sim_random_range(100000..500000)),
168 partition_probability: sim_random_range(0..15) as f64 / 100.0, partition_duration: Duration::from_millis(sim_random_range(100..1000))
170 ..Duration::from_millis(sim_random_range(500..3000)),
171 bit_flip_probability: sim_random_range(1..20) as f64 / 100000.0,
173 bit_flip_min_bits: 1,
174 bit_flip_max_bits: 32,
175 bit_flip_cooldown: Duration::from_millis(sim_random_range(0..100)),
176 partial_write_max_bytes: sim_random_range(100..2000), random_close_probability: sim_random_range(1..100) as f64 / 1000000.0,
179 random_close_cooldown: Duration::from_millis(sim_random_range(1000..10000)),
180 random_close_explicit_ratio: sim_random_range(20..40) as f64 / 100.0, packet_loss_probability: sim_random_range(0..50) as f64 / 1000.0,
183 clock_drift_enabled: true,
184 clock_drift_max: Duration::from_millis(sim_random_range(50..150)), buggified_delay_enabled: true,
186 buggified_delay_max: Duration::from_millis(sim_random_range(50..150)), buggified_delay_probability: sim_random_range(20..30) as f64 / 100.0, connect_failure_mode: ConnectFailureMode::random_for_seed(),
189 connect_failure_probability: sim_random_range(40..60) as f64 / 100.0, }
191 }
192}
193
194#[derive(Debug, Clone)]
196pub struct NetworkConfiguration {
197 pub bind_latency: Range<Duration>,
199 pub accept_latency: Range<Duration>,
201 pub connect_latency: Range<Duration>,
203 pub read_latency: Range<Duration>,
205 pub write_latency: Range<Duration>,
207
208 pub chaos: ChaosConfiguration,
210}
211
212impl Default for NetworkConfiguration {
213 fn default() -> Self {
214 Self {
215 bind_latency: Duration::from_micros(50)..Duration::from_micros(150),
216 accept_latency: Duration::from_millis(1)..Duration::from_millis(6),
217 connect_latency: Duration::from_millis(1)..Duration::from_millis(11),
218 read_latency: Duration::from_micros(10)..Duration::from_micros(60),
219 write_latency: Duration::from_micros(100)..Duration::from_micros(600),
220 chaos: ChaosConfiguration::default(),
221 }
222 }
223}
224
225pub fn sample_duration(range: &Range<Duration>) -> Duration {
227 let start_nanos = range.start.as_nanos() as u64;
228 let end_nanos = range.end.as_nanos() as u64;
229 let random_nanos = sim_random_range_or_default(start_nanos..end_nanos);
230 Duration::from_nanos(random_nanos)
231}
232
233impl NetworkConfiguration {
234 pub fn new() -> Self {
236 Self::default()
237 }
238
239 pub fn random_for_seed() -> Self {
241 Self {
242 bind_latency: Duration::from_micros(sim_random_range(10..200))
243 ..Duration::from_micros(sim_random_range(50..300)),
244 accept_latency: Duration::from_micros(sim_random_range(1000..10000))
245 ..Duration::from_micros(sim_random_range(5000..15000)),
246 connect_latency: Duration::from_micros(sim_random_range(1000..50000))
247 ..Duration::from_micros(sim_random_range(10000..100000)),
248 read_latency: Duration::from_micros(sim_random_range(5..100))
249 ..Duration::from_micros(sim_random_range(50..200)),
250 write_latency: Duration::from_micros(sim_random_range(50..1000))
251 ..Duration::from_micros(sim_random_range(200..2000)),
252 chaos: ChaosConfiguration::random_for_seed(),
253 }
254 }
255
256 pub fn fast_local() -> Self {
258 let one_us = Duration::from_micros(1);
259 let ten_us = Duration::from_micros(10);
260 Self {
261 bind_latency: one_us..one_us,
262 accept_latency: ten_us..ten_us,
263 connect_latency: ten_us..ten_us,
264 read_latency: one_us..one_us,
265 write_latency: one_us..one_us,
266 chaos: ChaosConfiguration::disabled(),
267 }
268 }
269}