use std::sync::Arc;
use std::sync::atomic::{AtomicU32, Ordering};
use alloy::primitives::B256;
use dashmap::DashMap;
#[derive(Debug, Default)]
pub struct ShedState {
node_active: AtomicU32,
per_client: DashMap<B256, Arc<AtomicU32>>,
}
impl ShedState {
#[must_use]
pub fn new() -> Arc<Self> {
Arc::new(Self::default())
}
#[must_use]
pub fn counts(&self, client: B256) -> (u32, u32) {
let node = self.node_active.load(Ordering::Relaxed);
let per = self
.per_client
.get(&client)
.map_or(0, |c| c.load(Ordering::Relaxed));
(node, per)
}
#[must_use]
pub fn node_in_flight(&self) -> u32 {
self.node_active.load(Ordering::Relaxed)
}
#[must_use]
pub fn acquire(self: &Arc<Self>, client: B256) -> ShedSlot {
self.node_active.fetch_add(1, Ordering::Relaxed);
let counter = self
.per_client
.entry(client)
.or_insert_with(|| Arc::new(AtomicU32::new(0)))
.clone();
counter.fetch_add(1, Ordering::Relaxed);
ShedSlot {
state: Arc::clone(self),
client,
counter,
}
}
}
#[derive(Debug)]
pub struct ShedSlot {
state: Arc<ShedState>,
client: B256,
counter: Arc<AtomicU32>,
}
impl Drop for ShedSlot {
fn drop(&mut self) {
self.state
.node_active
.update(Ordering::Relaxed, Ordering::Relaxed, |n| {
n.saturating_sub(1)
});
self.counter
.update(Ordering::Relaxed, Ordering::Relaxed, |n| {
n.saturating_sub(1)
});
self.state
.per_client
.remove_if(&self.client, |_, c| c.load(Ordering::Relaxed) == 0);
}
}
#[cfg(test)]
mod tests;