1use crate::MonotonicInstant;
2use std::time::Duration;
3
4pub type BusyHandlerCallback = Box<dyn Fn(i32) -> i32 + Send + Sync>;
18
19#[derive(Default)]
20pub enum BusyHandler {
22 #[default]
23 None,
25 Timeout(Duration),
28 Custom { callback: BusyHandlerCallback },
30}
31
32impl std::fmt::Debug for BusyHandler {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 match self {
35 BusyHandler::None => write!(f, "BusyHandler::None"),
36 BusyHandler::Timeout(d) => write!(f, "BusyHandler::Timeout({d:?}"),
37 BusyHandler::Custom { .. } => write!(f, "BusyHandler::Custom"),
38 }
39 }
40}
41
42#[derive(Debug)]
51pub struct BusyHandlerState {
52 invocation_count: i32,
54 timeout: MonotonicInstant,
56 iteration: usize,
58}
59
60impl BusyHandlerState {
61 const DELAYS: [Duration; 12] = [
63 Duration::from_millis(1),
64 Duration::from_millis(2),
65 Duration::from_millis(5),
66 Duration::from_millis(10),
67 Duration::from_millis(15),
68 Duration::from_millis(20),
69 Duration::from_millis(25),
70 Duration::from_millis(25),
71 Duration::from_millis(25),
72 Duration::from_millis(50),
73 Duration::from_millis(50),
74 Duration::from_millis(100),
75 ];
76
77 const TOTALS: [Duration; 12] = [
79 Duration::from_millis(0),
80 Duration::from_millis(1),
81 Duration::from_millis(3),
82 Duration::from_millis(8),
83 Duration::from_millis(18),
84 Duration::from_millis(33),
85 Duration::from_millis(53),
86 Duration::from_millis(78),
87 Duration::from_millis(103),
88 Duration::from_millis(128),
89 Duration::from_millis(178),
90 Duration::from_millis(228),
91 ];
92
93 pub fn new(now: MonotonicInstant) -> Self {
95 Self {
96 invocation_count: 0,
97 timeout: now,
98 iteration: 0,
99 }
100 }
101
102 pub fn reset(&mut self, now: MonotonicInstant) {
104 self.invocation_count = 0;
105 self.timeout = now;
106 self.iteration = 0;
107 }
108
109 pub fn timeout(&self) -> MonotonicInstant {
111 self.timeout
112 }
113
114 pub fn invoke(&mut self, handler: &BusyHandler, now: MonotonicInstant) -> bool {
122 match handler {
123 BusyHandler::None => {
124 false
126 }
127 BusyHandler::Timeout(max_duration) => self.invoke_timeout_handler(*max_duration, now),
128 BusyHandler::Custom { callback } => {
129 let result = callback(self.invocation_count);
130 self.invocation_count += 1;
131 if result != 0 {
132 self.timeout = now + Duration::from_millis(1);
134 true
135 } else {
136 false
137 }
138 }
139 }
140 }
141
142 fn invoke_timeout_handler(&mut self, max_duration: Duration, now: MonotonicInstant) -> bool {
146 let idx = self.iteration.min(11);
147 let mut delay = Self::DELAYS[idx];
148 let mut prior = Self::TOTALS[idx];
149
150 if self.iteration >= 12 {
152 prior += delay * (self.iteration as u32 - 11);
153 }
154
155 if prior + delay > max_duration {
157 delay = max_duration.saturating_sub(prior);
158 if delay.is_zero() {
159 return false;
160 }
161 }
162
163 self.iteration = self.iteration.saturating_add(1);
164 self.invocation_count += 1;
165 self.timeout = now + delay;
166 true
167 }
168
169 pub fn get_delay(&self, now: MonotonicInstant) -> Duration {
174 if now >= self.timeout {
175 Duration::ZERO
176 } else {
177 self.timeout.duration_since(now)
178 }
179 }
180}
181
182#[cfg(clt_turso_tests)]
183mod tests {
184 use super::*;
185
186 fn test_instant() -> MonotonicInstant {
187 MonotonicInstant::now()
188 }
189
190 #[test]
191 fn test_busy_handler_timeout_basic() {
192 let handler = BusyHandler::Timeout(Duration::from_millis(100));
193 let now = test_instant();
194 let mut state = BusyHandlerState::new(now);
195
196 assert!(state.invoke(&handler, now));
198 assert_eq!(state.timeout(), now + Duration::from_millis(1));
200 }
201
202 #[test]
203 fn test_busy_handler_timeout_exhausted() {
204 let handler = BusyHandler::Timeout(Duration::from_millis(0));
205 let now = test_instant();
206 let mut state = BusyHandlerState::new(now);
207
208 assert!(!state.invoke(&handler, now));
210 }
211
212 #[test]
213 fn test_busy_handler_custom_callback() {
214 let callback: BusyHandlerCallback = Box::new(|count| if count < 3 { 1 } else { 0 });
216 let handler = BusyHandler::Custom { callback };
217 let now = test_instant();
218 let mut state = BusyHandlerState::new(now);
219
220 assert!(state.invoke(&handler, now));
222 assert!(state.invoke(&handler, now));
223 assert!(state.invoke(&handler, now));
224 assert!(!state.invoke(&handler, now));
226 }
227
228 #[test]
229 fn test_busy_handler_none_returns_false_immediately() {
230 let handler = BusyHandler::None;
231 let now = test_instant();
232 let mut state = BusyHandlerState::new(now);
233
234 assert!(!state.invoke(&handler, now));
236 assert!(!state.invoke(&handler, now));
238 }
239
240 #[test]
241 fn test_custom_callback_receives_correct_count() {
242 use std::sync::{Arc, Mutex};
243
244 let counts = Arc::new(Mutex::new(Vec::new()));
246 let counts_clone = counts.clone();
247
248 let callback: BusyHandlerCallback = Box::new(move |count| {
249 counts_clone.lock().unwrap().push(count);
250 if count < 5 {
251 1
252 } else {
253 0
254 }
255 });
256
257 let handler = BusyHandler::Custom { callback };
258 let now = test_instant();
259 let mut state = BusyHandlerState::new(now);
260
261 for _ in 0..6 {
263 state.invoke(&handler, now);
264 }
265
266 assert_eq!(*counts.lock().unwrap(), vec![0, 1, 2, 3, 4, 5]);
268 }
269
270 #[test]
271 fn test_custom_callback_always_retry() {
272 let callback: BusyHandlerCallback = Box::new(|_| 1);
274 let handler = BusyHandler::Custom { callback };
275 let now = test_instant();
276 let mut state = BusyHandlerState::new(now);
277
278 for _ in 0..100 {
280 assert!(state.invoke(&handler, now));
281 }
282 }
283
284 #[test]
285 fn test_custom_callback_never_retry() {
286 let callback: BusyHandlerCallback = Box::new(|_| 0);
288 let handler = BusyHandler::Custom { callback };
289 let now = test_instant();
290 let mut state = BusyHandlerState::new(now);
291
292 assert!(!state.invoke(&handler, now));
294 }
295
296 #[test]
297 fn test_custom_callback_sets_timeout() {
298 let callback: BusyHandlerCallback = Box::new(|_| 1);
299 let handler = BusyHandler::Custom { callback };
300 let now = test_instant();
301 let mut state = BusyHandlerState::new(now);
302
303 assert!(state.invoke(&handler, now));
304 assert_eq!(state.timeout(), now + Duration::from_millis(1));
306 }
307
308 #[test]
309 fn test_timeout_delay_schedule() {
310 let handler = BusyHandler::Timeout(Duration::from_secs(10)); let now = test_instant();
312 let mut state = BusyHandlerState::new(now);
313
314 let expected_delays_ms: [u64; 12] = [1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100];
317
318 for (i, expected_ms) in expected_delays_ms.iter().enumerate() {
319 assert!(state.invoke(&handler, now), "iteration {i} should retry");
320 let timeout = state.timeout();
321 assert_eq!(
322 timeout,
323 now + Duration::from_millis(*expected_ms),
324 "iteration {i} should have delay of {expected_ms}ms"
325 );
326 }
327 }
328
329 #[test]
330 fn test_timeout_caps_at_max_duration() {
331 let handler = BusyHandler::Timeout(Duration::from_millis(5));
333 let now = test_instant();
334 let mut state = BusyHandlerState::new(now);
335
336 assert!(state.invoke(&handler, now));
338 assert!(state.invoke(&handler, now));
340 assert!(state.invoke(&handler, now));
343 assert!(!state.invoke(&handler, now));
345 }
346
347 #[test]
348 fn test_state_reset() {
349 let handler = BusyHandler::Timeout(Duration::from_millis(100));
350 let now = test_instant();
351 let mut state = BusyHandlerState::new(now);
352
353 state.invoke(&handler, now);
355 state.invoke(&handler, now);
356 state.invoke(&handler, now);
357
358 let later = MonotonicInstant::now();
360 state.reset(later);
361
362 assert_eq!(state.timeout(), later);
364 assert!(state.invoke(&handler, later));
365 assert_eq!(state.timeout(), later + Duration::from_millis(1));
367 }
368
369 #[test]
370 fn test_get_delay_when_timeout_passed() {
371 let now = MonotonicInstant::now();
372 let state = BusyHandlerState::new(now);
373
374 assert_eq!(state.get_delay(now), Duration::ZERO);
376
377 std::thread::sleep(Duration::from_micros(10));
379 let later = MonotonicInstant::now();
380 assert_eq!(state.get_delay(later), Duration::ZERO);
381 }
382
383 #[test]
384 fn test_get_delay_calculates_remaining_time() {
385 let now = MonotonicInstant::now();
386 let mut state = BusyHandlerState::new(now);
387
388 let handler = BusyHandler::Timeout(Duration::from_millis(100));
389 state.invoke(&handler, now); let delay = state.get_delay(now);
393 assert_eq!(delay, Duration::from_millis(1));
394 }
395}