use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use kglite::api::session::CancelToken;
pub trait InflightCancel {
fn cancel_inflight(&self, session_id: &str);
}
#[derive(Default)]
pub struct InflightQueries {
tokens: Arc<Mutex<HashMap<String, CancelToken>>>,
}
impl InflightQueries {
pub fn begin(&self, session_id: &str) -> InflightGuard {
let token = CancelToken::new();
self.tokens
.lock()
.unwrap_or_else(|p| p.into_inner())
.insert(session_id.to_string(), token.clone());
InflightGuard {
token,
session_id: session_id.to_string(),
tokens: Arc::clone(&self.tokens),
}
}
pub fn cancel(&self, session_id: &str) {
let token = self
.tokens
.lock()
.unwrap_or_else(|p| p.into_inner())
.get(session_id)
.cloned();
if let Some(token) = token {
token.cancel();
}
}
}
pub struct InflightGuard {
token: CancelToken,
session_id: String,
tokens: Arc<Mutex<HashMap<String, CancelToken>>>,
}
impl InflightGuard {
pub fn token(&self) -> &CancelToken {
&self.token
}
}
impl Drop for InflightGuard {
fn drop(&mut self) {
self.tokens
.lock()
.unwrap_or_else(|p| p.into_inner())
.remove(&self.session_id);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cancel_reaches_the_running_query_only() {
let q = InflightQueries::default();
let a = q.begin("s1");
let b = q.begin("s2");
q.cancel("s1");
assert!(a.token().is_cancelled());
assert!(!b.token().is_cancelled());
drop(a);
q.cancel("s1");
q.cancel("nobody");
assert!(!b.token().is_cancelled());
}
}