use std::{
collections::VecDeque,
num::NonZeroUsize,
sync::{
Arc, Mutex,
atomic::{AtomicU8, Ordering as AtomicOrdering},
},
};
use tokio::sync::Notify;
use super::error::DropCapacityError;
const CAPACITY_WAITING: u8 = 0;
const CAPACITY_GRANTED: u8 = 1;
const CAPACITY_CLOSED: u8 = 2;
const CAPACITY_TAKEN: u8 = 3;
const CAPACITY_CANCELED: u8 = 4;
struct CapacitySignal {
status: AtomicU8,
changed: Notify,
}
impl CapacitySignal {
fn waiting() -> Self {
Self {
status: AtomicU8::new(CAPACITY_WAITING),
changed: Notify::new(),
}
}
}
struct CapacityWaiter {
units: usize,
bypassed_units: usize,
signal: Arc<CapacitySignal>,
}
struct LimitedCapacityState {
available: usize,
effective_capacity: usize,
waiters: VecDeque<CapacityWaiter>,
}
enum CapacityMode {
Limited(LimitedCapacityState),
Unlimited,
}
struct CapacityState {
closed: bool,
mode: CapacityMode,
}
pub(super) struct CapacityBroker {
limit: Option<NonZeroUsize>,
state: Mutex<CapacityState>,
}
enum CapacityStart {
Ready(OwnershipPermit),
Waiting(CapacityRequest),
}
struct CapacityRequest {
broker: Arc<CapacityBroker>,
units: usize,
signal: Arc<CapacitySignal>,
active: bool,
}
impl CapacityRequest {
async fn wait(mut self) -> Result<OwnershipPermit, DropCapacityError> {
loop {
let changed = self.signal.changed.notified();
tokio::pin!(changed);
changed.as_mut().enable();
match self.signal.status.load(AtomicOrdering::Acquire) {
CAPACITY_WAITING => changed.await,
CAPACITY_GRANTED => {
self.signal
.status
.store(CAPACITY_TAKEN, AtomicOrdering::Release);
self.active = false;
return Ok(OwnershipPermit::new(Arc::clone(&self.broker), self.units));
}
CAPACITY_CLOSED => {
self.active = false;
return Err(self.broker.error());
}
_invalid => {
self.broker.close();
self.active = false;
return Err(self.broker.error());
}
}
}
}
}
impl Drop for CapacityRequest {
fn drop(&mut self) {
if self.active {
self.broker.cancel(self.units, &self.signal);
}
}
}
impl CapacityBroker {
pub(super) fn new(limit: Option<NonZeroUsize>) -> Arc<Self> {
let mode = match limit {
Some(limit) => CapacityMode::Limited(LimitedCapacityState {
available: limit.get(),
effective_capacity: limit.get(),
waiters: VecDeque::new(),
}),
None => CapacityMode::Unlimited,
};
Arc::new(Self {
limit,
state: Mutex::new(CapacityState {
closed: false,
mode,
}),
})
}
fn error(&self) -> DropCapacityError {
DropCapacityError::new(self.limit)
}
pub(super) async fn acquire(
self: &Arc<Self>,
units: usize,
) -> Result<OwnershipPermit, DropCapacityError> {
match self.start_acquire(units)? {
CapacityStart::Ready(permit) => Ok(permit),
CapacityStart::Waiting(request) => request.wait().await,
}
}
pub(super) fn try_acquire(
self: &Arc<Self>,
units: usize,
) -> Result<OwnershipPermit, DropCapacityError> {
if units == 0 || self.limit.is_some_and(|limit| units > limit.get()) {
return Err(self.error());
}
let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
if state.closed {
return Err(self.error());
}
let CapacityMode::Limited(limited) = &mut state.mode else {
return Ok(OwnershipPermit::new(Arc::clone(self), units));
};
if units > limited.effective_capacity
|| !limited.waiters.is_empty()
|| limited.available < units
{
return Err(self.error());
}
limited.available -= units;
Ok(OwnershipPermit::new(Arc::clone(self), units))
}
fn start_acquire(self: &Arc<Self>, units: usize) -> Result<CapacityStart, DropCapacityError> {
if units == 0 || self.limit.is_some_and(|limit| units > limit.get()) {
return Err(self.error());
}
let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
if state.closed {
return Err(self.error());
}
let CapacityMode::Limited(limited) = &mut state.mode else {
return Ok(CapacityStart::Ready(OwnershipPermit::new(
Arc::clone(self),
units,
)));
};
if units > limited.effective_capacity {
return Err(self.error());
}
if limited.waiters.is_empty() && limited.available >= units {
limited.available -= units;
return Ok(CapacityStart::Ready(OwnershipPermit::new(
Arc::clone(self),
units,
)));
}
let capacity = self
.limit
.expect("limited capacity mode has a configured limit")
.get();
if limited.waiters.len() >= capacity {
return Err(self.error());
}
let signal = Arc::new(CapacitySignal::waiting());
limited.waiters.push_back(CapacityWaiter {
units,
bypassed_units: 0,
signal: Arc::clone(&signal),
});
let (ready, valid) = Self::dispatch_limited(limited);
if !valid {
state.closed = true;
let closed = Self::close_waiters_locked(&mut state);
drop(state);
Self::notify(closed);
return Err(self.error());
}
drop(state);
Self::notify(ready);
Ok(CapacityStart::Waiting(CapacityRequest {
broker: Arc::clone(self),
units,
signal,
active: true,
}))
}
fn release(&self, units: usize) {
if units == 0 {
return;
}
let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
let ready = if Self::return_capacity_locked(&mut state, units) {
Self::dispatch_locked(&mut state)
} else {
Self::close_waiters_locked(&mut state)
};
drop(state);
Self::notify(ready);
}
fn retire(&self, units: usize) {
if units == 0 {
return;
}
let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
if state.closed {
return;
}
let CapacityMode::Limited(limited) = &mut state.mode else {
return;
};
let mut rejected = Vec::new();
let close = if let Some(effective_capacity) = limited.effective_capacity.checked_sub(units)
{
if limited.available > effective_capacity {
true
} else {
limited.effective_capacity = effective_capacity;
limited.waiters.retain(|waiter| {
if waiter.units <= effective_capacity {
true
} else {
waiter
.signal
.status
.store(CAPACITY_CLOSED, AtomicOrdering::Release);
rejected.push(Arc::clone(&waiter.signal));
false
}
});
effective_capacity == 0
}
} else {
true
};
if close {
state.closed = true;
rejected.extend(Self::close_waiters_locked(&mut state));
} else {
rejected.extend(Self::dispatch_locked(&mut state));
}
drop(state);
Self::notify(rejected);
}
fn cancel(&self, units: usize, signal: &Arc<CapacitySignal>) {
let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
match signal.status.load(AtomicOrdering::Acquire) {
CAPACITY_WAITING => {
let CapacityMode::Limited(limited) = &mut state.mode else {
state.closed = true;
signal
.status
.store(CAPACITY_CANCELED, AtomicOrdering::Release);
return;
};
if let Some(position) = limited
.waiters
.iter()
.position(|waiter| Arc::ptr_eq(&waiter.signal, signal))
{
limited.waiters.remove(position);
}
}
CAPACITY_GRANTED => {
if !Self::return_capacity_locked(&mut state, units) {
signal
.status
.store(CAPACITY_CANCELED, AtomicOrdering::Release);
let closed = Self::close_waiters_locked(&mut state);
drop(state);
Self::notify(closed);
return;
}
}
CAPACITY_CLOSED => {}
CAPACITY_TAKEN | CAPACITY_CANCELED => return,
_invalid => {
state.closed = true;
signal
.status
.store(CAPACITY_CANCELED, AtomicOrdering::Release);
let closed = Self::close_waiters_locked(&mut state);
drop(state);
Self::notify(closed);
return;
}
}
signal
.status
.store(CAPACITY_CANCELED, AtomicOrdering::Release);
let ready = Self::dispatch_locked(&mut state);
drop(state);
Self::notify(ready);
}
pub(super) fn close(&self) {
let signals = {
let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
if state.closed {
return;
}
state.closed = true;
Self::close_waiters_locked(&mut state)
};
Self::notify(signals);
}
fn return_capacity_locked(state: &mut CapacityState, units: usize) -> bool {
let CapacityMode::Limited(limited) = &mut state.mode else {
return true;
};
let Some(available) = limited.available.checked_add(units) else {
state.closed = true;
return false;
};
if available > limited.effective_capacity {
state.closed = true;
return false;
}
limited.available = available;
true
}
fn close_waiters_locked(state: &mut CapacityState) -> Vec<Arc<CapacitySignal>> {
let CapacityMode::Limited(limited) = &mut state.mode else {
return Vec::new();
};
limited
.waiters
.drain(..)
.map(|waiter| {
waiter
.signal
.status
.store(CAPACITY_CLOSED, AtomicOrdering::Release);
waiter.signal
})
.collect()
}
fn dispatch_locked(state: &mut CapacityState) -> Vec<Arc<CapacitySignal>> {
if state.closed {
return Vec::new();
}
let CapacityMode::Limited(limited) = &mut state.mode else {
return Vec::new();
};
let (mut ready, valid) = Self::dispatch_limited(limited);
if !valid {
state.closed = true;
ready.extend(Self::close_waiters_locked(state));
}
ready
}
fn dispatch_limited(limited: &mut LimitedCapacityState) -> (Vec<Arc<CapacitySignal>>, bool) {
let effective_capacity = limited.effective_capacity;
let mut ready = Vec::new();
loop {
let mut selected = None;
for (index, waiter) in limited.waiters.iter().enumerate() {
if waiter.units <= limited.available {
let exceeds_bypass_budget = limited.waiters.iter().take(index).any(|older| {
older.bypassed_units.saturating_add(waiter.units) > effective_capacity
});
if exceeds_bypass_budget {
break;
}
selected = Some(index);
break;
}
if waiter.bypassed_units >= effective_capacity {
break;
}
}
let Some(index) = selected else {
break;
};
let granted_units = limited.waiters[index].units;
for waiter in limited.waiters.iter_mut().take(index) {
waiter.bypassed_units = waiter.bypassed_units.saturating_add(granted_units);
}
let Some(waiter) = limited.waiters.remove(index) else {
return (ready, false);
};
limited.available -= waiter.units;
waiter
.signal
.status
.store(CAPACITY_GRANTED, AtomicOrdering::Release);
ready.push(waiter.signal);
}
(ready, true)
}
fn notify(signals: Vec<Arc<CapacitySignal>>) {
for signal in signals {
signal.changed.notify_waiters();
}
}
#[cfg(test)]
pub(super) fn available(&self) -> usize {
let state = self.state.lock().unwrap_or_else(|error| error.into_inner());
let CapacityMode::Limited(limited) = &state.mode else {
panic!("unlimited capacity has no available-unit count");
};
limited.available
}
#[cfg(test)]
pub(super) fn effective_capacity(&self) -> usize {
let state = self.state.lock().unwrap_or_else(|error| error.into_inner());
let CapacityMode::Limited(limited) = &state.mode else {
panic!("unlimited capacity has no effective-unit count");
};
limited.effective_capacity
}
#[cfg(test)]
pub(super) fn waiter_count(&self) -> usize {
let state = self.state.lock().unwrap_or_else(|error| error.into_inner());
match &state.mode {
CapacityMode::Limited(limited) => limited.waiters.len(),
CapacityMode::Unlimited => 0,
}
}
}
pub(super) struct OwnershipPermit {
broker: Arc<CapacityBroker>,
units: usize,
}
impl OwnershipPermit {
fn new(broker: Arc<CapacityBroker>, units: usize) -> Self {
Self { broker, units }
}
pub(super) fn split_one(&mut self) -> Option<Self> {
if self.units == 0 {
return None;
}
self.units -= 1;
Some(Self::new(Arc::clone(&self.broker), 1))
}
pub(super) fn retire(mut self) {
let units = std::mem::take(&mut self.units);
self.broker.retire(units);
}
pub(super) fn close_without_release(mut self) {
self.units = 0;
self.broker.close();
}
}
impl Drop for OwnershipPermit {
fn drop(&mut self) {
let units = std::mem::take(&mut self.units);
self.broker.release(units);
}
}