use crate::spec::shutdown::TreeShutdownPolicy;
use serde::{Deserialize, Serialize};
use std::sync::atomic::{AtomicU32, Ordering};
use std::time::Duration;
const DEFAULT_ORPHAN_THRESHOLD_WORKER_RATIO: f64 = 0.25;
static NUM_WORKER_THREADS: AtomicU32 = AtomicU32::new(0);
fn detect_num_worker_threads() -> u32 {
NUM_WORKER_THREADS
.load(Ordering::Relaxed)
.max(std::thread::available_parallelism().map_or(1, |v| v.get() as u32))
}
pub fn compute_orphan_threshold_from_worker_count(worker_count: u32) -> u32 {
(worker_count as f64 * DEFAULT_ORPHAN_THRESHOLD_WORKER_RATIO)
.ceil()
.max(1.0) as u32
}
impl TreeShutdownPolicy {
pub fn effective_global_deadline(&self) -> Duration {
self.budget.graceful_timeout + self.budget.abort_wait + self.force_kill_margin
}
pub fn effective_max_orphan_threshold(&self) -> u32 {
if self.max_orphan_threshold > 0 {
self.max_orphan_threshold
} else {
compute_orphan_threshold_from_worker_count(detect_num_worker_threads())
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ShutdownPhase {
Idle,
RequestStop,
GracefulDrain,
AbortStragglers,
Reconcile,
Completed,
}
impl ShutdownPhase {
pub fn next(self) -> Option<Self> {
match self {
Self::Idle => Some(Self::RequestStop),
Self::RequestStop => Some(Self::GracefulDrain),
Self::GracefulDrain => Some(Self::AbortStragglers),
Self::AbortStragglers => Some(Self::Reconcile),
Self::Reconcile => Some(Self::Completed),
Self::Completed => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ShutdownCause {
pub requested_by: String,
pub reason: String,
}
impl ShutdownCause {
pub fn new(requested_by: impl Into<String>, reason: impl Into<String>) -> Self {
Self {
requested_by: requested_by.into(),
reason: reason.into(),
}
}
}