Repository navigation
Darling collects each database's forced plans every 5 minutes (#5632) - #6069
Merged
Merged
Conversation
added 4 commits
October 18, 2026 11:48
Owner
Author
|
Claude posting for Erik Darling. Fix round on the 10 failures from the seat's full run at Result: after the fixes, 25 pattern groups (every class that names a file I changed, plus the migration, rung-rewind, schema generator, provision-roles ACL and alert-read-surface classes) ran in the VM with
The first VM run on Deferred and follow-upsNone. |
erikdarlingdata
marked this pull request as ready for review
October 18, 2026 19:34
… to six, the forced-plans collector in Darling only (#5632)
13 of 15 tasks
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.
Part of #5632.
Why
The Query Store collector reads only plans that ran since its last pass, so a forced plan the engine ignores, or that never runs, never reaches the store. Later steps of #5632 need the state of every force. This PR is step 1: the store gets the forced plans themselves. The state read (WORKING, NOT_EXERCISED, IGNORED, FAILING, REMOVED) is not built yet. See Deferred. The seat ships this collector half on its own, so that the V195 rung lands before the next rung (#5632 step 5) and the table gathers history before its read exists. A new lane builds steps 3 and 4.
What changes
query_store_forced_plans, every 5 minutes, 30 days retention (QueryStoreForcedPlansCollector.cs, modelled onplan_correction). Per database it readssys.query_store_planwhereis_forced_plan = 1:plan_id,query_id,query_plan_hash,plan_forcing_type(gated to SQL Server 2017+ and Azure),force_failure_count,last_force_failure_reason(NULL when NONE),last_execution_time,last_compile_start_time(both UTC). It never reads plan XML. It is capped at 500 rows per database and setsCommandTimeout120 s and a 120 s per-server wall-clock budget.query_store: the same vendor-name screen, AG-primary rule and scope filter. The Query Store state check runs inside each database's own statement. Azure SQL DB has the per-database branch.collect.query_store_forced_plansplus index(server_id, collection_time), identical to the generator's output.SchemaVersion195, viewer probe arm andRungRewindArtifactsentry added. No grant needed (thecollectschema carries blanket SELECT).provision-roles.sqlandDarlingManagedRoles.csare untouched.StaysPlainTable, likeattention_events): a few rows per database per pass, so the grid stays at 72 hypertables and no worker-sizing numbers move. Retention is the existing time-sliced DELETE.ICollectorSchemaInfo.IsDarlingOnly(default false). Lite'sStoredCollectorsskips it, so Lite creates no table and lists no schedule row. The Lite twin is under Deferred.DarlingWorkerdispatch,ServerHealthBandsuser-database enumerator list. NoCollectorEngineCapabilitycapture-path entry: the version gate is inside the collector's own SQL, andCollectorEngineCapabilityTestsaccepts only entries gated in the capability map. Counts and docs:PgSchemaGeneratorTests73,llms.txtandDarling/README.md44 SQL Server / 73 total,ConsumedTimestampFrameDisciplineTests(two UTC columns), the two empty-enumeration inventory tests,AttentionPlainTableTestsopt-out census.QueryStoreForcedPlansCollectorTests:is_forced_plan = 1, carries the marker row and sets a command timeout.Where the writer is:
DarlingWorkerdispatchquery_store_forced_plansrunsQueryStoreForcedPlansCollectorthrough the normal runner, so the rows are written by the running service. The reader (get_forced_plans) is not written yet.Test plan
VM_PG=1) at19f43c922:Darling.Tests Total: 34090, Errors: 0, Failed: 10, Skipped: 182. Full Lite.Tests at the same head:Lite.Tests Total: 10703, Errors: 0, Failed: 0, Skipped: 5.bed1a5ab3, comment below): 9 of the 10 were census pins the new collector joined, and one was a defect in the version-gate pin (its test context set no engine version). The database scope was already applied byBuildEnumerationQuery, and a pin now holds it.RollupFloorCacheLiveTestspassed twice in the fix round and is not changed. Fix round VM run withVM_PG=1:Darling.Tests Total: 325, Errors: 0, Failed: 0, Skipped: 0.origin/dev(da7cf8832) merged.bed1a5ab3found one more:CollectionCaveatLedgerParityTests. The two SKUs'get_collection_healthdescriptions must be byte-identical, and the fix round had changed only Darling's fan-out sentence. Seat fix5e835504e: both now say "Up to six fan out ... query_store_forced_plans in Darling only", because Lite does not run this collector. VM at5e835504e:Darling.Tests Total: 42, Errors: 0, Failed: 0(CollectionCaveatLedger*,CollectionLogFanoutRollupStoreTests,McpToolGuideTests,CollectionHealthPayloadBudgetLiveTests, withVM_PG=1) andLite.Tests Total: 185, Errors: 0, Failed: 0.CHANGELOG entry
(Seat: the entry is rewritten to describe only the collector, which is what this PR ships.)
Deferred and follow-ups
Deferred (the brief's steps 3 and 4, not started because the investigation of the registration points used the lane's budget):
get_forced_plansMCP read:server_name, optionaldatabase_name,hours_back,as_of(DarlingReadWindow), registered likeget_plan_force_precheck(An MCP read checks a Query Store plan before anyone forces it (#5632) #6065): tool class andWithGeminiCompatibleTools,DarlingWebEndpointsdescriptor and dispatch (PDatabases/DatabaseNamesor IDENTITY),WebReadReach,DarlingMcpToolClassification,plain-text.jsMCP_TOOL_NAMES,database-filter-reads.js,CatalogCensuscount (206 to 207), docs tool counts (docs/mcp-server.md,docs/editions.md),WebReadCancellationPinTestsfake request,WebDatabaseFilterBehaviourTestsscope count,McpToolGuideTests.get_query_store_query_historyalways lists forced plans, with state (DarlingMcpQueryStoreHistoryTools.csabout line 253,DarlingWebEndpoints.cs).HistorySqlandHistoryTableSqluntouched so far.IsDarlingOnlycurrently hides it from Lite).AgentLevel2StoreTestsrewind and the other live classes.Follow-ups proposed (not filed): none beyond the items above.