1use crate::FilteredLoadBalancer;
2use crate::LoadBalancer;
3use std::sync::atomic::Ordering::{Acquire, Release};
4use std::{
5 future::Future,
6 sync::{Arc, atomic::AtomicU64},
7 time::{Duration, Instant},
8};
9use tokio::{
10 spawn,
11 sync::{Mutex, RwLock},
12 task::{JoinHandle, yield_now},
13 time::sleep,
14};
15
16pub struct Entry<T>
18where
19 T: Send + Sync + Clone + 'static,
20{
21 pub max_count: u64,
22 pub count: AtomicU64,
23 pub value: T,
24}
25
26impl<T> Clone for Entry<T>
27where
28 T: Send + Sync + Clone + 'static,
29{
30 fn clone(&self) -> Self {
31 Self {
32 max_count: self.max_count.clone(),
33 count: self.count.load(Acquire).into(),
34 value: self.value.clone(),
35 }
36 }
37}
38
39pub struct Inner<T>
40where
41 T: Send + Sync + Clone + 'static,
42{
43 pub entries: RwLock<Vec<Entry<T>>>,
44 pub timer: Mutex<Option<JoinHandle<()>>>,
45 pub interval: RwLock<Duration>,
46 pub next_reset: RwLock<Instant>,
47}
48
49#[derive(Clone)]
54pub struct Window<T>
55where
56 T: Send + Sync + Clone + 'static,
57{
58 inner: Arc<Inner<T>>,
59}
60
61impl<T> Window<T>
62where
63 T: Send + Sync + Clone + 'static,
64{
65 pub fn new(entries: Vec<(u64, T)>) -> Self {
69 Self::new_interval(entries, Duration::from_secs(1))
70 }
71
72 pub fn new_interval(entries: Vec<(u64, T)>, interval: Duration) -> Self {
74 Self {
75 inner: Arc::new(Inner {
76 entries: entries
77 .into_iter()
78 .map(|(max_count, value)| Entry {
79 max_count,
80 value,
81 count: 0.into(),
82 })
83 .collect::<Vec<_>>()
84 .into(),
85 timer: Mutex::new(None),
86 interval: interval.into(),
87 next_reset: RwLock::new(Instant::now() + interval),
88 }),
89 }
90 }
91
92 pub async fn update<F, R, N>(&self, handler: F) -> anyhow::Result<N>
94 where
95 F: Fn(Arc<Inner<T>>) -> R,
96 R: Future<Output = anyhow::Result<N>>,
97 {
98 handler(self.inner.clone()).await
99 }
100
101 pub async fn update_timer<F, R>(
107 &self,
108 handler: F,
109 interval: Duration,
110 ) -> anyhow::Result<JoinHandle<()>>
111 where
112 F: Fn(Arc<Inner<T>>) -> R + Send + Sync + 'static,
113 R: Future<Output = anyhow::Result<()>> + Send,
114 {
115 handler(self.inner.clone()).await?;
116
117 let inner = self.inner.clone();
118
119 Ok(spawn(async move {
120 loop {
121 sleep(interval).await;
122 let _ = handler(inner.clone()).await;
123 }
124 }))
125 }
126}
127
128impl<T> FilteredLoadBalancer<T> for Window<T>
129where
130 T: Send + Sync + Clone + 'static,
131{
132 async fn alloc_filter(
133 &self,
134 mut predicate: impl FnMut((usize, &T)) -> bool + Send,
135 ) -> (usize, T) {
136 loop {
137 if let Some(result) = self.try_alloc_filter(&mut predicate) {
138 return result;
139 }
140
141 let now = Instant::now();
142
143 let next = *self.inner.next_reset.read().await;
144
145 let remaining = if now < next {
146 next - now
147 } else {
148 Duration::ZERO
149 };
150
151 if remaining > Duration::ZERO {
152 sleep(remaining).await;
153 } else {
154 yield_now().await;
155 }
156 }
157 }
158
159 fn try_alloc_filter(
160 &self,
161 mut predicate: impl FnMut((usize, &T)) -> bool,
162 ) -> Option<(usize, T)> {
163 if let Ok(mut timer_guard) = self.inner.timer.try_lock() {
164 if timer_guard.is_none() {
165 let this = self.inner.clone();
166
167 *timer_guard = Some(spawn(async move {
168 let mut interval = *this.interval.read().await;
169
170 *this.next_reset.write().await = Instant::now() + interval;
171
172 loop {
173 sleep(match this.interval.try_read() {
174 Ok(v) => {
175 interval = *v;
176 interval
177 }
178 Err(_) => interval,
179 })
180 .await;
181
182 let now = Instant::now();
183
184 let entries = this.entries.read().await;
185
186 for entry in entries.iter() {
187 entry.count.store(0, Release);
188 }
189
190 *this.next_reset.write().await = now + interval;
191 }
192 }));
193 }
194 }
195
196 if let Ok(entries) = self.inner.entries.try_read() {
197 for (i, entry) in entries.iter().enumerate() {
198 if !predicate((i, &entry.value)) {
199 continue;
200 }
201
202 let count = entry.count.load(Acquire);
203
204 if entry.max_count == 0
205 || count < entry.max_count
206 && entry
207 .count
208 .compare_exchange(count, count + 1, Release, Acquire)
209 .is_ok()
210 {
211 return Some((i, entry.value.clone()));
212 }
213 }
214 }
215
216 None
217 }
218}
219
220impl<T> LoadBalancer<T> for Window<T>
221where
222 T: Send + Sync + Clone + 'static,
223{
224 fn alloc(&self) -> impl Future<Output = T> + Send {
225 async move { self.alloc_filter(|_| true).await.1 }
226 }
227
228 fn try_alloc(&self) -> Option<T> {
229 self.try_alloc_filter(|_| true).map(|v| v.1)
230 }
231}