use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, RwLock};
use std::time::{Duration, Instant};
#[derive(Debug, Clone)]
pub struct ConnectionManagerConfig {
pub min_buffer_size: usize,
pub max_buffer_size: usize,
pub initial_buffer_size: usize,
pub buffer_adjust_interval: Duration,
pub buffer_history_window: Duration,
pub base_keep_alive_timeout: Duration,
pub min_keep_alive_timeout: Duration,
pub max_keep_alive_timeout: Duration,
pub keep_alive_load_threshold: f64,
pub enable_culling: bool,
pub idle_timeout: Duration,
pub cull_pressure_threshold: f64,
pub max_connections: usize,
pub min_connections: usize,
pub cull_batch_size: usize,
}
impl Default for ConnectionManagerConfig {
fn default() -> Self {
Self {
min_buffer_size: 256,
max_buffer_size: 64 * 1024,
initial_buffer_size: 4 * 1024,
buffer_adjust_interval: Duration::from_secs(10),
buffer_history_window: Duration::from_secs(60),
base_keep_alive_timeout: Duration::from_secs(60),
min_keep_alive_timeout: Duration::from_secs(5),
max_keep_alive_timeout: Duration::from_secs(120),
keep_alive_load_threshold: 0.7,
enable_culling: true,
idle_timeout: Duration::from_secs(30),
cull_pressure_threshold: 0.8,
max_connections: 10_000,
min_connections: 100,
cull_batch_size: 100,
}
}
}
impl ConnectionManagerConfig {
pub fn high_throughput() -> Self {
Self {
min_buffer_size: 4 * 1024,
max_buffer_size: 256 * 1024,
initial_buffer_size: 16 * 1024,
buffer_adjust_interval: Duration::from_secs(5),
buffer_history_window: Duration::from_secs(30),
base_keep_alive_timeout: Duration::from_secs(120),
min_keep_alive_timeout: Duration::from_secs(10),
max_keep_alive_timeout: Duration::from_secs(300),
keep_alive_load_threshold: 0.85,
enable_culling: true,
idle_timeout: Duration::from_secs(60),
cull_pressure_threshold: 0.9,
max_connections: 50_000,
min_connections: 500,
cull_batch_size: 200,
}
}
pub fn low_memory() -> Self {
Self {
min_buffer_size: 256,
max_buffer_size: 16 * 1024,
initial_buffer_size: 1024,
buffer_adjust_interval: Duration::from_secs(5),
buffer_history_window: Duration::from_secs(30),
base_keep_alive_timeout: Duration::from_secs(30),
min_keep_alive_timeout: Duration::from_secs(5),
max_keep_alive_timeout: Duration::from_secs(60),
keep_alive_load_threshold: 0.5,
enable_culling: true,
idle_timeout: Duration::from_secs(15),
cull_pressure_threshold: 0.6,
max_connections: 1000,
min_connections: 50,
cull_batch_size: 50,
}
}
pub fn development() -> Self {
Self {
enable_culling: false,
max_connections: 100,
..Default::default()
}
}
}
pub type ConnectionId = u64;
#[derive(Debug)]
struct ConnectionState {
#[allow(dead_code)] id: ConnectionId,
created_at: Instant,
last_active_nanos: AtomicU64,
bytes_read: AtomicU64,
bytes_written: AtomicU64,
requests: AtomicU64,
is_keep_alive: AtomicBool,
}
impl ConnectionState {
fn new(id: ConnectionId) -> Self {
Self {
id,
created_at: Instant::now(),
last_active_nanos: AtomicU64::new(0),
bytes_read: AtomicU64::new(0),
bytes_written: AtomicU64::new(0),
requests: AtomicU64::new(0),
is_keep_alive: AtomicBool::new(false),
}
}
fn touch(&self) {
let elapsed = self.created_at.elapsed().as_nanos() as u64;
self.last_active_nanos.store(elapsed, Ordering::Relaxed);
}
fn idle_duration(&self) -> Duration {
let last = Duration::from_nanos(self.last_active_nanos.load(Ordering::Relaxed));
self.created_at.elapsed().saturating_sub(last)
}
}
#[derive(Debug, Clone, Copy)]
struct BufferSample {
timestamp: Instant,
size: usize,
was_sufficient: bool,
}
#[derive(Debug)]
struct BufferHistory {
samples: Vec<BufferSample>,
window: Duration,
optimal_size: AtomicUsize,
}
impl BufferHistory {
const MAX_SAMPLES: usize = 1000;
fn new(window: Duration, initial_size: usize) -> Self {
Self {
samples: Vec::with_capacity(1000),
window,
optimal_size: AtomicUsize::new(initial_size),
}
}
fn record(&mut self, size: usize, was_sufficient: bool) {
let now = Instant::now();
self.samples
.retain(|s| now.duration_since(s.timestamp) < self.window);
while self.samples.len() >= Self::MAX_SAMPLES {
self.samples.remove(0);
}
self.samples.push(BufferSample {
timestamp: now,
size,
was_sufficient,
});
}
fn compute_optimal_size(&self, min: usize, max: usize) -> usize {
if self.samples.is_empty() {
return self.optimal_size.load(Ordering::Relaxed);
}
let mut successful: Vec<usize> = self
.samples
.iter()
.filter(|s| s.was_sufficient)
.map(|s| s.size)
.collect();
if successful.is_empty() {
let current = self.optimal_size.load(Ordering::Relaxed);
return (current * 2).min(max);
}
successful.sort_unstable();
let p95_idx = (successful.len() * 95 / 100).min(successful.len() - 1);
let p95 = successful[p95_idx];
let size = p95.next_power_of_two().clamp(min, max);
self.optimal_size.store(size, Ordering::Relaxed);
size
}
fn get_optimal_size(&self) -> usize {
self.optimal_size.load(Ordering::Relaxed)
}
}
#[derive(Debug)]
struct LoadTracker {
active_connections: AtomicUsize,
peak_connections: AtomicUsize,
requests_per_second: AtomicU64,
last_rps_update: Mutex<Instant>,
request_count: AtomicU64,
memory_pressure: AtomicUsize,
}
impl Default for LoadTracker {
fn default() -> Self {
Self {
active_connections: AtomicUsize::new(0),
peak_connections: AtomicUsize::new(0),
requests_per_second: AtomicU64::new(0),
last_rps_update: Mutex::new(Instant::now()),
request_count: AtomicU64::new(0),
memory_pressure: AtomicUsize::new(0),
}
}
}
impl LoadTracker {
fn connection_opened(&self) {
let count = self.active_connections.fetch_add(1, Ordering::Relaxed) + 1;
self.peak_connections.fetch_max(count, Ordering::Relaxed);
}
fn connection_closed(&self) {
self.active_connections.fetch_sub(1, Ordering::Relaxed);
}
fn record_request(&self) {
self.request_count.fetch_add(1, Ordering::Relaxed);
}
fn update_rps(&self) {
let mut last_update = self.last_rps_update.lock().unwrap();
let elapsed = last_update.elapsed();
if elapsed >= Duration::from_secs(1) {
let count = self.request_count.swap(0, Ordering::Relaxed);
let rps = (count as f64 / elapsed.as_secs_f64()) as u64;
self.requests_per_second.store(rps, Ordering::Relaxed);
*last_update = Instant::now();
}
}
fn set_memory_pressure(&self, pressure: usize) {
self.memory_pressure
.store(pressure.min(100), Ordering::Relaxed);
}
fn load_factor(&self, max_connections: usize) -> f64 {
let active = self.active_connections.load(Ordering::Relaxed) as f64;
let max = max_connections as f64;
(active / max).min(1.0)
}
fn memory_pressure_factor(&self) -> f64 {
self.memory_pressure.load(Ordering::Relaxed) as f64 / 100.0
}
fn active_connections(&self) -> usize {
self.active_connections.load(Ordering::Relaxed)
}
fn rps(&self) -> u64 {
self.requests_per_second.load(Ordering::Relaxed)
}
}
#[derive(Debug, Default)]
pub struct ConnectionManagerStats {
pub connections_opened: AtomicU64,
pub connections_closed: AtomicU64,
pub connections_culled: AtomicU64,
pub connections_rejected: AtomicU64,
pub buffer_adjustments: AtomicU64,
pub keep_alive_adjustments: AtomicU64,
pub current_buffer_size: AtomicUsize,
pub current_keep_alive_ms: AtomicU64,
}
pub struct ConnectionManager {
config: ConnectionManagerConfig,
connections: RwLock<HashMap<ConnectionId, Arc<ConnectionState>>>,
next_id: AtomicU64,
buffer_history: Mutex<BufferHistory>,
load: LoadTracker,
stats: ConnectionManagerStats,
last_maintenance: Mutex<Instant>,
shutdown: AtomicBool,
}
impl ConnectionManager {
pub fn new(config: ConnectionManagerConfig) -> Self {
let buffer_history =
BufferHistory::new(config.buffer_history_window, config.initial_buffer_size);
Self {
config,
connections: RwLock::new(HashMap::new()),
next_id: AtomicU64::new(1),
buffer_history: Mutex::new(buffer_history),
load: LoadTracker::default(),
stats: ConnectionManagerStats::default(),
last_maintenance: Mutex::new(Instant::now()),
shutdown: AtomicBool::new(false),
}
}
pub fn default_manager() -> Self {
Self::new(ConnectionManagerConfig::default())
}
pub fn register_connection(&self) -> Option<ConnectionId> {
let current = self.load.active_connections();
if current >= self.config.max_connections {
self.stats
.connections_rejected
.fetch_add(1, Ordering::Relaxed);
return None;
}
let id = self.next_id.fetch_add(1, Ordering::Relaxed);
let state = Arc::new(ConnectionState::new(id));
{
let mut connections = self.connections.write().unwrap();
connections.insert(id, state);
}
self.load.connection_opened();
self.stats
.connections_opened
.fetch_add(1, Ordering::Relaxed);
Some(id)
}
pub fn unregister_connection(&self, id: ConnectionId) {
let mut connections = self.connections.write().unwrap();
if connections.remove(&id).is_some() {
self.load.connection_closed();
self.stats
.connections_closed
.fetch_add(1, Ordering::Relaxed);
}
}
pub fn mark_active(&self, id: ConnectionId) {
if let Ok(connections) = self.connections.read()
&& let Some(state) = connections.get(&id)
{
state.touch();
state.requests.fetch_add(1, Ordering::Relaxed);
}
self.load.record_request();
}
pub fn record_bytes_read(&self, id: ConnectionId, bytes: u64) {
if let Ok(connections) = self.connections.read()
&& let Some(state) = connections.get(&id)
{
state.bytes_read.fetch_add(bytes, Ordering::Relaxed);
}
}
pub fn record_bytes_written(&self, id: ConnectionId, bytes: u64) {
if let Ok(connections) = self.connections.read()
&& let Some(state) = connections.get(&id)
{
state.bytes_written.fetch_add(bytes, Ordering::Relaxed);
}
}
pub fn set_keep_alive(&self, id: ConnectionId, keep_alive: bool) {
if let Ok(connections) = self.connections.read()
&& let Some(state) = connections.get(&id)
{
state.is_keep_alive.store(keep_alive, Ordering::Relaxed);
}
}
pub fn recommended_buffer_size(&self) -> usize {
self.buffer_history.lock().unwrap().get_optimal_size()
}
pub fn record_buffer_usage(&self, size: usize, was_sufficient: bool) {
let mut history = self.buffer_history.lock().unwrap();
history.record(size, was_sufficient);
}
fn adjust_buffer_size(&self) {
let history = self.buffer_history.lock().unwrap();
let optimal =
history.compute_optimal_size(self.config.min_buffer_size, self.config.max_buffer_size);
let previous = self
.stats
.current_buffer_size
.swap(optimal, Ordering::Relaxed);
if previous != optimal {
self.stats
.buffer_adjustments
.fetch_add(1, Ordering::Relaxed);
}
}
pub fn keep_alive_timeout(&self) -> Duration {
let load = self.load.load_factor(self.config.max_connections);
let memory_pressure = self.load.memory_pressure_factor();
let pressure = load.max(memory_pressure);
if pressure < self.config.keep_alive_load_threshold {
let extension = (1.0 - pressure / self.config.keep_alive_load_threshold) * 0.5;
let timeout_ms =
self.config.base_keep_alive_timeout.as_millis() as f64 * (1.0 + extension);
let max_ms = self.config.max_keep_alive_timeout.as_millis() as f64;
Duration::from_millis(timeout_ms.min(max_ms) as u64)
} else {
let reduction = (pressure - self.config.keep_alive_load_threshold)
/ (1.0 - self.config.keep_alive_load_threshold);
let base_ms = self.config.base_keep_alive_timeout.as_millis() as f64;
let min_ms = self.config.min_keep_alive_timeout.as_millis() as f64;
let timeout_ms = base_ms - (base_ms - min_ms) * reduction;
Duration::from_millis(timeout_ms.max(min_ms) as u64)
}
}
pub fn allow_keep_alive(&self) -> bool {
let load = self.load.load_factor(self.config.max_connections);
load < 0.95 }
pub fn set_memory_pressure(&self, pressure: usize) {
self.load.set_memory_pressure(pressure);
}
pub fn cull_idle_connections(&self) -> usize {
if !self.config.enable_culling {
return 0;
}
let current = self.load.active_connections();
if current <= self.config.min_connections {
return 0;
}
let load = self.load.load_factor(self.config.max_connections);
let memory_pressure = self.load.memory_pressure_factor();
let pressure = load.max(memory_pressure);
if pressure < self.config.cull_pressure_threshold {
return 0;
}
let to_cull: Vec<ConnectionId> = {
let connections = self.connections.read().unwrap();
let mut idle_connections: Vec<_> = connections
.iter()
.filter(|(_, state)| state.idle_duration() >= self.config.idle_timeout)
.map(|(id, state)| (*id, state.idle_duration()))
.collect();
idle_connections.sort_by_key(|k| std::cmp::Reverse(k.1));
let max_cull = (current - self.config.min_connections).min(self.config.cull_batch_size);
idle_connections
.into_iter()
.take(max_cull)
.map(|(id, _)| id)
.collect()
};
let culled = to_cull.len();
{
let mut connections = self.connections.write().unwrap();
for id in to_cull {
connections.remove(&id);
self.load.connection_closed();
}
}
self.stats
.connections_culled
.fetch_add(culled as u64, Ordering::Relaxed);
culled
}
pub fn get_expired_connections(&self) -> Vec<ConnectionId> {
let connections = self.connections.read().unwrap();
let timeout = self.keep_alive_timeout();
connections
.iter()
.filter(|(_, state)| state.idle_duration() >= timeout)
.map(|(id, _)| *id)
.collect()
}
pub fn maintain(&self) {
if self.shutdown.load(Ordering::Relaxed) {
return;
}
self.load.update_rps();
{
let mut last = self.last_maintenance.lock().unwrap();
if last.elapsed() >= self.config.buffer_adjust_interval {
self.adjust_buffer_size();
*last = Instant::now();
}
}
let timeout = self.keep_alive_timeout();
self.stats
.current_keep_alive_ms
.store(timeout.as_millis() as u64, Ordering::Relaxed);
self.cull_idle_connections();
}
pub fn shutdown(&self) {
self.shutdown.store(true, Ordering::Relaxed);
}
pub fn stats(&self) -> &ConnectionManagerStats {
&self.stats
}
pub fn active_connections(&self) -> usize {
self.load.active_connections()
}
pub fn load_factor(&self) -> f64 {
self.load.load_factor(self.config.max_connections)
}
pub fn rps(&self) -> u64 {
self.load.rps()
}
pub fn snapshot(&self) -> ConnectionManagerSnapshot {
ConnectionManagerSnapshot {
active_connections: self.load.active_connections(),
rps: self.load.rps(),
load_factor: self.load_factor(),
memory_pressure: self.load.memory_pressure_factor(),
buffer_size: self.recommended_buffer_size(),
keep_alive_timeout: self.keep_alive_timeout(),
connections_opened: self.stats.connections_opened.load(Ordering::Relaxed),
connections_closed: self.stats.connections_closed.load(Ordering::Relaxed),
connections_culled: self.stats.connections_culled.load(Ordering::Relaxed),
}
}
}
#[derive(Debug, Clone)]
pub struct ConnectionManagerSnapshot {
pub active_connections: usize,
pub rps: u64,
pub load_factor: f64,
pub memory_pressure: f64,
pub buffer_size: usize,
pub keep_alive_timeout: Duration,
pub connections_opened: u64,
pub connections_closed: u64,
pub connections_culled: u64,
}
use std::sync::OnceLock;
static GLOBAL_MANAGER: OnceLock<Arc<ConnectionManager>> = OnceLock::new();
pub fn init_global_manager(config: ConnectionManagerConfig) -> &'static Arc<ConnectionManager> {
GLOBAL_MANAGER.get_or_init(|| Arc::new(ConnectionManager::new(config)))
}
pub fn global_manager() -> Option<&'static Arc<ConnectionManager>> {
GLOBAL_MANAGER.get()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_connection_lifecycle() {
let manager = ConnectionManager::new(ConnectionManagerConfig::default());
let id = manager.register_connection().unwrap();
assert_eq!(manager.active_connections(), 1);
manager.mark_active(id);
manager.record_bytes_read(id, 1000);
manager.record_bytes_written(id, 500);
manager.unregister_connection(id);
assert_eq!(manager.active_connections(), 0);
}
#[test]
fn test_buffer_tuning() {
let manager = ConnectionManager::new(ConnectionManagerConfig::default());
for _ in 0..100 {
manager.record_buffer_usage(1024, true);
}
manager.adjust_buffer_size();
let size = manager.recommended_buffer_size();
assert!(size >= 1024);
}
#[test]
fn test_keep_alive_under_load() {
let config = ConnectionManagerConfig {
max_connections: 100,
keep_alive_load_threshold: 0.5,
..Default::default()
};
let manager = ConnectionManager::new(config);
let timeout_low = manager.keep_alive_timeout();
for _ in 0..80 {
manager.register_connection();
}
let timeout_high = manager.keep_alive_timeout();
assert!(timeout_high < timeout_low);
}
#[test]
fn test_idle_culling() {
let config = ConnectionManagerConfig {
enable_culling: true,
idle_timeout: Duration::from_millis(1),
cull_pressure_threshold: 0.5,
max_connections: 100,
min_connections: 10,
cull_batch_size: 10,
..Default::default()
};
let manager = ConnectionManager::new(config);
for _ in 0..80 {
manager.register_connection();
}
std::thread::sleep(Duration::from_millis(5));
manager.set_memory_pressure(90);
let culled = manager.cull_idle_connections();
assert!(culled > 0);
assert!(manager.active_connections() < 80);
}
#[test]
fn test_connection_limit() {
let config = ConnectionManagerConfig {
max_connections: 10,
..Default::default()
};
let manager = ConnectionManager::new(config);
for _ in 0..10 {
assert!(manager.register_connection().is_some());
}
assert!(manager.register_connection().is_none());
manager.unregister_connection(1);
assert!(manager.register_connection().is_some());
}
#[test]
fn test_snapshot() {
let manager = ConnectionManager::new(ConnectionManagerConfig::default());
let id = manager.register_connection().unwrap();
manager.mark_active(id);
let snapshot = manager.snapshot();
assert_eq!(snapshot.active_connections, 1);
assert!(snapshot.buffer_size > 0);
}
#[test]
fn test_concurrent_io_accounting_is_lock_free_and_correct() {
let manager = Arc::new(ConnectionManager::new(ConnectionManagerConfig::default()));
let id = manager.register_connection().unwrap();
const THREADS: u64 = 8;
const ITERS: u64 = 1000;
let mut handles = Vec::new();
for _ in 0..THREADS {
let m = Arc::clone(&manager);
handles.push(std::thread::spawn(move || {
for _ in 0..ITERS {
m.record_bytes_read(id, 1);
m.record_bytes_written(id, 2);
m.mark_active(id);
}
}));
}
for h in handles {
h.join().unwrap();
}
let conns = manager.connections.read().unwrap();
let state = conns.get(&id).unwrap();
assert_eq!(state.bytes_read.load(Ordering::Relaxed), THREADS * ITERS);
assert_eq!(
state.bytes_written.load(Ordering::Relaxed),
THREADS * ITERS * 2
);
assert_eq!(state.requests.load(Ordering::Relaxed), THREADS * ITERS);
assert!(state.idle_duration() < Duration::from_secs(1));
}
}