1use std::sync::atomic::{AtomicBool, Ordering};
16use std::sync::{Arc, Mutex};
17
18use common_base::cancellation::CancellationHandle;
19
20pub mod remote_job_scheduler;
21pub mod scheduler;
22
23#[derive(Debug, Clone)]
25pub(crate) struct CancellableTaskState {
26 cancel_handle: Arc<CancellationHandle>,
27 commit_started: Arc<Mutex<bool>>,
28 started: Arc<AtomicBool>,
29}
30
31impl CancellableTaskState {
32 pub(crate) fn new() -> Self {
33 Self {
34 cancel_handle: Arc::new(CancellationHandle::default()),
35 commit_started: Arc::new(Mutex::new(false)),
36 started: Arc::new(AtomicBool::new(false)),
37 }
38 }
39
40 pub(crate) fn mark_started(&self) {
42 self.started.store(true, Ordering::Relaxed);
43 }
44
45 pub(crate) fn started(&self) -> bool {
47 self.started.load(Ordering::Relaxed)
48 }
49
50 pub(crate) fn cancel_handle(&self) -> Arc<CancellationHandle> {
51 self.cancel_handle.clone()
52 }
53
54 pub(crate) fn is_cancelled(&self) -> bool {
55 self.cancel_handle.is_cancelled()
56 }
57
58 pub(crate) fn commit_started(&self) -> bool {
60 *self.commit_started.lock().unwrap()
61 }
62
63 pub(crate) fn mark_commit_started(&self) -> bool {
67 let mut commit_started = self.commit_started.lock().unwrap();
68 if self.cancel_handle.is_cancelled() {
69 return false;
70 }
71 *commit_started = true;
72 true
73 }
74
75 pub(crate) fn request_cancel(&self) -> RequestCancelResult {
76 let commit_started = self.commit_started.lock().unwrap();
78 if *commit_started {
79 return RequestCancelResult::TooLateToCancel;
80 }
81 if self.cancel_handle.is_cancelled() {
82 return RequestCancelResult::AlreadyCancelling;
83 }
84
85 self.cancel_handle.cancel();
86 RequestCancelResult::CancelIssued
87 }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91pub(crate) enum RequestCancelResult {
92 CancelIssued,
93 AlreadyCancelling,
94 TooLateToCancel,
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn test_cancellable_task_state_transitions() {
103 let state = CancellableTaskState::new();
104 assert_eq!(RequestCancelResult::CancelIssued, state.request_cancel());
105 assert!(state.is_cancelled());
106 assert_eq!(
107 RequestCancelResult::AlreadyCancelling,
108 state.request_cancel()
109 );
110 assert!(!state.mark_commit_started());
111
112 let state = CancellableTaskState::new();
113 assert!(state.mark_commit_started());
114 assert_eq!(RequestCancelResult::TooLateToCancel, state.request_cancel());
115 }
116}