bitfold_peer/
bandwidth_throttle.rs1use std::time::{Duration, Instant};
25
26const BANDWIDTH_WINDOW: Duration = Duration::from_secs(1);
28
29pub struct BandwidthThrottle {
34 bytes_sent_this_window: u32,
36 bytes_received_this_window: u32,
38 bandwidth_window_start: Instant,
40 outgoing_bandwidth_limit: u32,
42 incoming_bandwidth_limit: u32,
44}
45
46impl BandwidthThrottle {
47 pub fn new(outgoing_limit: u32, incoming_limit: u32, start_time: Instant) -> Self {
55 Self {
56 bytes_sent_this_window: 0,
57 bytes_received_this_window: 0,
58 bandwidth_window_start: start_time,
59 outgoing_bandwidth_limit: outgoing_limit,
60 incoming_bandwidth_limit: incoming_limit,
61 }
62 }
63
64 pub fn update_bandwidth_window(&mut self, time: Instant) -> bool {
73 if time.duration_since(self.bandwidth_window_start) >= BANDWIDTH_WINDOW {
74 self.bytes_sent_this_window = 0;
75 self.bytes_received_this_window = 0;
76 self.bandwidth_window_start = time;
77 true
78 } else {
79 false
80 }
81 }
82
83 pub fn record_bytes_sent(&mut self, bytes: u32) {
87 self.bytes_sent_this_window = self.bytes_sent_this_window.saturating_add(bytes);
88 }
89
90 pub fn record_bytes_received(&mut self, bytes: u32) {
94 self.bytes_received_this_window = self.bytes_received_this_window.saturating_add(bytes);
95 }
96
97 pub fn can_send_within_bandwidth(&self) -> bool {
103 if self.outgoing_bandwidth_limit == 0 {
104 return true; }
106 self.bytes_sent_this_window < self.outgoing_bandwidth_limit
107 }
108
109 pub fn bandwidth_utilization(&self) -> f32 {
118 if self.outgoing_bandwidth_limit == 0 {
119 return 0.0; }
121 self.bytes_sent_this_window as f32 / self.outgoing_bandwidth_limit as f32
122 }
123
124 pub fn can_receive_within_bandwidth(&self) -> bool {
130 if self.incoming_bandwidth_limit == 0 {
131 return true; }
133 self.bytes_received_this_window < self.incoming_bandwidth_limit
134 }
135
136 pub fn incoming_bandwidth_utilization(&self) -> f32 {
145 if self.incoming_bandwidth_limit == 0 {
146 return 0.0; }
148 self.bytes_received_this_window as f32 / self.incoming_bandwidth_limit as f32
149 }
150
151 pub fn set_outgoing_bandwidth_limit(&mut self, limit: u32) {
157 self.outgoing_bandwidth_limit = limit;
158 }
159
160 pub fn set_incoming_bandwidth_limit(&mut self, limit: u32) {
166 self.incoming_bandwidth_limit = limit;
167 }
168
169 pub fn outgoing_bandwidth_limit(&self) -> u32 {
171 self.outgoing_bandwidth_limit
172 }
173
174 pub fn incoming_bandwidth_limit(&self) -> u32 {
176 self.incoming_bandwidth_limit
177 }
178
179 pub fn bytes_sent_this_window(&self) -> u32 {
181 self.bytes_sent_this_window
182 }
183
184 pub fn bytes_received_this_window(&self) -> u32 {
186 self.bytes_received_this_window
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193
194 #[test]
195 fn test_bandwidth_unlimited_by_default() {
196 let time = Instant::now();
197 let mut throttle = BandwidthThrottle::new(0, 0, time);
198
199 assert!(throttle.can_send_within_bandwidth());
201
202 throttle.record_bytes_sent(1_000_000);
204 assert!(throttle.can_send_within_bandwidth());
205
206 assert_eq!(throttle.bandwidth_utilization(), 0.0);
208 }
209
210 #[test]
211 fn test_bandwidth_throttling_when_limited() {
212 let time = Instant::now();
213 let mut throttle = BandwidthThrottle::new(1000, 0, time); assert!(throttle.can_send_within_bandwidth());
217 assert_eq!(throttle.bandwidth_utilization(), 0.0);
218
219 throttle.record_bytes_sent(500);
221 assert!(throttle.can_send_within_bandwidth());
222 assert_eq!(throttle.bandwidth_utilization(), 0.5);
223
224 throttle.record_bytes_sent(500);
226 assert!(!throttle.can_send_within_bandwidth()); assert_eq!(throttle.bandwidth_utilization(), 1.0);
228
229 throttle.record_bytes_sent(100);
231 assert!(!throttle.can_send_within_bandwidth());
232 assert!(throttle.bandwidth_utilization() > 1.0);
233
234 let time_plus_1sec = time + Duration::from_secs(1);
236 throttle.update_bandwidth_window(time_plus_1sec);
237 assert!(throttle.can_send_within_bandwidth());
238 assert_eq!(throttle.bandwidth_utilization(), 0.0);
239 }
240
241 #[test]
242 fn test_bandwidth_limit_updates() {
243 let time = Instant::now();
244 let mut throttle = BandwidthThrottle::new(0, 0, time);
245
246 assert_eq!(throttle.outgoing_bandwidth_limit(), 0);
248 assert_eq!(throttle.incoming_bandwidth_limit(), 0);
249
250 throttle.set_incoming_bandwidth_limit(1234);
252 throttle.set_outgoing_bandwidth_limit(5678);
253
254 assert_eq!(throttle.incoming_bandwidth_limit(), 1234);
255 assert_eq!(throttle.outgoing_bandwidth_limit(), 5678);
256 }
257
258 #[test]
259 fn test_incoming_bandwidth_throttling() {
260 let time = Instant::now();
261 let mut throttle = BandwidthThrottle::new(0, 2000, time); assert!(throttle.can_receive_within_bandwidth());
265 assert_eq!(throttle.incoming_bandwidth_utilization(), 0.0);
266
267 throttle.record_bytes_received(1000);
269 assert!(throttle.can_receive_within_bandwidth());
270 assert_eq!(throttle.incoming_bandwidth_utilization(), 0.5);
271
272 throttle.record_bytes_received(1000);
274 assert!(!throttle.can_receive_within_bandwidth()); assert_eq!(throttle.incoming_bandwidth_utilization(), 1.0);
276
277 let time_plus_1sec = time + Duration::from_secs(1);
279 throttle.update_bandwidth_window(time_plus_1sec);
280 assert!(throttle.can_receive_within_bandwidth());
281 assert_eq!(throttle.incoming_bandwidth_utilization(), 0.0);
282 }
283
284 #[test]
285 fn test_bytes_tracking() {
286 let time = Instant::now();
287 let mut throttle = BandwidthThrottle::new(1000, 2000, time);
288
289 assert_eq!(throttle.bytes_sent_this_window(), 0);
290 assert_eq!(throttle.bytes_received_this_window(), 0);
291
292 throttle.record_bytes_sent(100);
293 throttle.record_bytes_received(200);
294
295 assert_eq!(throttle.bytes_sent_this_window(), 100);
296 assert_eq!(throttle.bytes_received_this_window(), 200);
297
298 let time_plus_1sec = time + Duration::from_secs(1);
300 throttle.update_bandwidth_window(time_plus_1sec);
301
302 assert_eq!(throttle.bytes_sent_this_window(), 0);
303 assert_eq!(throttle.bytes_received_this_window(), 0);
304 }
305
306 #[test]
307 fn test_saturating_addition() {
308 let time = Instant::now();
309 let mut throttle = BandwidthThrottle::new(1000, 2000, time);
310
311 throttle.record_bytes_sent(u32::MAX);
313 throttle.record_bytes_sent(100); assert_eq!(throttle.bytes_sent_this_window(), u32::MAX);
315
316 throttle.record_bytes_received(u32::MAX);
318 throttle.record_bytes_received(100); assert_eq!(throttle.bytes_received_this_window(), u32::MAX);
320 }
321}