use std::sync::atomic::{AtomicU64, Ordering::Relaxed};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Metrics {
pub live: u64,
pub idle: u64,
pub parked: u64,
pub created: u64,
pub closed: u64,
pub acquires: u64,
pub waits: u64,
pub timeouts: u64,
pub poisoned: u64,
pub recycle_failures: u64,
pub unparked: u64,
}
#[derive(Debug, Default)]
pub(crate) struct Counters {
pub live: AtomicU64,
pub idle: AtomicU64,
pub created: AtomicU64,
pub closed: AtomicU64,
pub acquires: AtomicU64,
pub waits: AtomicU64,
pub timeouts: AtomicU64,
pub poisoned: AtomicU64,
pub recycle_failures: AtomicU64,
pub unparked: AtomicU64,
}
impl Counters {
pub(crate) fn inc(c: &AtomicU64) {
c.fetch_add(1, Relaxed);
}
pub(crate) fn dec(c: &AtomicU64) {
c.fetch_sub(1, Relaxed);
}
pub(crate) fn snapshot(&self, parked: u64) -> Metrics {
Metrics {
live: self.live.load(Relaxed),
idle: self.idle.load(Relaxed),
parked,
created: self.created.load(Relaxed),
closed: self.closed.load(Relaxed),
acquires: self.acquires.load(Relaxed),
waits: self.waits.load(Relaxed),
timeouts: self.timeouts.load(Relaxed),
poisoned: self.poisoned.load(Relaxed),
recycle_failures: self.recycle_failures.load(Relaxed),
unparked: self.unparked.load(Relaxed),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn counters_start_at_zero() {
assert_eq!(Counters::default().snapshot(0), Metrics::default());
}
#[test]
fn inc_and_dec_move_one_at_a_time() {
let c = Counters::default();
Counters::inc(&c.live);
Counters::inc(&c.live);
Counters::dec(&c.live);
assert_eq!(c.live.load(Relaxed), 1);
}
#[test]
fn snapshot_maps_every_field_to_its_own_counter() {
let c = Counters::default();
c.live.store(1, Relaxed);
c.idle.store(2, Relaxed);
c.created.store(3, Relaxed);
c.closed.store(4, Relaxed);
c.acquires.store(5, Relaxed);
c.waits.store(6, Relaxed);
c.timeouts.store(7, Relaxed);
c.poisoned.store(8, Relaxed);
c.recycle_failures.store(9, Relaxed);
c.unparked.store(10, Relaxed);
assert_eq!(
c.snapshot(11),
Metrics {
live: 1,
idle: 2,
parked: 11,
created: 3,
closed: 4,
acquires: 5,
waits: 6,
timeouts: 7,
poisoned: 8,
recycle_failures: 9,
unparked: 10,
}
);
}
#[test]
fn parked_comes_from_the_argument() {
let c = Counters::default();
assert_eq!(c.snapshot(0).parked, 0);
assert_eq!(c.snapshot(42).parked, 42);
}
#[test]
fn metrics_is_copy_eq_and_debug() {
let m = Counters::default().snapshot(1);
let copy = m;
assert_eq!(m, copy);
assert_ne!(m, Metrics::default());
assert!(format!("{m:?}").contains("parked"));
assert!(format!("{:?}", Counters::default()).contains("live"));
}
}