use std::sync::Arc;
use tokio::sync::{OwnedSemaphorePermit, Semaphore};
use super::RequestHandler;
use crate::error::{ServerError, ServerResult};
use crate::store::tenant::TenantContext;
impl RequestHandler {
pub(crate) async fn acquire_tenant_slot(&self) -> ServerResult<Option<OwnedSemaphorePermit>> {
let Some(cap) = self
.tenant_limits()
.and_then(|limits| limits.max_concurrent_tasks)
else {
return Ok(None);
};
let tenant = TenantContext::current();
let semaphore = self.tenant_slot_semaphore(&tenant, cap).await;
semaphore.try_acquire_owned().map(Some).map_err(|_| {
ServerError::Overloaded(format!(
"tenant '{tenant}' already has {cap} task(s) in flight"
))
})
}
async fn tenant_slot_semaphore(&self, tenant: &str, cap: usize) -> Arc<Semaphore> {
let mut slots = self.tenant_slots.write().await;
if slots.len() >= self.limits.max_context_locks {
slots.retain(|_, sem| Arc::strong_count(sem) > 1);
}
Arc::clone(
slots
.entry(tenant.to_owned())
.or_insert_with(|| Arc::new(Semaphore::new(cap))),
)
}
}