use std::collections::BTreeMap;
use std::sync::Mutex;
use tracing::error;
#[derive(Debug)]
struct ParkedRow {
attempt: u32,
confirmed: bool,
woken_while_pending: bool,
}
#[derive(Debug, Default)]
pub(super) struct CapacityParkedRows {
rows: Mutex<BTreeMap<String, ParkedRow>>,
}
impl CapacityParkedRows {
pub(super) fn park_pending(&self, dispatch_key: &str, attempt: u32) {
let Ok(mut rows) = self.rows.lock() else {
error!(
dispatch_key,
"capacity-parked set is poisoned; this row waits for its durable fence instead \
of the next freed slot"
);
return;
};
rows.insert(
dispatch_key.to_owned(),
ParkedRow {
attempt,
confirmed: false,
woken_while_pending: false,
},
);
}
pub(super) fn abandon(&self, dispatch_key: &str) {
let Ok(mut rows) = self.rows.lock() else {
error!(
dispatch_key,
"capacity-parked set is poisoned; a row whose park failed stays remembered"
);
return;
};
rows.remove(dispatch_key);
}
pub(super) fn confirm(&self, dispatch_key: &str) -> bool {
let Ok(mut rows) = self.rows.lock() else {
error!(
dispatch_key,
"capacity-parked set is poisoned; this row waits for its durable fence instead \
of the next freed slot"
);
return false;
};
let Some(row) = rows.get_mut(dispatch_key) else {
return false;
};
row.confirmed = true;
if row.woken_while_pending {
rows.remove(dispatch_key);
return true;
}
false
}
pub(super) fn take_confirmed(&self) -> Vec<(String, u32)> {
let Ok(mut rows) = self.rows.lock() else {
error!(
"capacity-parked set is poisoned; rows wait for their durable fences instead of \
the freed slot"
);
return Vec::new();
};
let mut ready = Vec::new();
rows.retain(|dispatch_key, row| {
if row.confirmed {
ready.push((dispatch_key.clone(), row.attempt));
return false;
}
row.woken_while_pending = true;
true
});
ready
}
#[cfg(test)]
pub(super) fn is_pending(&self, dispatch_key: &str) -> bool {
self.rows
.lock()
.is_ok_and(|rows| rows.get(dispatch_key).is_some_and(|row| !row.confirmed))
}
#[cfg(test)]
pub(super) fn contains(&self, dispatch_key: &str) -> bool {
self.rows
.lock()
.is_ok_and(|rows| rows.contains_key(dispatch_key))
}
}