#[cfg(feature = "sql")]
use super::SqlCompileRejectPhase;
use super::{
CacheKind, CacheMissReason, CacheOutcome, ExecKind, ExecOutcome, MetricsEvent,
event_is_observable, record,
};
use std::rc::Rc;
pub(crate) struct PathSpan {
kind: ExecKind,
entity_path: Option<Rc<str>>,
start: u64,
rows: u64,
outcome: ExecOutcome,
finished: bool,
}
#[cfg_attr(
not(target_arch = "wasm32"),
expect(
clippy::missing_const_for_fn,
reason = "host metrics counter stub intentionally mirrors the wasm runtime hook"
)
)]
fn read_perf_counter() -> u64 {
#[cfg(target_arch = "wasm32")]
{
crate::runtime::performance_counter(1)
}
#[cfg(not(target_arch = "wasm32"))]
{
0
}
}
pub(crate) fn record_cache_event_for_path(
kind: CacheKind,
outcome: CacheOutcome,
entity_path: &str,
) {
if !event_is_observable() {
return;
}
record(MetricsEvent::Cache {
entity_path: entity_path.into(),
kind,
outcome,
});
}
pub(crate) fn record_cache_miss_reason_for_path(
kind: CacheKind,
reason: CacheMissReason,
entity_path: &str,
) {
if !event_is_observable() {
return;
}
record(MetricsEvent::CacheMissReason {
entity_path: entity_path.into(),
kind,
reason,
});
}
#[cfg(feature = "sql")]
pub(crate) fn record_sql_compile_reject_for_path(phase: SqlCompileRejectPhase, entity_path: &str) {
if !event_is_observable() {
return;
}
record(MetricsEvent::SqlCompileReject {
entity_path: entity_path.into(),
phase,
});
}
pub(crate) fn record_prepared_shape_already_finalized_for_path(entity_path: &str) {
if !event_is_observable() {
return;
}
record(MetricsEvent::PreparedShapeAlreadyFinalized {
entity_path: entity_path.into(),
});
}
pub(crate) fn record_cache_entries(kind: CacheKind, entries: usize) {
if !event_is_observable() {
return;
}
let entries = u64::try_from(entries).unwrap_or(u64::MAX);
record(MetricsEvent::CacheEntries { kind, entries });
}
impl PathSpan {
#[must_use]
pub(crate) fn new(kind: ExecKind, entity_path: &str) -> Self {
if !event_is_observable() {
return Self {
kind,
entity_path: None,
start: 0,
rows: 0,
outcome: ExecOutcome::Aborted,
finished: true,
};
}
record(MetricsEvent::ExecStart {
kind,
entity_path: entity_path.into(),
});
Self {
kind,
entity_path: Some(entity_path.into()),
start: read_perf_counter(),
rows: 0,
outcome: ExecOutcome::Aborted,
finished: false,
}
}
pub(crate) const fn set_rows(&mut self, rows: u64) {
self.rows = rows;
self.outcome = ExecOutcome::Success;
}
#[cfg(test)]
pub(super) const fn owns_entity_path(&self) -> bool {
self.entity_path.is_some()
}
#[cfg(test)]
pub(super) const fn is_finished(&self) -> bool {
self.finished
}
fn finish_inner(&self) {
let Some(entity_path) = self.entity_path.as_ref() else {
return;
};
let now = read_perf_counter();
let delta = now.saturating_sub(self.start);
record(MetricsEvent::ExecFinish {
kind: self.kind,
entity_path: Rc::clone(entity_path),
rows_touched: self.rows,
inst_delta: delta,
outcome: self.outcome,
});
}
fn finish(&mut self) {
if !self.finished {
self.finish_inner();
self.finished = true;
}
}
}
impl Drop for PathSpan {
fn drop(&mut self) {
self.finish();
}
}