use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Duration;
const ACCEPT_ERROR_BACKOFF: Duration = Duration::from_millis(100);
pub(crate) async fn handle_accept_error(context: &str, error: &std::io::Error) {
match error.kind() {
std::io::ErrorKind::WouldBlock
| std::io::ErrorKind::Interrupted
| std::io::ErrorKind::ConnectionAborted => {}
_ => tokio::time::sleep(ACCEPT_ERROR_BACKOFF).await,
}
tracing::error!("{context} accept error: {error}");
}
pub(crate) struct ListenerConnectionSlot {
active: Arc<AtomicU64>,
}
impl ListenerConnectionSlot {
pub(crate) fn try_acquire(active: &Arc<AtomicU64>, limit: u64) -> Option<Self> {
active
.fetch_update(Ordering::AcqRel, Ordering::Relaxed, |current| {
(current < limit).then_some(current + 1)
})
.ok()
.map(|_| Self {
active: active.clone(),
})
}
}
impl Drop for ListenerConnectionSlot {
fn drop(&mut self) {
self.active.fetch_sub(1, Ordering::Release);
}
}
pub(crate) struct ActiveConnectionGuard {
active: Arc<AtomicU64>,
}
impl ActiveConnectionGuard {
pub(crate) fn new(active: Arc<AtomicU64>) -> Self {
active.fetch_add(1, Ordering::AcqRel);
Self { active }
}
}
impl Drop for ActiveConnectionGuard {
fn drop(&mut self) {
self.active.fetch_sub(1, Ordering::Release);
}
}