use crate::id::types::{ChildId, ChildStartCount, Generation};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AdmissionConflict {
pub child_id: ChildId,
pub active_generation: Generation,
pub active_attempt: ChildStartCount,
pub conflicting_request: String,
}
impl AdmissionConflict {
pub fn new(
child_id: ChildId,
active_generation: Generation,
active_attempt: ChildStartCount,
conflicting_request: impl Into<String>,
) -> Self {
Self {
child_id,
active_generation,
active_attempt,
conflicting_request: conflicting_request.into(),
}
}
}
impl Display for AdmissionConflict {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
write!(
formatter,
"child {} already has active attempt gen{}-attempt{}; conflicting request: {}",
self.child_id,
self.active_generation.value,
self.active_attempt.value,
self.conflicting_request,
)
}
}
impl std::error::Error for AdmissionConflict {}
#[derive(Debug, Default)]
pub struct AdmissionSet {
admitted: HashSet<ChildId>,
}
impl AdmissionSet {
pub fn new() -> Self {
Self::default()
}
pub fn try_admit(
&mut self,
child_id: ChildId,
active_generation: Generation,
active_attempt: ChildStartCount,
) -> Result<(), AdmissionConflict> {
if self.admitted.contains(&child_id) {
return Err(AdmissionConflict::new(
child_id,
active_generation,
active_attempt,
"restart or activate request conflicts with existing active attempt",
));
}
self.admitted.insert(child_id);
Ok(())
}
pub fn try_admit_or_idempotent(
&mut self,
child_id: ChildId,
request_generation: Generation,
request_attempt: ChildStartCount,
active_generation: Generation,
active_attempt: ChildStartCount,
) -> Result<(), AdmissionConflict> {
if self.admitted.contains(&child_id) {
if request_generation == active_generation && request_attempt == active_attempt {
return Ok(());
}
return Err(AdmissionConflict::new(
child_id,
active_generation,
active_attempt,
"restart or activate request conflicts with existing active attempt",
));
}
self.admitted.insert(child_id);
Ok(())
}
pub fn release(&mut self, child_id: &ChildId) {
self.admitted.remove(child_id);
}
pub fn is_admitted(&self, child_id: &ChildId) -> bool {
self.admitted.contains(child_id)
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.admitted.len()
}
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.admitted.is_empty()
}
}