1use std::{
4 sync::{
5 atomic::{AtomicU64, Ordering},
6 LazyLock,
7 },
8 time::Instant,
9};
10
11#[doc(hidden)]
13pub const NOT_YET_RUN: u64 = u64::MAX;
14
15#[doc(hidden)]
17pub fn should_run(start: &LazyLock<Instant>, last: &AtomicU64, duration_millis: u64) -> bool {
18 let now = start.elapsed().as_millis() as u64;
19 let last_val = last.load(Ordering::Relaxed);
20
21 if last_val == NOT_YET_RUN {
22 return last
23 .compare_exchange(NOT_YET_RUN, now, Ordering::Relaxed, Ordering::Relaxed)
24 .is_ok();
25 }
26
27 if now.saturating_sub(last_val) >= duration_millis {
28 last.compare_exchange(last_val, now, Ordering::Relaxed, Ordering::Relaxed).is_ok()
29 } else {
30 false
31 }
32}
33
34#[deprecated(
51 note = "no longer used by reth and scheduled for removal, copy the macro if you depend on it"
52)]
53#[macro_export]
54macro_rules! throttle {
55 ($duration:expr, || $expr:expr) => {{
56 static START: ::std::sync::LazyLock<::std::time::Instant> =
57 ::std::sync::LazyLock::new(::std::time::Instant::now);
58 static LAST: ::core::sync::atomic::AtomicU64 =
59 ::core::sync::atomic::AtomicU64::new($crate::__private::NOT_YET_RUN);
60
61 if $crate::__private::should_run(&START, &LAST, $duration.as_millis() as u64) {
62 $expr
63 }
64 }};
65}
66
67#[cfg(test)]
68#[allow(deprecated)]
69mod tests {
70 use std::sync::atomic::{AtomicUsize, Ordering};
71
72 #[test]
73 fn test_throttle_runs_once_initially() {
74 static COUNTER: AtomicUsize = AtomicUsize::new(0);
75
76 throttle!(std::time::Duration::from_secs(10), || {
77 COUNTER.fetch_add(1, Ordering::SeqCst);
78 });
79
80 assert_eq!(COUNTER.load(Ordering::SeqCst), 1);
81 }
82}