use std::collections::HashSet;
use std::sync::{Arc, Mutex};
use nodedb_types::id::RequestId;
use nodedb_types::result::QueryResult;
use crate::error::LiteError;
#[derive(Clone, Default)]
pub struct CancellationRegistry {
cancelled: Arc<Mutex<HashSet<u64>>>,
}
impl CancellationRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn cancel(&self, rid: RequestId) -> Result<(), LiteError> {
let mut set = self.cancelled.lock().map_err(|_| LiteError::LockPoisoned)?;
set.insert(rid.as_u64());
Ok(())
}
pub fn is_cancelled(&self, rid: RequestId) -> bool {
self.cancelled
.lock()
.map(|s| s.contains(&rid.as_u64()))
.unwrap_or(false)
}
pub fn clear(&self, rid: RequestId) {
if let Ok(mut s) = self.cancelled.lock() {
s.remove(&rid.as_u64());
}
}
}
pub fn handle_cancel(
registry: &CancellationRegistry,
target_request_id: RequestId,
) -> Result<QueryResult, LiteError> {
registry.cancel(target_request_id)?;
Ok(QueryResult::empty())
}
#[cfg(test)]
mod tests {
use super::*;
use nodedb_types::id::RequestId;
#[test]
fn cancel_marks_and_clears_request() {
let registry = CancellationRegistry::new();
let rid = RequestId::new(42);
assert!(!registry.is_cancelled(rid));
let result = handle_cancel(®istry, rid).unwrap();
assert_eq!(result.rows_affected, 0);
assert!(registry.is_cancelled(rid));
registry.clear(rid);
assert!(!registry.is_cancelled(rid));
}
#[test]
fn cancel_idempotent() {
let registry = CancellationRegistry::new();
let rid = RequestId::new(99);
handle_cancel(®istry, rid).unwrap();
handle_cancel(®istry, rid).unwrap();
assert!(registry.is_cancelled(rid));
}
}