mod histogram;
#[cfg(test)]
mod tests;
pub use histogram::{Histogram, HistogramSnapshot};
use tessarikv_sync::StripedCounters;
use histogram::{BUCKETS, SLOTS};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Ticker {
GetCalls,
MemtableHit,
MemtableMiss,
BlockCacheHit,
BlockCacheMiss,
BlockBytesRead,
BloomUseful,
BloomMaybe,
KeysWritten,
BytesWritten,
WalBytes,
WalSyncs,
StallMicros,
FlushBytes,
CompactionBytesRead,
CompactionBytesWritten,
CompactionKeysDropped,
}
impl Ticker {
pub const ALL: [Self; 17] = [
Self::GetCalls,
Self::MemtableHit,
Self::MemtableMiss,
Self::BlockCacheHit,
Self::BlockCacheMiss,
Self::BlockBytesRead,
Self::BloomUseful,
Self::BloomMaybe,
Self::KeysWritten,
Self::BytesWritten,
Self::WalBytes,
Self::WalSyncs,
Self::StallMicros,
Self::FlushBytes,
Self::CompactionBytesRead,
Self::CompactionBytesWritten,
Self::CompactionKeysDropped,
];
#[must_use]
pub const fn name(self) -> &'static str {
match self {
Self::GetCalls => "get.calls",
Self::MemtableHit => "memtable.hit",
Self::MemtableMiss => "memtable.miss",
Self::BlockCacheHit => "block.cache.hit",
Self::BlockCacheMiss => "block.cache.miss",
Self::BlockBytesRead => "block.bytes.read",
Self::BloomUseful => "bloom.useful",
Self::BloomMaybe => "bloom.maybe",
Self::KeysWritten => "keys.written",
Self::BytesWritten => "bytes.written",
Self::WalBytes => "wal.bytes",
Self::WalSyncs => "wal.syncs",
Self::StallMicros => "stall.micros",
Self::FlushBytes => "flush.bytes",
Self::CompactionBytesRead => "compaction.bytes.read",
Self::CompactionBytesWritten => "compaction.bytes.written",
Self::CompactionKeysDropped => "compaction.keys.dropped",
}
}
const fn index(self) -> usize {
match self {
Self::GetCalls => 0,
Self::MemtableHit => 1,
Self::MemtableMiss => 2,
Self::BlockCacheHit => 3,
Self::BlockCacheMiss => 4,
Self::BlockBytesRead => 5,
Self::BloomUseful => 6,
Self::BloomMaybe => 7,
Self::KeysWritten => 8,
Self::BytesWritten => 9,
Self::WalBytes => 10,
Self::WalSyncs => 11,
Self::StallMicros => 12,
Self::FlushBytes => 13,
Self::CompactionBytesRead => 14,
Self::CompactionBytesWritten => 15,
Self::CompactionKeysDropped => 16,
}
}
}
#[derive(Debug)]
pub(crate) struct Statistics {
tickers: StripedCounters,
histograms: StripedCounters,
}
impl Statistics {
pub(crate) fn new() -> Self {
Self {
tickers: StripedCounters::new(Ticker::ALL.len()),
histograms: StripedCounters::new(Histogram::ALL.len().saturating_mul(SLOTS)),
}
}
pub(crate) fn record(&self, ticker: Ticker, amount: u64) {
self.tickers.add(ticker.index(), amount);
}
pub(crate) fn observe(&self, histogram: Histogram, micros: u64) {
let base = histogram.base();
self.histograms
.add(base.saturating_add(histogram::bucket(micros)), 1);
self.histograms.add(base.saturating_add(BUCKETS), micros);
}
pub(crate) fn snapshot(&self) -> StatisticsSnapshot {
StatisticsSnapshot {
tickers: Ticker::ALL.map(|ticker| self.tickers.sum(ticker.index())),
histograms: Histogram::ALL.map(|histogram| {
let base = histogram.base();
let mut snapshot = HistogramSnapshot::default();
for (bucket, count) in snapshot.buckets.iter_mut().enumerate() {
*count = self.histograms.take(base.saturating_add(bucket));
}
snapshot.sum = self.histograms.take(base.saturating_add(BUCKETS));
snapshot
}),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StatisticsSnapshot {
tickers: [u64; Ticker::ALL.len()],
histograms: [HistogramSnapshot; Histogram::ALL.len()],
}
impl StatisticsSnapshot {
#[must_use]
pub fn ticker(&self, ticker: Ticker) -> u64 {
self.tickers.get(ticker.index()).copied().unwrap_or(0)
}
#[must_use]
pub fn histogram(&self, histogram: Histogram) -> &HistogramSnapshot {
&self.histograms[histogram.index()]
}
}