Skip to content

database_size_stats swallows per-database file-space failures in an empty CATCH #1851

Description

@erikdarlingdata

Found while implementing #1837's probe-failure contract, and deliberately left out of that PR.

DatabaseSizeStatsCollector's per-database cursor (PerformanceMonitor.Collectors/DatabaseSizeStatsCollector.cs, around the #file_space INSERT) runs [db].sys.sp_executesql inside a TRY and discards every failure:

    END TRY
    BEGIN CATCH
    END CATCH;

It is the same swallow shape #1837 closed for the enumerating collectors, with the same consequence: a database that is mid-restore, offline, or inaccessible to the login contributes no used_size_mb rows, the collector reports SUCCESS, and nothing anywhere says a database was skipped. Unlike the other empty CATCHes in this project (ServerPropertiesCollector, BlockedProcessReportCollector) this one is undocumented and drops whole rows rather than leaving one enrichment column NULL.

Why it was not fixed in #1837's PR. The contract that PR shipped is EnumeratedCollectorDriver.ReadEnumerationAsync: an ENUMERATION query may return an optional second result set of (item_name, error_text), which both runners read and summarize onto the collection_log row. database_size_stats is not an enumerating collector — it runs on the plain single-query path, where the one result set IS the payload that ICollectorDefinition.ReadAsync consumes. Giving that path a probe-failure channel means either

  • extending ReadAsync's contract so the plain path also calls NextResult after the payload (touches every definition's read contract, and needs a rule for the collectors that already use a supplemental query), or
  • having the collector fold the failures into its own payload rows (needs a sentinel row shape, which then has to be filtered out of every read of database_size_stats).

Both are design decisions, not a mechanical mirror of what #1837 shipped.

Scope when picked up: decide the plain-path channel, apply it to database_size_stats, and audit the other non-enumeration cursors for the same shape. The note/summary/log plumbing already exists (EnumeratedCollectorDriver.BuildNote, ProbeFailureLogTemplate, and the last_note / note_count columns on all three Collection Health reads) — only the collector-to-runner channel is missing.

Applies to both Lite and Darling (shared collector definition).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions