use std::{
sync::{
Arc,
atomic::{AtomicU64, Ordering},
},
time::Duration,
};
use crate::wire::BufferPoolStats;
#[derive(Debug, Clone, Default)]
pub(super) struct AdminMetrics {
inner: Arc<AdminMetricsInner>,
}
#[derive(Debug, Default)]
#[expect(
clippy::struct_field_names,
reason = "All counters are request-scoped."
)]
struct AdminMetricsInner {
request_total: AtomicU64,
request_error_total: AtomicU64,
request_latency_nanos_total: AtomicU64,
request_latency_nanos_max: AtomicU64,
}
impl AdminMetrics {
pub(super) fn record(&self, latency: Duration, is_error: bool) {
let nanos = u64::try_from(latency.as_nanos()).unwrap_or(u64::MAX);
let _previous = self.inner.request_total.fetch_add(1, Ordering::Relaxed);
if is_error {
let _previous = self
.inner
.request_error_total
.fetch_add(1, Ordering::Relaxed);
}
let _previous = self
.inner
.request_latency_nanos_total
.fetch_add(nanos, Ordering::Relaxed);
let _previous = self
.inner
.request_latency_nanos_max
.fetch_max(nanos, Ordering::Relaxed);
}
pub(super) fn snapshot(&self, buffer_pool: BufferPoolStats) -> AdminMetricsSnapshot {
let request_total = self.inner.request_total.load(Ordering::Relaxed);
let request_latency_nanos_total = self
.inner
.request_latency_nanos_total
.load(Ordering::Relaxed);
let request_latency_avg_nanos = request_latency_nanos_total
.checked_div(request_total)
.unwrap_or(0);
AdminMetricsSnapshot {
request_total,
request_error_total: self.inner.request_error_total.load(Ordering::Relaxed),
request_latency_avg_nanos,
request_latency_max_nanos: self.inner.request_latency_nanos_max.load(Ordering::Relaxed),
buffer_pool,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AdminMetricsSnapshot {
pub request_total: u64,
pub request_error_total: u64,
pub request_latency_avg_nanos: u64,
pub request_latency_max_nanos: u64,
pub buffer_pool: BufferPoolStats,
}