Skip to content

Say that the recorded-size read's cheapness is incidental, and on which axis that differs (#3199 follow-up) - #3215

Merged
erikdarlingdata merged 1 commit into
devfrom
fix/3199-followup-incidental-index-note
Sep 9, 2026
Merged

Say that the recorded-size read's cheapness is incidental, and on which axis that differs (#3199 follow-up)#3215
erikdarlingdata merged 1 commit into
devfrom
fix/3199-followup-incidental-index-note

Conversation

@erikdarlingdata

Copy link
Copy Markdown
Owner

Follow-up to #3203 (#3199). Comment-only — twenty added lines of doc comment on StoreSelfMetrics.LatestStoreSizeSql, no code change.

Why it is its own PR

The review bot on #3203 raised a non-blocking finding I agreed with, and I committed the disposition to the branch. #3203 merged at 6f6e2f5b before that commit was pushed, so the commit landed on a branch whose PR was already closed — and a closed PR dispatches no pull_request workflows, so it sat on the remote with zero check-runs and no path into dev. Cherry-picked onto current dev here so it actually gets CI and actually lands.

Worth naming because the emptiness reads as a pass: a "no check failed" filter over zero check-runs returns "none failed". The tell is the distinct-name count, which was 0, not 8.

The finding, verified in source

idx_store_metrics_time (V53) indexes (metric_time) alone, and every row one StoreSelfMetrics.SweepAsync run writes carries the same metric_time — one utcNow stamps all of them, deliberately, so a run's rows join. So ORDER BY metric_time DESC LIMIT 1 WHERE object_kind = 'store' reaches the whole-store row early only because StoreInsertSql happens to run last in the sweep, not because the query says so. The EXPLAIN (ANALYZE, BUFFERS) in #3203 came back at three buffers, which is that ordering holding rather than the query guaranteeing anything. Reordering the sweep, a VACUUM or a REINDEX could make the scan step past the tied group first.

One correction to the magnitude, in the direction that supports the finding: the tied group is larger than the ~30 rows/hour figure that file's own retention note quotes, which predates the background-job rows. TimescaleSupport.HypertableCount is 70 today (read off the shipped constant, not counted by eye), plus one row per Timescale background job, plus two dimension rows, plus this one.

Why it is documented rather than fixed

The growth axis, not the magnitude. pg_database_size tracked the store's file count, which retention span and ingest rate grow without anything choosing to — that is what turned an 806x margin into 1.57x with no code change and nothing noticing, which is #3199. The tied group tracks the collector catalog, which moves only when a migration rung adds a hypertable: a product constant, changed deliberately, in a commit someone reviews. Both are "cheap today"; only one gets more expensive while nobody is looking.

A composite (object_kind, metric_time DESC) index would make it exact and is the right follow-up. It needs a migration rung, and claiming a rung number alongside unmerged sibling branches is its own hazard here — a collision is loud, a gap is silent and unrepairable — so it does not belong bundled into either this note or the change that removed the unbounded read.

What this PR buys is that an incidental property is written down as incidental. The query previously read as though the index guaranteed its own cheapness.

Verification

Comment-only, so the guard that matters is doc hygiene: DocCommentHygieneTests' cref and summary-block rules, 28 tests, 0 failed, run against the real shipped file through a net10.0 xunit.v3 harness (the suite targets net10.0-windows and cannot run on macOS). #3199's own pins re-run clean on this branch too — 54 tests, 0 failed, 0 not run. PerformanceMonitor.Darling.Storage and Darling.Tests both compile with -p:EnableWindowsTargeting=true.

No mutation table: there is no behaviour to mutate. The added <para> blocks are prose, and the two things about them that can be mechanically wrong — an unresolvable cref and a stacked <summary> — are what those 28 tests check. The nested-<para> typo the first draft had was caught by exactly that route.

CHANGELOG

Not edited, per the standing rule. This is a comment on a change already described by #3199's entry, so it needs no entry of its own — the reasoning belongs in the code, which is where it now is.

…ch axis that differs

Review finding, verified: every row one SweepAsync run writes carries the same
metric_time by design, and idx_store_metrics_time indexes (metric_time) alone -
so the backward scan reaches the whole-store row early only because
StoreInsertSql happens to run last, not because the query says so. Measured 3
buffers on a 225 GiB store, which is that ordering holding.

Accepted rather than fixed here, and the reason is the growth axis rather than
the magnitude. The tied group is one sweep's output - TimescaleSupport.HypertableCount
(70 today) plus one row per background job plus two dimensions plus this one -
so it tracks the collector catalog, a product constant that moves only when a
rung adds a hypertable. pg_database_size tracked the store's file count, which
retention span and ingest grow without anything choosing to.

A composite (object_kind, metric_time DESC) index is the right follow-up. It
needs a migration rung, and claiming a rung number alongside unmerged siblings
is its own hazard, so it is not bundled into the change that removed the
unbounded read.
@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown

Reviewed. This is a pure XML-doc addition to LatestStoreSizeSql's summary — no code, SQL, or behavior change — so most review dimensions (correctness, Lite/Darling parity, security, performance) don't apply here; there's no Lite counterpart for a Darling-internal store-metrics doc comment to drift from.

Spot-checked the factual claims against source, all confirmed:

  • idx_store_metrics_time (V53, PgMigrations.cs:1110) does index (metric_time) alone.
  • SweepAsync (StoreSelfMetrics.cs:311-358) does run StoreInsertSql after the hypertable/job/dimension inserts and before the retention delete — "runs last in the sweep" is accurate.
  • TimescaleSupport.HypertableCount and the other <see cref> targets all resolve.
  • The "documented hazard" callout for claiming a migration rung number alongside unmerged siblings matches CONTRIBUTING.md's rung-numbering section (collision vs. silent/unrepairable gap) almost verbatim.

No issues found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant