use crate::layout::BlobGuid;
use crate::layout::{DATA_AREA_START, PAGE_SIZE};
#[derive(Debug, Clone, Copy)]
pub struct BlobStats {
pub guid: BlobGuid,
pub space_used: u32,
pub gap_space: u32,
pub num_slots: u16,
pub num_ext_blobs: u16,
pub compact_times: u32,
pub tombstone_leaf_cnt: u32,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct RouteCacheStats {
pub entries: usize,
pub hits: u64,
pub misses: u64,
pub learns: u64,
pub evictions: u64,
pub invalidations: u64,
}
#[derive(Debug, Clone)]
pub struct TreeStats {
pub blob_count: u32,
pub total_space_used: u64,
pub total_gap_space: u64,
pub total_slots: u64,
pub total_compactions: u64,
pub total_tombstones: u64,
pub total_blob_edges: u64,
pub leaf_blob_count: u32,
pub max_blob_depth: u32,
pub total_blob_depth: u64,
pub max_blob_fill_per_mille: u32,
pub blobs: Vec<BlobStats>,
pub bm_dirty_count: usize,
pub bm_pending_delete_count: usize,
pub bm_cache_hits: u64,
pub bm_cache_misses: u64,
pub bm_optimistic_restarts: u64,
pub bm_range_restarts: u64,
pub bm_walker_ops: u64,
pub bm_walker_blob_hops: u64,
pub bm_max_blob_hops: u64,
pub bm_max_cross_blob_depth: u64,
pub bm_spillovers: u64,
pub bm_merges: u64,
pub route_cache: RouteCacheStats,
pub journal: Option<JournalStats>,
pub checkpointer: Option<CheckpointerStats>,
}
impl TreeStats {
#[must_use]
#[allow(clippy::cast_precision_loss)] pub fn bm_avg_blob_hops(&self) -> f64 {
if self.bm_walker_ops == 0 {
0.0
} else {
self.bm_walker_blob_hops as f64 / self.bm_walker_ops as f64
}
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn avg_blob_depth(&self) -> f64 {
if self.blob_count == 0 {
0.0
} else {
self.total_blob_depth as f64 / f64::from(self.blob_count)
}
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn leaf_blob_ratio(&self) -> f64 {
if self.blob_count == 0 {
0.0
} else {
f64::from(self.leaf_blob_count) / f64::from(self.blob_count)
}
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn avg_blob_fill_ratio(&self) -> f64 {
if self.blob_count == 0 {
return 0.0;
}
let header_bytes = u64::from(self.blob_count) * DATA_AREA_START as u64;
let data_used = self.total_space_used.saturating_sub(header_bytes);
let data_capacity = u64::from(self.blob_count) * (PAGE_SIZE - DATA_AREA_START) as u64;
if data_capacity == 0 {
0.0
} else {
data_used as f64 / data_capacity as f64
}
}
#[must_use]
pub fn max_blob_fill_ratio(&self) -> f64 {
f64::from(self.max_blob_fill_per_mille) / 1000.0
}
}
#[derive(Debug, Clone, Copy)]
pub struct JournalStats {
pub appends: u64,
pub batches: u64,
pub syncs: u64,
}
#[derive(Debug, Clone, Copy)]
pub struct CheckpointerStats {
pub rounds_attempted: u64,
pub rounds_succeeded: u64,
pub blobs_flushed: u64,
pub merges_total: u64,
pub truncates: u64,
pub evictions: u64,
}