tds_driver/client/cancel.rs
1use futures_util::task::AtomicWaker;
2use std::sync::atomic::{AtomicBool, Ordering};
3use std::sync::Arc;
4use std::task::Context;
5
6/// Cancels the request in flight on a [`Client`]'s connection from outside the
7/// future awaiting it: another task, or a `select!` branch beside it.
8///
9/// Unlike [`Client::cancel_query`], which can only run once the response
10/// stream has been dropped, this also stops a request that is still being sent
11/// or that the server hasn't answered yet, such as a statement still sorting,
12/// aggregating or waiting on a lock.
13///
14/// [`Client`]: crate::Client
15/// [`Client::cancel_query`]: crate::Client::cancel_query
16#[derive(Clone, Debug, Default)]
17pub struct CancelHandle(Arc<Signal>);
18
19#[derive(Debug, Default)]
20struct Signal {
21 requested: AtomicBool,
22 waker: AtomicWaker,
23}
24
25impl CancelHandle {
26 /// Asks the server to stop the request in flight on the connection.
27 ///
28 /// The Attention goes out the next time the response is read, so keep
29 /// polling the future awaiting it. It then finishes early, with whatever
30 /// the server sent before it stopped, or with server error 3980 if the
31 /// request was aborted before it ran.
32 ///
33 /// A cancel is forgotten if it comes before a request is sent, so it never
34 /// stops a later one, or if the response is dropped before the Attention
35 /// goes out; call [`Client::cancel_query`] then instead.
36 ///
37 /// [`Client::cancel_query`]: crate::Client::cancel_query
38 pub fn cancel(&self) {
39 self.0.requested.store(true, Ordering::Release);
40 self.0.waker.wake();
41 }
42
43 /// Whether a cancel is pending. Registers `cx` to be woken by the next one.
44 pub(crate) fn poll_requested(&self, cx: &mut Context<'_>) -> bool {
45 self.0.waker.register(cx.waker());
46 self.0.requested.load(Ordering::Acquire)
47 }
48
49 /// Forgets a pending cancel.
50 pub(crate) fn clear(&self) {
51 self.0.requested.store(false, Ordering::Release);
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58 use std::sync::atomic::AtomicUsize;
59 use std::task::{Wake, Waker};
60
61 struct CountWakes(AtomicUsize);
62
63 impl Wake for CountWakes {
64 fn wake(self: Arc<Self>) {
65 self.0.fetch_add(1, Ordering::SeqCst);
66 }
67 }
68
69 #[test]
70 fn cancel_wakes_the_reader_and_stays_pending_until_cleared() {
71 let wakes = Arc::new(CountWakes(AtomicUsize::new(0)));
72 let waker = Waker::from(Arc::clone(&wakes));
73 let mut cx = Context::from_waker(&waker);
74 let handle = CancelHandle::default();
75
76 assert!(!handle.poll_requested(&mut cx));
77 handle.clone().cancel();
78 assert_eq!(1, wakes.0.load(Ordering::SeqCst));
79 assert!(handle.poll_requested(&mut cx));
80
81 handle.clear();
82 assert!(!handle.poll_requested(&mut cx));
83 }
84}