Repository navigation
Bucket the blocking-trend reads: lock waits, waiting tasks, blocked sessions (#4349) - #4362
Merged
Merged
Conversation
…essions (#4234) (#4349) GetLockWaitTrendAsync, GetWaitingTaskTrendAsync, and GetBlockedSessionTrendAsync returned one row per collection for both products, unbucketed at the 7-day window unlike #4353's (Darling) and #4340's (Lite) already-bucketed twins for the other trend charts. Each now buckets to TrendBudget.Chart's per-series point budget via TrendBuckets.AutoMinutes (date_bin on Darling, time_bucket on Lite, both anchored to the shared bucket origin), stamps points at their own raw collection time instead of the bucket grid when every returned bucket holds exactly one physical collection, and carries the #3540 unrated-collection rule for the lock-wait rate (nulled into a rated CTE, not filtered, so collection_count still counts an unrated row). Waiting-task duration and blocked-session count have no interval-based delta to rate (a waiting-task row is a point-in-time snapshot, not a counter), so every row in those two reads is unconditionally "rated" and collection_count is a plain COUNT(*). Darling: ViewerDataService.BlockingTrends.cs. Lite: LocalDataService.Blocking.cs, LocalDataService.WaitingTasks.cs.
…double-count Adds source-check and live-store tests for the lock-wait, waiting-task and blocked-session trend reads, mirroring ViewerCpuTempDbTests (#4234) and LiteMemoryFileIoTrendBucketingTests (#4340): a 7-day row-budget cap, point equality for the rate/count formulas, and singleton-window raw-timestamp stamping, for both products. Fixes a defect the tests surfaced: BlockedSessionTrendSql/its Lite twin summed a per-snapshot gauge (COUNT(*) blocked sessions) across every merged collection in a bucket, double- (or N-tuple-) counting purely because a wide bucket merged more snapshots, with no more blocking having happened. Both reads now average the per-collection count over the merged bucket (matching the CPU tab's gauge-averaging idiom), via a per_collection CTE that keeps the un-bucketed read's own count unchanged. Refs #4349.
…#4349) BlockedSessionTrendSql_CarriesABucketWidth test asserted no COUNT(*) AS blocked_count anywhere in the SQL, but the inner per_collection CTE legitimately keeps that per-snapshot COUNT(*) - it's what the outer AVG averages. Scoped the assertion to the outer SELECT (after the CTE closes) instead of the whole SQL text. LockWaitTrendSql_FiltersLckPrefix_PerSecondRateViaLag pinned the old per-row "delta_wait_time_ms / interval_seconds" text. The bucketed SQL now computes the same per-second rate through a time-weighted rated CTE (SUM(rated_wait_ms) / SUM(rated_seconds)), matching WaitStatsTrendsSql's existing idiom. Updated the pin to the new text and kept every behavioural assertion.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #4349.
Why
The BLOCKING trio of trend charts read one row per collection at the 7-day window, unbucketed unlike #4353's (Darling) and #4340's (Lite) twins for the other trend charts. The issue's own measured 7-day row counts at 1-minute cadence: Lock waits 20,160; Waiting tasks 30,240; Blocked sessions 20,160.
Measurement was not completed inside this lane's 30-minute limit (build/test priority came first, per the brief's own ordering). The before/after row counts on a live rig are deferred to a follow-up comment or a sibling lane; the code change is proven by build and by the same bucketing shape #4353/#4340 already ship.
What changes
Darling (
ViewerDataService.BlockingTrends.cs):LockWaitTrendSql/GetLockWaitTrendAsync: bucketed viadate_bin,TrendBuckets.AutoMinutesper wait type (series). The Measurement-layer campaign: the delta honesty contract (11 findings, one keystone) #3540 "no delta knowable" rule is carried into aratedCTE (nulled, not filtered) socollection_countstill counts an unrated row.WaitingTaskTrendSql/GetWaitingTaskTrendAsync: bucketed the same way. A waiting-task row has no delta/interval, so every row is unconditionally "rated";collection_countis a plainCOUNT(*).BlockedSessionTrendSql/GetBlockedSessionTrendAsync: bucketed the same way, same "every row rated" note, plus the existing database filter parameter (now$4, bucket width moved to$5).first_collection_timeinstead of thebucket_startgrid line, matching Bucket the Darling viewer's TempDB file I/O trend (#4234) #4353/WPF trend charts never adopted the #3897/#3960 bucket contract: at the "Last 7 days" window one chart reads 85–170 k raw rows, and the pickers re-run a week-long DISTINCT every refresh #4234's rule.Lite (
LocalDataService.Blocking.cs,LocalDataService.WaitingTasks.cs):GetLockWaitTrendAsync: SQL pulled into a namedLockWaitTrendSqlstring (matching Bucket Lite's memory clerk and File I/O trend reads (#4234) #4340's pattern for checkability), bucketed viatime_bucket/to_minutes/TrendBuckets.OriginSql, same rated-CTE and singleton-stamping rules as Darling.GetWaitingTaskTrendAsync/GetBlockedSessionTrendAsync: bucketed inline (matching the reads' existing dynamic-SQL style for the ignore-list/database-filter clauses), same "every row rated" and singleton-stamping rules.No new shared helper: every read reuses
TrendBuckets/TrendBudget(already shared by both SKUs) and keeps its bucket expression local, per the ruling.Test plan
dotnet build Darling/Darling.Tests/Darling.Tests.csproj -p:EnableWindowsTargeting=true— 0 Warning(s), 0 Error(s)dotnet build Lite.Tests/Lite.Tests.csproj -p:EnableWindowsTargeting=true— 0 Warning(s), 0 Error(s)ViewerCpuTempDbTests/LiteMemoryFileIoTrendBucketingTests(deferred — not added in this lane; listed unchecked per the brief's priority order)CHANGELOG entry
SECTION: Fixed
ENTRY:
REF:
[Bucket the blocking-trend reads: lock waits, waiting tasks, blocked sessions (#4349) #4362]: Bucket the blocking-trend reads: lock waits, waiting tasks, blocked sessions (#4349) #4362
For the coordinator
PerformanceMonitor.Darling.Storage,timescale/timescaledb:2.30.1-pg18on port 55471) would confirm the counts before marking this ready.ViewerCpuTempDbTests/LiteMemoryFileIoTrendBucketingTests) are not yet added. Both would assert: unbucketed SQL returns one row per collection per series at a 7-day/1-minute seed (fails the "coarsens at wide windows" expectation); bucketed SQL groups bydate_bin/time_bucketand returns far fewer rows; a single-collection window stamps points at the raw collection time, not the bucket grid.ViewerDataService.OverviewLanes.cs/ViewerServerTab.Blocking.cscallers were not touched — they already pass(serverId, startUtc, endUtc)and don't post-filter onendUtcclient-side (unlike the Bucket the Darling viewer's TempDB file I/O trend (#4234) #4353LoadTempDbAsyncfix), so no caller-side change was needed. Same check on Lite'sServerTab.Refresh.cscall sites — no post-filtering there either.pm-pr lane report (tests)
Head after this lane:
96318d76(mergedorigin/devin, keeping both sides — no conflicts).Lite-parity check (coordinator's follow-up): the Lite twins were already present in this PR's 3-file diff —
Lite/Services/LocalDataService.Blocking.cs(GetLockWaitTrendAsync) andLite/Services/LocalDataService.WaitingTasks.cs(GetWaitingTaskTrendAsync,GetBlockedSessionTrendAsync), both bucketed in DuckDB'stime_bucket/to_minutesshape. Nothing to add.Tests added, mirroring
ViewerCpuTempDbTests(#4234) /LiteMemoryFileIoTrendBucketingTests(#4340):Darling/Darling.Tests/ViewerBlockingTrendBucketingTests.cs: a source check per read (bucket-width parameter,date_bin/GREATEST, the Measurement-layer campaign: the delta honesty contract (11 findings, one keystone) #3540 rated-CTE no-delta rule for lock waits, plainCOUNT(*)-then-CAST(SUM...)for waiting-task duration, and the new per-collection-then-AVGshape for blocked-session count) plus 8 live-Postgres tests (gated onDARLING_TEST_PG,[Collection("live-postgres")]): a 7-day/1-minute-cadence row-budget cap and a budget-covers-every-collection raw-timestamp/point-equality pin for each of the three reads, plus a merged-bucket average-not-sum pin for blocked sessions.Lite.Tests/LiteBlockingTrendBucketingTests.cs: the matching source check plus 7 live-DuckDB tests againstSharedDuckDbFixture([Collection("server-time-helper")],ServerTimeHelper.UtcOffsetMinutespinned to 0) — same budget-cap / singleton-stamping / merged-bucket-average coverage for all three reads.RED/GREEN evidence: unchecked. The test projects are
net10.0-windowsand this lane's host is macOS — WPF-hosted xunit can't run here (confirmed:dotnet execon the built DLL fails with "No frameworks were found,"Microsoft.WindowsDesktop.Appisn't installed). I did not stand up the dockertimescale/timescaledb:2.30.1-pg18throwaway harness in the time this follow-up left; CI's Windowsbuildjob is the first real run of both new files. Both projects build locally with 0 Warning(s), 0 Error(s).SQL defect found and fixed (in-lane):
BlockedSessionTrendSql(and its Lite twin) computedCOUNT(*) AS blocked_countover the bucket's rawwaiting_tasksrows. A blocked-session count is a PER-SNAPSHOT gauge, not a delta — the un-bucketed read'sCOUNT(*)was already "sessions blocked at this one collection." Bucketing by summing that count across every collection a wide bucket merges double- (or N-tuple-) counts purely from how many snapshots got merged, with no more blocking having happened — the same shape as the CPU tab's gauge columns (#4234), which the PR's own doc comments already correctly averaged. Fixed both reads to keep the un-bucketed per-collection count in an inner CTE/subquery, thenAVG(rounded,CAST/ROUNDto bigint on Postgres) it across the merged collections — neverSUM.collection_countstill counts the merged collections viaCOUNT(*)over that CTE. Covered by the new merged-bucket tests in both files.Left for pm-pr to check by hand: the RED/GREEN Docker proof (item 4 of the brief) and the full Windows suite — both need CI or a Windows/WSL host. The before/after row-count measurement is explicitly out of this lane's scope per the brief (a separate lane's job).
pm-pr: measured before/after
Darling, measured live (docker TimescaleDB 2.30.1-pg18, a fresh migrated store,
generate_seriesat each collector's cadence, one server, 7-day window; dev's SQL vs this PR's SQL at 80507a2, run verbatim): Lock waits 20,160 → 2,016; Waiting tasks 30,240 → 3,024; Blocked sessions 20,160 → 2,016 (10-minute buckets). The lane's later blocked-sessions averaging fix changes the value, not the row count. Lite: computed, not run (no DuckDB on the measuring host); the expectation is the same 2,016 / 3,024 / 2,016.pm-pr lane report (CRLF locator fix)
New head: 9980f73
Test fixed: Darling.Tests.ViewerBlockingTrendBucketingSqlTests.BlockedSessionTrendSql_CarriesABucketWidth_AndAveragesThePerSnapshotCount_NeverSums
Pattern: sql.ReplaceLineEndings("\n") before the ")\n SELECT" locator search (house pattern, matches ReplaceLineEndings usage elsewhere in Darling.Tests); scanned branch diff for other \n-joined multi-line locators, found none else.
pm-pr lane report (CI pin fixes, assigned to pm-worker)
Both failing tests were mis-aimed pins, and the SQL is unchanged: the
NeverSumsDoesNotContain is now scoped to the outer select (the inner per-collection CTE rightly counts), and theLockWaitTrendSqlpin now asserts the rated-CTE CASE expressions and the time-weighted SUM/SUM. Dev's per-row rate already excluded non-positive intervals and negative deltas, so single-collection results are unchanged.