pub mod jitter;
mod pool;
pub mod transmit;
pub use jitter::*;
pub use pool::*;
pub use transmit::*;
use std::sync::Arc;
use tokio::sync::Semaphore;
pub const DEFAULT_MAX_BUFFERED_PACKETS: usize = 1000;
#[derive(Debug, Clone)]
pub struct BufferLimits {
pub max_packets_per_stream: usize,
pub max_packet_size: usize,
pub max_memory: usize,
}
impl Default for BufferLimits {
fn default() -> Self {
Self {
max_packets_per_stream: DEFAULT_MAX_BUFFERED_PACKETS,
max_packet_size: crate::DEFAULT_MAX_PACKET_SIZE,
max_memory: 0, }
}
}
pub struct GlobalBufferManager {
memory_semaphore: Option<Arc<Semaphore>>,
limits: BufferLimits,
}
impl GlobalBufferManager {
pub fn new(limits: BufferLimits) -> Self {
let memory_semaphore = if limits.max_memory > 0 {
let chunk_size = 1024; let permits = limits.max_memory / chunk_size;
Some(Arc::new(Semaphore::new(permits)))
} else {
None
};
Self {
memory_semaphore,
limits,
}
}
pub async fn acquire_memory(&self, size: usize) -> Option<MemoryPermit> {
if let Some(semaphore) = &self.memory_semaphore {
let chunk_size = 1024; let chunks = (size + chunk_size - 1) / chunk_size;
let sem_clone = semaphore.clone();
match Arc::clone(&sem_clone).try_acquire_many_owned(chunks as u32) {
Ok(permit) => Some(MemoryPermit {
permit: Some(permit),
chunks,
}),
Err(_) => None, }
} else {
Some(MemoryPermit {
permit: None,
chunks: 0,
})
}
}
pub fn get_limits(&self) -> &BufferLimits {
&self.limits
}
}
#[allow(dead_code)] pub struct MemoryPermit {
permit: Option<tokio::sync::OwnedSemaphorePermit>,
#[allow(dead_code)] chunks: usize,
}
impl Drop for MemoryPermit {
fn drop(&mut self) {
if let Some(permit) = self.permit.take() {
drop(permit);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_memory_limits() {
let limits = BufferLimits {
max_memory: 10 * 1024, ..Default::default()
};
let manager = GlobalBufferManager::new(limits);
let permit1 = manager.acquire_memory(5 * 1024).await;
assert!(permit1.is_some(), "Should be able to acquire 5KB");
let permit2 = manager.acquire_memory(5 * 1024).await;
assert!(permit2.is_some(), "Should be able to acquire another 5KB");
let permit3 = manager.acquire_memory(1024).await;
assert!(
permit3.is_none(),
"Should not be able to acquire more memory when limit reached"
);
drop(permit1);
let permit3 = manager.acquire_memory(5 * 1024).await;
assert!(
permit3.is_some(),
"Should be able to acquire 5KB after releasing memory"
);
let permit4 = manager.acquire_memory(6 * 1024).await;
assert!(
permit4.is_none(),
"Should not be able to acquire 6KB when only 5KB is available"
);
}
}