use std::sync::OnceLock;
pub use histogram::{Bucket, Config, Error, Histogram};
use parking_lot::RwLock;
use crate::{HistogramMetric, Metric, Value};
pub struct AtomicHistogram {
inner: OnceLock<histogram::AtomicHistogram>,
config: Config,
}
impl AtomicHistogram {
pub const fn new(grouping_power: u8, max_value_power: u8) -> Self {
let config = match ::histogram::Config::new(grouping_power, max_value_power) {
Ok(c) => c,
Err(_) => panic!("invalid histogram config"),
};
Self {
inner: OnceLock::new(),
config,
}
}
pub fn increment(&self, value: u64) -> Result<(), Error> {
self.get_or_init().increment(value)
}
pub fn config(&self) -> Config {
self.config
}
pub fn load(&self) -> Option<Histogram> {
self.inner.get().map(|h| h.load())
}
fn get_or_init(&self) -> &::histogram::AtomicHistogram {
self.inner
.get_or_init(|| ::histogram::AtomicHistogram::with_config(&self.config))
}
}
impl HistogramMetric for AtomicHistogram {
fn config(&self) -> Config {
self.config
}
fn load(&self) -> Option<Histogram> {
self.load()
}
}
impl Metric for AtomicHistogram {
fn as_any(&self) -> Option<&dyn std::any::Any> {
Some(self)
}
fn value(&self) -> Option<Value<'_>> {
Some(Value::Histogram(self))
}
}
pub struct RwLockHistogram {
inner: OnceLock<RwLock<histogram::Histogram>>,
config: Config,
}
impl RwLockHistogram {
pub const fn new(grouping_power: u8, max_value_power: u8) -> Self {
let config = match ::histogram::Config::new(grouping_power, max_value_power) {
Ok(c) => c,
Err(_e) => panic!("invalid histogram config"),
};
Self {
inner: OnceLock::new(),
config,
}
}
pub fn update_from(&self, data: &[u64]) -> Result<(), Error> {
if data.len() != self.config.total_buckets() {
return Err(Error::IncompatibleParameters);
}
let mut histogram = self.get_or_init().write();
let buckets = histogram.as_mut_slice();
buckets.copy_from_slice(data);
Ok(())
}
pub fn config(&self) -> Config {
self.config
}
pub fn load(&self) -> Option<Histogram> {
self.inner.get().map(|h| h.read().clone())
}
fn get_or_init(&self) -> &RwLock<::histogram::Histogram> {
self.inner
.get_or_init(|| ::histogram::Histogram::with_config(&self.config).into())
}
}
impl HistogramMetric for RwLockHistogram {
fn config(&self) -> Config {
self.config
}
fn load(&self) -> Option<Histogram> {
self.load()
}
}
impl Metric for RwLockHistogram {
fn as_any(&self) -> Option<&dyn std::any::Any> {
Some(self)
}
fn value(&self) -> Option<Value<'_>> {
Some(Value::Histogram(self))
}
}