diff --git a/crates/tracedecay-lcm/src/gc/orphan_scan.rs b/crates/tracedecay-lcm/src/gc/orphan_scan.rs index d94101775a..1e56aaeed4 100644 --- a/crates/tracedecay-lcm/src/gc/orphan_scan.rs +++ b/crates/tracedecay-lcm/src/gc/orphan_scan.rs @@ -7,6 +7,7 @@ use tracedecay_runtime_core::db::engine::Executor; use super::super::util; use super::{LcmError, LcmGcConfig, LcmGcReport, payload, stage_payload_delete}; +#[hotpath::measure(label = "sessions.lcm.gc.orphan_preview")] pub(super) fn preview_orphan_files( dir: &Path, metadata_refs: &BTreeSet, @@ -107,6 +108,7 @@ where candidates } +#[hotpath::measure(label = "sessions.lcm.gc.orphan_stage", future = true)] pub(super) async fn stage_orphan_files( conn: &(impl Executor + ?Sized), dir: &Path, diff --git a/crates/tracedecay-lcm/src/gc/pending_delete.rs b/crates/tracedecay-lcm/src/gc/pending_delete.rs index 54c4a8e51b..f68f52c7e2 100644 --- a/crates/tracedecay-lcm/src/gc/pending_delete.rs +++ b/crates/tracedecay-lcm/src/gc/pending_delete.rs @@ -76,6 +76,7 @@ pub(super) fn pending_payload_delete_key(payload_ref: &str) -> String { format!("{PENDING_PAYLOAD_DELETE_PREFIX}{payload_ref}") } +#[hotpath::measure(label = "sessions.lcm.gc.stage_delete", future = true)] pub async fn stage_payload_delete( conn: &(impl Executor + ?Sized), payload_ref: &str, @@ -113,6 +114,7 @@ pub async fn drain_pending_payload_delete_in_transaction( ) } +#[hotpath::measure(label = "sessions.lcm.gc.drain_pending_deletes", future = true)] async fn drain_pending_payload_deletes_matching( conn: &(impl Executor + ?Sized), storage_root: &Path, @@ -256,6 +258,7 @@ struct MetadataProbe { /// probe. Chunked at [`util::SQLITE_IN_BATCH_SIZE`] so an unbounded tombstone /// backlog cannot exceed SQLite's bind-variable limit; an empty input issues no /// query at all. +#[hotpath::measure(label = "sessions.lcm.gc.probe_pending_metadata", future = true)] async fn probe_metadata_rows( conn: &(impl Executor + ?Sized), payload_refs: &[String], diff --git a/crates/tracedecay-lcm/src/gc/placeholder_scan.rs b/crates/tracedecay-lcm/src/gc/placeholder_scan.rs index ce85ca5fa2..58b2a8a571 100644 --- a/crates/tracedecay-lcm/src/gc/placeholder_scan.rs +++ b/crates/tracedecay-lcm/src/gc/placeholder_scan.rs @@ -145,6 +145,7 @@ enum PlaceholderScanFlow { /// Aggregates every prefiltered candidate row. Callers that only need to know /// whether *one* row qualifies must use [`any_placeholder_text_row`] instead: /// this retains the full result in memory. +#[hotpath::measure(label = "sessions.lcm.gc.placeholder_scan", future = true)] pub(crate) async fn scan_placeholder_text_rows( conn: &(impl QueryExecutor + ?Sized), scope: PlaceholderScanScope<'_>, @@ -166,6 +167,7 @@ pub(crate) async fn scan_placeholder_text_rows( /// over what a match means; the early exit changes when the scan stops, never /// what it decides. An existence question about one payload therefore costs one /// page of candidates instead of the store's whole placeholder history. +#[hotpath::measure(label = "sessions.lcm.gc.placeholder_probe", future = true)] pub(crate) async fn any_placeholder_text_row( conn: &(impl QueryExecutor + ?Sized), scope: PlaceholderScanScope<'_>, @@ -258,6 +260,7 @@ async fn drive_placeholder_text_scan( } } +#[hotpath::measure(label = "sessions.lcm.gc.placeholder_count", future = true)] pub(crate) async fn count_placeholder_text_rows( conn: &(impl QueryExecutor + ?Sized), scope: PlaceholderScanScope<'_>, diff --git a/crates/tracedecay-lcm/src/maintenance.rs b/crates/tracedecay-lcm/src/maintenance.rs index e70ce76f76..9cc04e4e38 100644 --- a/crates/tracedecay-lcm/src/maintenance.rs +++ b/crates/tracedecay-lcm/src/maintenance.rs @@ -13,6 +13,7 @@ use super::{LCM_SCAN_PAGE_ROWS, LcmError}; static BACKUP_NONCE: AtomicU64 = AtomicU64::new(0); +#[hotpath::measure(label = "sessions.lcm.maintenance.backup", future = true)] pub(super) async fn backup_database( db_path: &Path, storage_root: &Path, @@ -111,6 +112,7 @@ pub(super) async fn payload_metadata_refs_for_scope( /// Collects payload-metadata references through `rowid` keyset pages: the /// whole `lcm_external_payloads` table exceeds what the `SQLite` runtime will /// materialize for one query on a long-lived profile. +#[hotpath::measure(label = "sessions.lcm.maintenance.scan_payload_refs", future = true)] async fn payload_metadata_refs( conn: &(impl QueryExecutor + ?Sized), provider: &str, diff --git a/crates/tracedecay-lcm/src/payload/delete_recovery.rs b/crates/tracedecay-lcm/src/payload/delete_recovery.rs index 6eeff6660a..97553e9d94 100644 --- a/crates/tracedecay-lcm/src/payload/delete_recovery.rs +++ b/crates/tracedecay-lcm/src/payload/delete_recovery.rs @@ -161,6 +161,7 @@ pub fn reconcile_committed_payload_drain( } } +#[hotpath::measure(label = "sessions.lcm.payload.delete", future = true)] pub(super) async fn delete_external_payload_in_transaction( conn: &(impl Executor + ?Sized), storage_root: &Path, @@ -181,6 +182,7 @@ pub(super) async fn delete_external_payload_in_transaction( Ok(prepared) } +#[hotpath::measure(label = "sessions.lcm.payload.delete_prepare", future = true)] pub(super) async fn prepare_external_payload_delete_in_transaction_with_cache( conn: &(impl Executor + ?Sized), storage_root: &Path, @@ -316,6 +318,7 @@ pub fn remove_committed_payload_file( ) } +#[hotpath::measure(label = "sessions.lcm.payload.remove_file")] pub fn remove_committed_payload_file_with( storage_root: &Path, payload_ref: &str, @@ -425,6 +428,7 @@ fn restore_quarantined_payload( fs::rename(quarantine, path).map_err(|error| LcmError::Io(error.to_string())) } +#[hotpath::measure(label = "sessions.lcm.payload.fingerprint")] pub fn payload_file_fingerprint( dir: &Path, payload_ref: &str, @@ -443,6 +447,7 @@ pub fn payload_file_fingerprint( )) } +#[hotpath::measure(label = "sessions.lcm.payload.tombstone_placeholders", future = true)] async fn tombstone_residual_placeholders( conn: &(impl Executor + ?Sized), payload_ref: &str, diff --git a/crates/tracedecay-lcm/src/query/describe.rs b/crates/tracedecay-lcm/src/query/describe.rs index c410aafcc5..254c816075 100644 --- a/crates/tracedecay-lcm/src/query/describe.rs +++ b/crates/tracedecay-lcm/src/query/describe.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use super::super::util::{SQLITE_IN_BATCH_SIZE, sql_in_placeholders}; use super::*; +#[hotpath::measure(label = "sessions.lcm.describe.raw_overviews", future = true)] pub(super) async fn raw_message_overviews( conn: &(impl QueryExecutor + ?Sized), provider: &str, @@ -39,6 +40,7 @@ pub(super) async fn raw_message_overviews( Ok(overviews) } +#[hotpath::measure(label = "sessions.lcm.describe.summary_overviews", future = true)] pub(super) async fn summary_overviews( conn: &(impl QueryExecutor + ?Sized), provider: &str, @@ -74,6 +76,7 @@ pub(super) async fn summary_overviews( Ok(overviews) } +#[hotpath::measure(label = "sessions.lcm.describe.summary_node", future = true)] pub(super) async fn describe_summary_node( conn: &(impl QueryExecutor + ?Sized), provider: &str, @@ -113,6 +116,7 @@ enum DescribeSource { Summary { node_id: String }, } +#[hotpath::measure(label = "sessions.lcm.describe.sources", future = true)] async fn describe_summary_sources( conn: &(impl QueryExecutor + ?Sized), provider: &str, @@ -265,6 +269,7 @@ async fn load_describe_summary_nodes( Ok(out) } +#[hotpath::measure(label = "sessions.lcm.describe.external_payload", future = true)] pub(super) async fn describe_external_payload( conn: &(impl QueryExecutor + ?Sized), provider: &str, diff --git a/crates/tracedecay-lcm/src/schema.rs b/crates/tracedecay-lcm/src/schema.rs index 8d8a04652f..bb566a9859 100644 --- a/crates/tracedecay-lcm/src/schema.rs +++ b/crates/tracedecay-lcm/src/schema.rs @@ -82,6 +82,7 @@ const RAW_FTS_DDL: &str = "CREATE VIRTUAL TABLE IF NOT EXISTS lcm_raw_messages_f /// Returns whether the raw-message FTS table and all three synchronization /// triggers use the v3 content-only contracts. +#[hotpath::measure(label = "sessions.lcm.schema.verify_raw_fts", future = true)] pub async fn raw_fts_structure_is_current(conn: &(impl QueryExecutor + ?Sized)) -> Option { let mut rows = conn .query( @@ -164,6 +165,7 @@ fn compact_sql(sql: &str) -> String { /// explicit schema initialization/rebuild owner; idempotent and data-preserving /// because the index is derived entirely from the content table. Doctor never /// invokes this mutation. +#[hotpath::measure(label = "sessions.lcm.schema.rebuild_raw_fts", future = true)] pub async fn rebuild_raw_fts(conn: &(impl Executor + ?Sized)) -> Option<()> { conn.execute_batch( "DROP TRIGGER IF EXISTS lcm_raw_messages_fts_insert; @@ -218,6 +220,7 @@ pub enum LcmSchemaAdmission { /// explicit profile reset. Admission callers run this before other schema /// authorities so the truthful LCM state is surfaced rather than masked by a /// coarser authority's reset. +#[hotpath::measure(label = "sessions.lcm.schema.admit", future = true)] pub async fn require_admissible_lcm_schema( conn: &(impl QueryExecutor + ?Sized), ) -> Result { @@ -239,6 +242,7 @@ pub async fn require_admissible_lcm_schema( } } +#[hotpath::measure(label = "sessions.lcm.schema.ensure", future = true)] pub async fn ensure_lcm_schema_in_transaction( conn: &(impl Executor + ?Sized), ) -> Result<(), LcmError> { @@ -544,6 +548,7 @@ pub async fn clear_gc_meta(conn: &(impl Executor + ?Sized), key: &str) -> Result Ok(()) } +#[hotpath::measure(label = "sessions.lcm.raw.load_message", future = true)] pub async fn load_raw_message( conn: &(impl QueryExecutor + ?Sized), provider: &str,