use hawdb_core::error::HawDBError;
#[cfg(all(unix, not(target_arch = "wasm32")))]
pub(super) const HOST_HEADROOM: usize = 64;
#[cfg(all(unix, not(target_arch = "wasm32")))]
mod native {
use super::{HawDBError, HOST_HEADROOM};
use hawdb_core::error::FileDescriptorError;
use std::io;
const MIN_PROJECT_CAPACITY: usize = 8;
fn value<T: Into<u64>>(limit: T) -> u64 {
limit.into()
}
fn rejected(limit: Option<libc::rlimit>, requested: usize, os_code: Option<i32>) -> HawDBError {
HawDBError::FileDescriptors(FileDescriptorError::OsLimit {
requested,
os_code,
soft: limit.as_ref().map(|limit| value(limit.rlim_cur)),
hard: limit.as_ref().map(|limit| value(limit.rlim_max)),
})
}
fn read() -> io::Result<libc::rlimit> {
let mut limit = libc::rlimit {
rlim_cur: 0,
rlim_max: 0,
};
if unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &mut limit) } != 0 {
return Err(io::Error::last_os_error());
}
Ok(limit)
}
pub(super) fn effective_limit(budget: usize) -> Result<usize, HawDBError> {
let minimum = budget.min(MIN_PROJECT_CAPACITY);
let requested = minimum + HOST_HEADROOM;
let current = read().map_err(|error| rejected(None, requested, error.raw_os_error()))?;
let allowance = usize::try_from(value(current.rlim_cur))
.unwrap_or(usize::MAX)
.saturating_sub(HOST_HEADROOM);
let effective = budget.min(allowance);
if effective < minimum {
return Err(rejected(Some(current), requested, None));
}
Ok(effective)
}
pub(super) fn current_soft_limit() -> Option<u64> {
read().ok().map(|limit| value(limit.rlim_cur))
}
}
pub(super) fn effective_limit(budget: usize) -> Result<usize, HawDBError> {
#[cfg(all(unix, not(target_arch = "wasm32")))]
{
native::effective_limit(budget)
}
#[cfg(not(all(unix, not(target_arch = "wasm32"))))]
{
Ok(budget)
}
}
pub(super) fn current_soft_limit() -> Option<u64> {
#[cfg(all(unix, not(target_arch = "wasm32")))]
{
native::current_soft_limit()
}
#[cfg(not(all(unix, not(target_arch = "wasm32"))))]
None
}