#![forbid(unsafe_code)]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FormatInfo {
pub format_major: u16,
pub format_minor: u16,
pub compat: u64,
pub ro_compat: u64,
pub incompat: u64,
pub io_backend: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct AccountingMetrics {
pub logical_bytes: u64,
pub reachable_bytes: u64,
pub physical_used_bytes: u64,
pub physical_capacity_bytes: u64,
pub physical_free_bytes: u64,
pub object_count: u64,
pub data_record_count: u64,
pub blob_count: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct PhysicalMetrics {
pub live_bytes: u64,
pub dead_indexed_bytes: u64,
pub index_hidden_bytes: u64,
pub unindexed_bytes: u64,
pub torn_bytes: u64,
pub zero_padding_bytes: u64,
pub format_overhead_bytes: u64,
pub unexplained_bytes: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct GcMetrics {
pub unreachable_bytes: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct DsfbMetrics {
pub tracked_chunks: usize,
pub steps: u64,
pub drift_events: u64,
pub slew_events: u64,
pub narrowed_searches: u64,
pub candidates_evaluated: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct PressureMetrics {
pub pressured: bool,
pub samples: u64,
pub enter_events: u64,
pub leave_events: u64,
pub pressured_time_ms: u64,
pub rans_skips: u64,
pub deferred_extents: u64,
pub deferred_logical_bytes: u64,
pub deferred_age_ms: u64,
pub peak_deferred_bytes: u64,
pub debt_cap_engagements: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct CacheMetrics {
pub model_cache_hits: u64,
pub model_cache_misses: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PhaseMetrics {
pub phase: String,
pub count: u64,
pub total_ms: f64,
pub p50_us: f64,
pub p95_us: f64,
pub p99_us: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct EngineMetrics {
pub schema_version: u32,
pub format: FormatInfo,
pub accounting: AccountingMetrics,
pub physical: PhysicalMetrics,
pub gc: GcMetrics,
pub dsfb: DsfbMetrics,
pub pressure: PressureMetrics,
pub cache: CacheMetrics,
pub write_path_phases: Vec<PhaseMetrics>,
}
impl EngineMetrics {
pub fn to_json(&self) -> String {
serde_json::to_string_pretty(self).unwrap_or_else(|_| "{}".into())
}
}
#[derive(Debug, Clone, Copy)]
pub struct MetricDef {
pub key: &'static str,
pub unit: &'static str,
pub kind: &'static str,
pub scope: &'static str,
pub reset: &'static str,
pub authority: &'static str,
}
pub const METRIC_REGISTRY: &[MetricDef] = &[
MetricDef {
key: "format.format_major",
unit: "version",
kind: "snapshot",
scope: "store",
reset: "never (on-disk)",
authority: "superblock format_major",
},
MetricDef {
key: "format.format_minor",
unit: "version",
kind: "snapshot",
scope: "store",
reset: "never (on-disk)",
authority: "superblock format_minor",
},
MetricDef {
key: "format.compat",
unit: "bitmask",
kind: "snapshot",
scope: "store",
reset: "never (on-disk)",
authority: "superblock compat",
},
MetricDef {
key: "format.ro_compat",
unit: "bitmask",
kind: "snapshot",
scope: "store",
reset: "never (on-disk)",
authority: "superblock ro_compat",
},
MetricDef {
key: "format.incompat",
unit: "bitmask",
kind: "snapshot",
scope: "store",
reset: "never (on-disk)",
authority: "superblock incompat",
},
MetricDef {
key: "format.io_backend",
unit: "enum (sync|uring)",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "StoreConfig.io_backend",
},
MetricDef {
key: "accounting.logical_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "Store::logical_bytes",
},
MetricDef {
key: "accounting.reachable_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "StoreStats.reachable_bytes",
},
MetricDef {
key: "accounting.physical_used_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "Store::physical_used",
},
MetricDef {
key: "accounting.physical_capacity_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "Store::physical_capacity",
},
MetricDef {
key: "accounting.physical_free_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "capacity − used (derived)",
},
MetricDef {
key: "accounting.object_count",
unit: "objects",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "ObjectIndex::len",
},
MetricDef {
key: "accounting.data_record_count",
unit: "records",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "StoreStats.data_record_count",
},
MetricDef {
key: "accounting.blob_count",
unit: "blobs",
kind: "snapshot",
scope: "engine",
reset: "at open",
authority: "engine blob-namespace directory scan (O(n))",
},
MetricDef {
key: "physical.live_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "physical_report (Phase-9H)",
},
MetricDef {
key: "physical.dead_indexed_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "physical_report (Phase-9H)",
},
MetricDef {
key: "physical.index_hidden_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "physical_report (Phase-9H)",
},
MetricDef {
key: "physical.unindexed_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "physical_report (Phase-9H)",
},
MetricDef {
key: "physical.torn_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "physical_report (Phase-9H)",
},
MetricDef {
key: "physical.zero_padding_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "physical_report (Phase-9H)",
},
MetricDef {
key: "physical.format_overhead_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "physical_report (Phase-9H)",
},
MetricDef {
key: "physical.unexplained_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "physical_report::unexplained",
},
MetricDef {
key: "gc.unreachable_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "refreshed by compact/gc/fsck",
authority: "StoreStats.unreachable_bytes (last-known)",
},
MetricDef {
key: "dsfb.tracked_chunks",
unit: "chunks",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "ShardedStorageObserver stats",
},
MetricDef {
key: "dsfb.steps",
unit: "events",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "ShardedStorageObserver stats",
},
MetricDef {
key: "dsfb.drift_events",
unit: "events",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "ShardedStorageObserver stats",
},
MetricDef {
key: "dsfb.slew_events",
unit: "events",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "ShardedStorageObserver stats",
},
MetricDef {
key: "dsfb.narrowed_searches",
unit: "searches",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "ShardedStorageObserver stats",
},
MetricDef {
key: "dsfb.candidates_evaluated",
unit: "candidates",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "Store::candidates_evaluated",
},
MetricDef {
key: "pressure.pressured",
unit: "flag",
kind: "snapshot",
scope: "store",
reset: "at open",
authority: "Store::pressure_state",
},
MetricDef {
key: "pressure.rans_skips",
unit: "extents",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "Store::focused_rans_skips",
},
MetricDef {
key: "pressure.deferred_extents",
unit: "extents",
kind: "snapshot",
scope: "store",
reset: "at completed background pass",
authority: "Store::deferred_debt",
},
MetricDef {
key: "pressure.deferred_logical_bytes",
unit: "bytes",
kind: "snapshot",
scope: "store",
reset: "at completed background pass",
authority: "Store::deferred_debt",
},
MetricDef {
key: "pressure.deferred_age_ms",
unit: "milliseconds",
kind: "snapshot",
scope: "store",
reset: "at completed background pass",
authority: "Store::deferred_debt",
},
MetricDef {
key: "pressure.samples",
unit: "samples",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "Store::pressure_trace",
},
MetricDef {
key: "pressure.enter_events",
unit: "events",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "Store::pressure_trace",
},
MetricDef {
key: "pressure.leave_events",
unit: "events",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "Store::pressure_trace",
},
MetricDef {
key: "pressure.pressured_time_ms",
unit: "milliseconds",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "Store::pressure_trace",
},
MetricDef {
key: "pressure.peak_deferred_bytes",
unit: "bytes",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "Store::pressure_trace",
},
MetricDef {
key: "pressure.debt_cap_engagements",
unit: "events",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "Store::pressure_trace",
},
MetricDef {
key: "cache.model_cache_hits",
unit: "objects",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "Store::model_cache_hits",
},
MetricDef {
key: "cache.model_cache_misses",
unit: "objects",
kind: "cumulative",
scope: "store",
reset: "at open",
authority: "Store::model_cache_misses",
},
MetricDef {
key: "write_path_phases[]",
unit: "ms (total) / µs (p50/p95/p99)",
kind: "snapshot+cumulative",
scope: "per-phase",
reset: "at open",
authority: "perf::Timings::snapshot",
},
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dto_json_roundtrip() {
let m = EngineMetrics {
schema_version: 2,
format: FormatInfo {
format_major: 1,
format_minor: 0,
compat: 0,
ro_compat: 0,
incompat: 0x8000,
io_backend: "sync".to_string(),
},
accounting: AccountingMetrics {
logical_bytes: 1024,
reachable_bytes: 512,
physical_used_bytes: 2048,
physical_capacity_bytes: 1 << 30,
physical_free_bytes: (1 << 30) - 2048,
object_count: 3,
data_record_count: 2,
blob_count: 1,
},
physical: PhysicalMetrics {
live_bytes: 512,
dead_indexed_bytes: 0,
index_hidden_bytes: 0,
unindexed_bytes: 0,
torn_bytes: 0,
zero_padding_bytes: 0,
format_overhead_bytes: 4,
unexplained_bytes: 0,
},
gc: GcMetrics {
unreachable_bytes: 0,
},
dsfb: DsfbMetrics {
tracked_chunks: 0,
steps: 0,
drift_events: 0,
slew_events: 0,
narrowed_searches: 0,
candidates_evaluated: 0,
},
pressure: PressureMetrics {
pressured: false,
samples: 0,
enter_events: 0,
leave_events: 0,
pressured_time_ms: 0,
rans_skips: 0,
deferred_extents: 0,
deferred_logical_bytes: 0,
deferred_age_ms: 0,
peak_deferred_bytes: 0,
debt_cap_engagements: 0,
},
cache: CacheMetrics {
model_cache_hits: 0,
model_cache_misses: 0,
},
write_path_phases: Vec::new(),
};
let json = m.to_json();
let back: EngineMetrics = serde_json::from_str(&json).unwrap();
assert_eq!(back, m);
}
#[test]
fn registry_is_nonempty_and_keyed() {
assert!(!METRIC_REGISTRY.is_empty());
for def in METRIC_REGISTRY {
assert!(!def.key.is_empty());
assert!(def.key.contains('.') || def.key.contains("[]"));
assert!(matches!(
def.kind,
"snapshot" | "cumulative" | "snapshot+cumulative"
));
assert!(!def.authority.is_empty());
}
}
}