use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use super::DistOutbound;
pub(super) struct LaneResidency {
charged: AtomicUsize,
budget: usize,
}
impl LaneResidency {
pub(super) const fn new(budget: usize) -> Self {
Self {
charged: AtomicUsize::new(0),
budget,
}
}
pub(super) fn try_charge(self: &Arc<Self>, bytes: usize) -> Option<ResidencyCharge> {
let mut current = self.charged.load(Ordering::Relaxed);
loop {
let next = current.saturating_add(bytes);
if next > self.budget {
return None;
}
match self.charged.compare_exchange_weak(
current,
next,
Ordering::AcqRel,
Ordering::Relaxed,
) {
Ok(_) => {
return Some(ResidencyCharge {
residency: Arc::clone(self),
bytes,
});
}
Err(observed) => current = observed,
}
}
}
pub(super) fn resident_bytes(&self) -> usize {
self.charged.load(Ordering::Acquire)
}
}
pub(super) struct ResidencyCharge {
residency: Arc<LaneResidency>,
bytes: usize,
}
impl Drop for ResidencyCharge {
fn drop(&mut self) {
self.residency
.charged
.fetch_sub(self.bytes, Ordering::AcqRel);
}
}
pub(super) struct ChargedOutbound {
pub(super) item: DistOutbound,
pub(super) charge: ResidencyCharge,
}