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