Repository navigation
Darling.Tests: the WaitRate read-count pin counts in-process instead of through evictable pg_stat_statements; the test rig recipe preloads it - #4697
Merged
Conversation
…ling-pg job does The lane-orders rig recipe wrote shared_preload_libraries = 'timescaledb' only. The darling-pg job in .github/workflows/build.yml writes 'timescaledb,pg_stat_statements'. A rig without pg_stat_statements skips WaitRateTileReadCountLiveTests (and the other live tests that count statements through it) instead of running them, so a green local run proves less than CI's.
…gh cluster-wide pg_stat_statements The test passed alone and failed once in a full-suite run. pg_stat_statements is one cluster-wide table of 5000 entries that the parallel scratch-database classes refill within seconds, evicting the oldest once-called statements first. Measured: the window entry was present with calls = 1 right after the detector and gone 15 s later (dealloc 326 to 370), so the count read 0 with the seed intact. The count now comes from an ActivityListener on Npgsql's ActivitySource, scoped to the test's own scratch database by name and to the window SQL's fragments, with a control command that proves the listener sees both before the count is trusted. Assert.Equal(1, calls) is unchanged. The preload skip, CREATE EXTENSION, the reset and the oid helper are gone because nothing reads pg_stat_statements any more.
…eadcount-isolation
… census's 25-line lookback The rewritten class comment pushed the #1776 own-store marker more than 25 lines above the class declaration, so LivePostgresCollectionHygieneTests.EveryClassUsingTheSharedStore_IsSerializedOrDocumentsWhyNot failed in the full-suite run. The marker now sits in the last paragraph of the comment.
…ents WaitRateTileReadCountLiveTests no longer reads pg_stat_statements, so it is the wrong example for the note that a rig without the preload skips the tests that count statements through it. StoreSizeCacheLiveTests still counts its statements there and skips when the library is not preloaded.
erikdarlingdata
marked this pull request as ready for review
September 29, 2026 01:25
erikdarlingdata
deleted the
fix/darling-waitrate-readcount-isolation
branch
September 29, 2026 01:36
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.
No issue was filed for this.
WaitRateTileReadCountLiveTests.Waits_DetectAnomaliesAsync_ReadsWaitRateTileWindowSqlOnce_NotTwicepasses alone on a fresh database and failed once in the full-suite run of #4681; nobody recorded the count it read.Why
The test pins that
PgAnomalyDetectorreads the wait-rate window SQL once per pass, and it counted those reads throughpg_stat_statements. That view is one cluster-wide table ofpg_stat_statements.max= 5000 entries. Every parallel class that replays the migrations into its own scratch database refills it within seconds (utility tracking is on, so each DDL statement is an entry). Each time it is full it evicts the 250 lowest-usage entries, oldest once-called statements first. Once the test's entry is evicted the count reads 0, so the pin can fail with the product doing nothing wrong.The local PostgreSQL test-rig recipe also listed
shared_preload_libraries = 'timescaledb', while CI'sdarling-pgjob (the "Initialize and start throwaway PostgreSQL" step inbuild.yml) writes'timescaledb,pg_stat_statements'. A rig without it skips this test instead of running it.What changes
WaitRateTileReadCountLiveTestscounts the window reads in-process. AnActivityListeneron Npgsql'sNpgsqlActivitySourcecounts the commands run against this test's own scratch database (its name is unique to the test) whose text carries the window SQL's fragments (peak_ms_per_sec,v_wait_stats). Tags are matched by value, not by name, the waySharedBaselineCacheTests.CaptureAsyncalready finds command text, because Npgsql's attribute names have changed between majors.Assert.Equal(1, calls)is unchanged. No retry, no wider tolerance, no skip added.pg_stat_statementsany more: theshared_preload_librariesskip,CREATE EXTENSION, the per-databasepg_stat_statements_reset, and the database-oid lookup.NpgsqlDataSource:PgAnomalyDetector(10 sites) andPgBaselineProvider(1 site) open connections only through_postgres.OpenConnectionAsync, and nothing inPerformanceMonitor.Darling.AnalysiscallsNpgsqlDataSource.Create,NpgsqlDataSourceBuilderornew NpgsqlConnection. The database-name filter would also count a read through a second data source.pg_stat_statementsbesidetimescaledb, as CI'sdarling-pgjob does, and says why.Measured before the change (local PostgreSQL 18.6, UTC,
pg_stat_statements.max= 5000,track_utilityon)Two temporary copies of the old test logged
callsandpg_stat_statements_info.dealloc(before, right after the detector, after the count), run with the heavy scratch-database classes (FrozenRollupLiveTests,PgDeadlockRemaskTests,RollupBackfillLiveTests,PgSettingScrubLiveTests,FleetSweepStoreLivePostgresTests,ServerWatermarkCacheRunnerLiveTests,QueryStoreCorrectedRollupLiveTests,JobHistoryWatermarkEpochLiveTests) and, for the last two rows, a second process running eight more heavy classes. The copies are not committed.deallocrising.calls= 2, so there is no sign of a double read in the product.Test plan
deallocrose 654 to 1034 during the run. A temporary copy of the fixed test with a 15 s pause before the count was in that run and passed (the old shape read 0 under the same pause).WaitRateTileWindowSqlcommand inDetectWaitAnomalies, and the test failed withExpected: 1,Actual: 2. Reverted withgit restore; the product file is not in this diff.Darling.Testssuite once, on a freshdarlingtest, before the last commit: Total 16750, Failed 2, Skipped 64, Not Run 1, 909 s. Both failures are listed below.LivePostgresCollectionHygieneTests,WaitRateTileReadCountLiveTests,TrendPayloadBudgetLiveTests,LiveCleanupConversionRatchetTestsand the doc-comment census, on a fresh database: 105 tests, 1 failed (the trend test below).Failures in the full run:
LivePostgresCollectionHygieneTests.EveryClassUsingTheSharedStore_IsSerializedOrDocumentsWhyNot: caused by this change. The longer class comment pushed the#1776 own-storemarker out of the census's 25-line lookback above the class. Fixed in the second commit by moving the marker to the comment's last paragraph; it passes now.TrendPayloadBudgetLiveTests.EveryDefaultAnswer_StaysNearTheBudget_AndTheLargestAnswerStaysUnderTheCap:get_pg_io_trend over 72h answered a error ... Exception while reading from stream. Not caused by this change: it fails the same way (same message, 42 s) alone on a fresh database, and again on an unmodified build oforigin/devon this machine, while dev's own CI run for the same base commit (872e7c9) passes it. The cause on this machine was not investigated.CHANGELOG
None: test-only change.
Worth a second look
pg_stat_statementsread and share the eviction exposure:OverviewFleetHealthSingleFlightLiveTests(line 132),QueryStoreTrendRoutingCachedLiveTests(line 139) andStoreSizeCacheLiveTests(line 94). Not converted here.