1use std::collections::HashMap;
2use std::future::Future;
3use std::pin::Pin;
4use std::sync::Arc;
5use std::sync::atomic::{AtomicU64, Ordering};
6use std::task::{Context, Poll, Waker};
7use std::thread::JoinHandle;
8use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
9
10use crate::error::{DbError, DbResult};
11use crate::shutdown::ShutdownSignal;
12use crate::sync::{Condvar, Mutex, cv_wait_timeout, lock};
13
14use super::{LIVE_CLASS, Queue, QueueHandle, QueueKey, QueueSpec};
15
16const WORKER_IDLE_PARK: Duration = Duration::from_secs(60);
21
22#[cfg(all(debug_assertions, feature = "queue-test-support"))]
29#[doc(hidden)]
30pub mod test_support {
31 use std::sync::{Arc, Barrier, LazyLock, Mutex};
32
33 type ParkPause = (Arc<Barrier>, Arc<Barrier>);
35
36 static PARK_PAUSE: LazyLock<Mutex<Option<ParkPause>>> = LazyLock::new(|| Mutex::new(None));
37
38 pub fn pause_wake_worker_before_park() -> ParkPause {
40 let pause = (Arc::new(Barrier::new(2)), Arc::new(Barrier::new(2)));
41 *PARK_PAUSE.lock().expect("queue wake pause lock") = Some(pause.clone());
42 pause
43 }
44
45 pub fn disarm_wake_worker_pause() {
46 *PARK_PAUSE.lock().expect("queue wake pause lock") = None;
47 }
48
49 pub(crate) fn wait_before_park() {
50 let pause = PARK_PAUSE
51 .lock()
52 .expect("queue wake pause lock")
53 .as_ref()
54 .cloned();
55 if let Some((arrived, release)) = pause {
56 arrived.wait();
57 release.wait();
58 }
59 }
60}
61
62pub(crate) trait QueueHeaderRow {
63 fn lease_deadline_ms(&self) -> u64;
64}
65
66#[doc(hidden)]
68pub struct QueueScan {
69 pub(crate) due: bool,
70 pub(crate) delay: Option<Duration>,
71}
72
73impl QueueScan {
74 pub(crate) fn rows<I, R>(rows: I, wakeup_recheck: Duration) -> DbResult<Self>
75 where
76 I: IntoIterator<Item = (QueueKey, R)>,
77 R: QueueHeaderRow,
78 {
79 Self::rows_at(rows, wakeup_recheck, now_ms()?)
80 }
81
82 pub(crate) fn rows_at<I, R>(rows: I, wakeup_recheck: Duration, now_ms: u64) -> DbResult<Self>
83 where
84 I: IntoIterator<Item = (QueueKey, R)>,
85 R: QueueHeaderRow,
86 {
87 let mut next = None;
88 for (key, row) in rows {
89 if key.class() != LIVE_CLASS {
90 break;
91 }
92 if key.visible_at_ms() > now_ms {
93 next = min_target(next, key.visible_at_ms());
94 break;
95 }
96 let deadline = row.lease_deadline_ms();
97 if deadline > now_ms {
98 next = min_target(next, deadline);
99 continue;
100 }
101 return Ok(Self {
102 due: true,
103 delay: Some(Duration::ZERO),
104 });
105 }
106 Ok(Self {
107 due: false,
108 delay: next.map(|target| {
109 Duration::from_millis(target.saturating_sub(now_ms)).min(wakeup_recheck)
110 }),
111 })
112 }
113}
114
115fn min_target(current: Option<u64>, candidate: u64) -> Option<u64> {
116 Some(current.map_or(candidate, |current| current.min(candidate)))
117}
118
119fn now_ms() -> DbResult<u64> {
120 let millis = SystemTime::now()
121 .duration_since(UNIX_EPOCH)
122 .map_err(|_| DbError::Client("queue time is before unix epoch"))?
123 .as_millis();
124 u64::try_from(millis).map_err(|_| DbError::Client("queue time exceeds u64 milliseconds"))
125}
126
127#[doc(hidden)]
128pub struct QueueWait {
129 state: Mutex<WaitState>,
130 changed: Condvar,
131 pub(crate) service: Arc<QueueWakeService>,
132 recheck: Duration,
133}
134
135struct WaitState {
136 generation: u64,
137 blockers: HashMap<u64, u64>,
138 next_blocker: u64,
139 registrations: usize,
140}
141
142enum RegisterResult {
143 Registered(u64),
144 Changed,
145 Shutdown,
146}
147
148impl QueueWait {
149 pub(crate) fn new(service: Arc<QueueWakeService>, recheck: Duration) -> Arc<Self> {
150 let wait = Arc::new(Self {
151 state: Mutex::new(WaitState {
152 generation: 0,
153 blockers: HashMap::new(),
154 next_blocker: 1,
155 registrations: 0,
156 }),
157 changed: Condvar::new(),
158 service,
159 recheck,
160 });
161 let weak = Arc::downgrade(&wait);
166 wait.service.shutdown.listen(Arc::new(move || {
167 if let Some(wait) = weak.upgrade() {
168 wait.notify_all_blockers();
169 }
170 }));
171 wait
172 }
173
174 pub(crate) fn notify_visible_at(&self, visible_at_ms: u64) {
178 {
179 let mut state = lock(&self.state);
180 state.generation = state.generation.wrapping_add(1);
181 if visible_at_ms < blocker_threshold(&state) {
182 self.changed.notify_all();
183 }
184 }
185 self.service.wake_queue(self, visible_at_ms);
186 }
187
188 fn notify_all_blockers(&self) {
192 let mut state = lock(&self.state);
193 state.generation = state.generation.wrapping_add(1);
194 self.changed.notify_all();
195 }
196
197 fn generation(&self) -> u64 {
198 lock(&self.state).generation
199 }
200
201 fn wait_for_change(&self, delay: Duration, announced_until_ms: u64, generation: u64) -> bool {
202 let mut state = lock(&self.state);
203 if state.generation != generation {
204 return false;
205 }
206 let id = state.next_blocker;
207 state.next_blocker = state.next_blocker.wrapping_add(1);
208 state.blockers.insert(id, announced_until_ms);
209 let mut state = cv_wait_timeout(&self.changed, &self.state, state, delay);
210 state.blockers.remove(&id);
211 true
212 }
213
214 fn register(
215 &self,
216 id: Option<u64>,
217 waker: Waker,
218 delay: Duration,
219 generation: u64,
220 ) -> RegisterResult {
221 let mut state = lock(&self.state);
222 if state.generation != generation {
223 return RegisterResult::Changed;
224 }
225 if self.service.shutdown.is_shutdown() {
226 return RegisterResult::Shutdown;
227 }
228 let is_new = id.is_none();
229 let announced_until_ms = now_ms()
230 .unwrap_or(u64::MAX)
231 .saturating_add(u64::try_from(delay.as_millis()).unwrap_or(u64::MAX));
232 let Some(id) = self
233 .service
234 .register_locked(id, waker, delay, announced_until_ms, self)
235 else {
236 return RegisterResult::Shutdown;
237 };
238 if is_new {
239 state.registrations += 1;
240 }
241 RegisterResult::Registered(id)
242 }
243
244 fn deregistered(&self) {
245 let mut state = lock(&self.state);
246 state.registrations = state.registrations.saturating_sub(1);
247 }
248
249 #[cfg(all(debug_assertions, feature = "queue-test-support"))]
250 pub(crate) fn registration_count(&self) -> usize {
251 lock(&self.state).registrations
252 }
253}
254
255fn blocker_threshold(state: &WaitState) -> u64 {
264 state.blockers.values().copied().max().unwrap_or(u64::MAX)
265}
266
267pub(crate) struct QueueWakeService {
268 state: Mutex<WakeState>,
269 changed: Condvar,
270 pub(crate) shutdown: ShutdownSignal,
271 worker: Mutex<Option<JoinHandle<()>>>,
272 next_id: AtomicU64,
273}
274
275struct WakeState {
276 registrations: HashMap<u64, Registration>,
277}
278
279struct Registration {
280 queue: usize,
281 announced_until_ms: u64,
282 deadline: Instant,
283 waker: Waker,
284}
285
286impl QueueWakeService {
287 pub(crate) fn new(shutdown: ShutdownSignal) -> Arc<Self> {
288 let service = Arc::new(Self {
289 state: Mutex::new(WakeState {
290 registrations: HashMap::new(),
291 }),
292 changed: Condvar::new(),
293 shutdown: shutdown.clone(),
294 worker: Mutex::new(None),
295 next_id: AtomicU64::new(1),
296 });
297 let weak = Arc::downgrade(&service);
298 shutdown.listen(Arc::new(move || {
299 if let Some(service) = weak.upgrade() {
300 service.shutdown_wake();
301 }
302 }));
303 service
304 }
305
306 fn register_locked(
307 &self,
308 id: Option<u64>,
309 waker: Waker,
310 delay: Duration,
311 announced_until_ms: u64,
312 queue: &QueueWait,
313 ) -> Option<u64> {
314 let id = id.unwrap_or_else(|| self.next_id.fetch_add(1, Ordering::Relaxed));
315 let mut state = lock(&self.state);
316 if self.shutdown.is_shutdown() {
317 return None;
318 }
319 state.registrations.insert(
320 id,
321 Registration {
322 queue: queue as *const QueueWait as usize,
323 announced_until_ms,
324 deadline: Instant::now() + delay,
325 waker,
326 },
327 );
328 self.changed.notify_all();
329 Some(id)
330 }
331
332 fn deregister(&self, id: u64) {
333 lock(&self.state).registrations.remove(&id);
334 self.changed.notify_all();
335 }
336
337 fn wake_queue(&self, queue: &QueueWait, visible_at_ms: u64) {
338 let queue = queue as *const QueueWait as usize;
339 let wakers = {
340 let mut state = lock(&self.state);
341 let ids: Vec<_> = state
342 .registrations
343 .iter()
344 .filter_map(|(id, registration)| {
345 (registration.queue == queue && visible_at_ms < registration.announced_until_ms)
346 .then_some(*id)
347 })
348 .collect();
349 ids.into_iter()
350 .filter_map(|id| {
351 state
352 .registrations
353 .remove(&id)
354 .map(|registration| registration.waker)
355 })
356 .collect::<Vec<_>>()
357 };
358 for waker in wakers {
359 waker.wake();
360 }
361 }
362
363 fn shutdown_wake(&self) {
364 let wakers = {
365 let mut state = lock(&self.state);
366 state
367 .registrations
368 .drain()
369 .map(|(_, registration)| registration.waker)
370 .collect::<Vec<_>>()
371 };
372 self.changed.notify_all();
373 for waker in wakers {
374 waker.wake();
375 }
376 }
377
378 fn start(self: &Arc<Self>) {
379 let mut worker = lock(&self.worker);
380 if worker.is_some() {
381 return;
382 }
383 let service = Arc::clone(self);
384 *worker = Some(std::thread::spawn(move || service.run()));
385 }
386
387 fn run(self: Arc<Self>) {
388 loop {
389 if self.shutdown.is_shutdown() {
390 self.shutdown_wake();
391 return;
392 }
393 #[cfg(all(debug_assertions, feature = "queue-test-support"))]
394 test_support::wait_before_park();
395 let wakers = {
396 let mut state = lock(&self.state);
397 let now = Instant::now();
398 let ids: Vec<_> = state
399 .registrations
400 .iter()
401 .filter_map(|(id, registration)| (registration.deadline <= now).then_some(*id))
402 .collect();
403 if !ids.is_empty() {
404 ids.into_iter()
405 .filter_map(|id| {
406 state
407 .registrations
408 .remove(&id)
409 .map(|registration| registration.waker)
410 })
411 .collect()
412 } else {
413 let delay = state
414 .registrations
415 .values()
416 .map(|registration| registration.deadline)
417 .min()
418 .map_or(WORKER_IDLE_PARK, |deadline| {
419 deadline.saturating_duration_since(now)
420 });
421 if self.shutdown.is_shutdown() {
428 drop(state);
429 self.shutdown_wake();
430 return;
431 }
432 drop(cv_wait_timeout(&self.changed, &self.state, state, delay));
433 Vec::new()
434 }
435 };
436 for waker in wakers {
437 waker.wake();
438 }
439 }
440 }
441
442 pub(crate) fn join(&self) {
443 self.shutdown_wake();
444 if let Some(worker) = lock(&self.worker).take() {
445 let _ = worker.join();
446 }
447 }
448}
449
450pub struct QueueDue<'a, N: QueueSpec>
452where
453 N::Mode: QueueHandle<N>,
454{
455 queue: &'a Queue<N>,
456 registration: Option<u64>,
457}
458
459impl<'a, N> QueueDue<'a, N>
460where
461 N: QueueSpec,
462 N::Mode: QueueHandle<N>,
463{
464 pub(crate) fn new(queue: &'a Queue<N>) -> Self {
465 Self {
466 queue,
467 registration: None,
468 }
469 }
470
471 fn unregister(&mut self) {
472 if let Some(id) = self.registration.take() {
473 let wait = <N::Mode as QueueHandle<N>>::wait(self.queue);
474 wait.service.deregister(id);
475 wait.deregistered();
476 }
477 }
478}
479
480impl<N> Future for QueueDue<'_, N>
481where
482 N: QueueSpec,
483 N::Mode: QueueHandle<N>,
484{
485 type Output = DbResult<()>;
486
487 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
488 loop {
489 let wait = <N::Mode as QueueHandle<N>>::wait(self.queue);
490 let generation = wait.generation();
491 let scan = match <N::Mode as QueueHandle<N>>::scan_due(self.queue) {
492 Ok(scan) => scan,
493 Err(err) => {
494 self.unregister();
495 return Poll::Ready(Err(err));
496 }
497 };
498 if wait.service.shutdown.is_shutdown() {
499 self.unregister();
500 return Poll::Ready(Err(DbError::Client("queue wait service is shut down")));
501 }
502 if scan.due {
503 self.unregister();
504 return Poll::Ready(Ok(()));
505 }
506 match wait.register(
507 self.registration,
508 cx.waker().clone(),
509 scan.delay.unwrap_or(wait.recheck),
510 generation,
511 ) {
512 RegisterResult::Registered(id) => {
513 self.registration = Some(id);
514 wait.service.start();
515 return Poll::Pending;
516 }
517 RegisterResult::Changed => continue,
518 RegisterResult::Shutdown => {
519 self.unregister();
520 return Poll::Ready(Err(DbError::Client("queue wait service is shut down")));
521 }
522 }
523 }
524 }
525}
526
527impl<N> Drop for QueueDue<'_, N>
528where
529 N: QueueSpec,
530 N::Mode: QueueHandle<N>,
531{
532 fn drop(&mut self) {
533 self.unregister();
534 }
535}
536
537pub(crate) fn wait_due_timeout<N>(queue: &Queue<N>, timeout: Duration) -> DbResult<bool>
538where
539 N: QueueSpec,
540 N::Mode: QueueHandle<N>,
541{
542 let deadline = Instant::now() + timeout;
543 loop {
544 let wait = <N::Mode as QueueHandle<N>>::wait(queue);
545 let generation = wait.generation();
546 let scan = <N::Mode as QueueHandle<N>>::scan_due(queue)?;
547 if scan.due {
548 return Ok(true);
549 }
550 if wait.service.shutdown.is_shutdown() {
554 return Err(DbError::Client("queue wait service is shut down"));
555 }
556 let remaining = deadline.saturating_duration_since(Instant::now());
557 if remaining.is_zero() {
558 return Ok(false);
559 }
560 let delay = scan
561 .delay
562 .unwrap_or(wait.recheck)
563 .min(wait.recheck)
564 .min(remaining);
565 let announced_until_ms =
566 now_ms()?.saturating_add(u64::try_from(delay.as_millis()).unwrap_or(u64::MAX));
567 let _ = wait.wait_for_change(delay, announced_until_ms, generation);
568 }
569}
570
571#[cfg(test)]
572mod tests {
573 use super::*;
574
575 #[derive(Clone, Copy)]
576 struct Header(u64);
577
578 impl QueueHeaderRow for Header {
579 fn lease_deadline_ms(&self) -> u64 {
580 self.0
581 }
582 }
583
584 #[test]
585 fn backward_clock_jump_is_capped_by_recheck_from_a_fresh_scan() {
586 let rows = [(QueueKey::live(110, 1), Header(0))];
587 let recheck = Duration::from_millis(5);
588 let before_jump = QueueScan::rows_at(rows, recheck, 100).unwrap();
589 let after_jump = QueueScan::rows_at(rows, recheck, 90).unwrap();
590
591 assert_eq!(before_jump.delay, Some(Duration::from_millis(5)));
592 assert_eq!(after_jump.delay, Some(Duration::from_millis(5)));
593 }
594}