Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ Full entries: [docs/changelog/3.10.md](docs/changelog/3.10.md)
- **Lite keeps query stats and Query Store stats in one archive file per day** ([#5482])
- **The plan regression check in Darling reads stored per-day totals for closed days** ([#5467])
- **procedure_stats now fetches plans only for plans the collector has not stored** ([#5502])
- **Recommendations skip databases that are a secondary copy on this node** ([#5564])

### Fixed

Expand Down Expand Up @@ -301,6 +302,16 @@ Full entries: [docs/changelog/3.10.md](docs/changelog/3.10.md)
- **Small fixes across Lite and the Darling Viewer from the final release walk: Collector Schedules wording, Server Inventory health, time columns, screen-reader names and FinOps dashes** ([#5542])
- **Lite's Job History tab reads only the selected time range, and tab loads no longer wait on the database from the window** ([#5553])
- **Darling stops a rollup's refresh jobs before it drops the rollup** ([#5552])
- **The Darling Viewer's Top Queries, Top Procedures and Query Store tabs load faster over a network** ([#5556])
- **Two services starting against one PostgreSQL store no longer fail each other's role provisioning** ([#5566])
- **The Query Store interval purge finishes on a large store** ([#5572])
- **Running Jobs in Lite and the Viewer, and the get_running_jobs tool, list only jobs the collector's latest successful run found** ([#5554])
- **Each File I/O chart draws its own ten files, so Read Latency no longer goes blank when logs are busiest** ([#5554])
- **Lite's own queries no longer top Top Queries by Duration or Query Store by Duration** ([#5554])
- **The Live Snapshot button and the Get Actual Plan buttons in Lite judge statement text and plans with the screens' statement filter** ([#5554])
- **Select All in the Databases filter, or ticking every collected database, now means All** ([#5554])
- **Empty server-tab grids in Lite and the Viewer say why they are empty, and screen readers get names for toolbar combos and plan operators** ([#5554])
- **The web dashboard's footer time, Job History messages, saved views, offline fleet cards and service log read correctly** ([#5554])

## [3.9.0] - 2026-10-02

Expand Down Expand Up @@ -5142,3 +5153,8 @@ Full entries: [docs/changelog/3.0.md](docs/changelog/3.0.md)
[#5544]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5544
[#5552]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5552
[#5553]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5553
[#5554]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5554
[#5556]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5556
[#5564]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5564
[#5566]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5566
[#5572]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5572
16 changes: 16 additions & 0 deletions docs/changelog/3.10.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ compacted index for every version, this one included, and is where `[Unreleased]
- **Lite keeps query stats and Query Store stats in one archive file per day** ([#5482]) - Lite's compaction merged these two tables into one file per month. They are now merged one day at a time, as query_snapshots has been since #5434. A one-hour read now touches about 4% of a day's row groups instead of 15-20% of a month's. Month and imported files written earlier stay as they are.
- **The plan regression check in Darling reads stored per-day totals for closed days** ([#5467]) - The PLAN_REGRESSION fact used to re-read and re-add 14 days of Query Store intervals on every analysis run. On the busiest server of an 87.4 M-row store (4.67 M rows), that took 8.6 s and 986 K buffers. It now builds each closed day's totals once (about 1.1 s per day per server) and reads only the last three days live. A run is about 6x faster (1.28 s) and reads about 3x fewer buffers (338 K). It is not 14x, because three of the 14 days stay live. The comparison window now starts at the beginning of a day, and the regressed-queries drill-down uses the same start. A read that cannot use the totals falls back to the old read. That fallback is logged and records no collection caveat, because nothing is missing.
- **procedure_stats now fetches plans only for plans the collector has not stored** ([#5502]) - The procedureStatsDeferredPlanFetch setting now defaults to on, so a plan the collector already holds is not rendered on the monitored server and sent again. This cuts plan-rendering CPU on the monitored servers. To restore the old behavior, set procedureStatsDeferredPlanFetch to "off" in darling.json. Azure SQL Database stays off whatever the setting says.
- **Recommendations skip databases that are a secondary copy on this node** ([#5564]) - A node can hold a secondary copy of an Availability Group database. For that database, Lite and Darling no longer report findings that come from data every copy shares. These are database settings, percent file growth, Query Store plan regressions and table growth. On the FinOps tab they are idle databases, dev and test names, TDE blockers and compression candidates. The node that holds the primary copy reports them. Findings about work on the node, such as queries, missing indexes, blocking and I/O, stay on every node. If the group data is missing or old, nothing is skipped. The tab says how many databases it skipped, and the MCP analysis tools carry a note that says the same.

### Fixed

Expand Down Expand Up @@ -301,6 +302,16 @@ compacted index for every version, this one included, and is where `[Unreleased]
- **Small fixes across Lite and the Darling Viewer from the final release walk: Collector Schedules wording, Server Inventory health, time columns, screen-reader names and FinOps dashes** ([#5542]) - Every server showed Preset "Custom" next to Status "Default", which read as a contradiction. Status now reads "Uses default" or "Own schedule", both column headers have a tooltip, and a Custom preset has a tooltip naming the collector intervals that differ from the closest preset. The Server Inventory Health column in Lite and the Darling Viewer, web page and MCP tool now shows the same score as that server's Utilization view; it used to show almost the same number for every server because it scored average CPU against fixed memory and storage values. The Darling Viewer's Overview card shows the date of a collection that is not from today, the Alert History and Job History time columns name the clock they read on (and Viewer Job History rows read on their own server's clock), Alert History says when it shows only the newest 500, the Overview search also narrows the fleet roll-up above the cards ("Monitoring 2 of 9 servers"), and an Availability Group on old data reads Stale instead of Healthy in the Viewer and Lite. Screen readers now read column headers, their filter buttons, empty cells (text or templated), grid rows and server list items by name in Lite and the Viewer (they read as "System.Windows.Controls.StackPanel", a bare glyph or a type name before; a row now reads as its first two visible columns, such as "Time 06:01:12, Server example-sql-01"). The FinOps Utilization view in Lite and the Darling Viewer shows dashes for Avg, P95 and Max CPU when a server has no CPU sample in the last 24 hours (they read 0.00%, 0.00% and 0%) and hides the database sizes chart then, and the web page's Utilization read and the MCP tool return null for those three figures. The Server Inventory dash in place of a health score now has a tooltip that names both reasons for it (no CPU sample in the last 24 hours, or no memory sample collected), and Lite's Alert History count follows a column filter, as the Darling Viewer's does.
- **Lite's Job History tab reads only the selected time range, and tab loads no longer wait on the database from the window** ([#5553]) - Every Job History read loaded and sorted each server's whole archived job history before it dropped the runs outside the selected range. On a 30-server test store that cost 4 to 8 seconds and 600 to 730 MB per server, and on a larger store it can run out of DuckDB's memory cap. The archive view now applies the time range first: 0.5 to 0.7 seconds, under 300 MB, same rows. The Availability Groups and FinOps tab loads, opening a plan viewer from a tab, the Overview's tag refresh, and the Manage Tags, Database State Overrides, history, drill-down and Collection Log windows also awaited their database reads and writes on the window's own thread. There they can wait behind archival or a long read. They now read off that thread.
- **Darling stops a rollup's refresh jobs before it drops the rollup** ([#5552]). When Darling retired or rebuilt a rollup (a TimescaleDB continuous aggregate), its background refresh was sometimes still running. The drop failed with "tuple concurrently deleted", and in one test run the PostgreSQL backend running the refresh crashed. Darling now stops the rollup's jobs and waits up to 30 seconds for a running refresh to end. TimescaleDB ends it within seconds, as one failed run, so a rollup that stays can raise one information-level job-failure alert. If the wait runs out or the drop fails, Darling restarts the jobs and tries again on the next pass.
- **The Darling Viewer's Top Queries, Top Procedures and Query Store tabs load faster over a network** ([#5556]) - A 7 day Top Queries load fetched each row's query text with its own store call, 50 calls in all. It is now one call. The slicer read starts beside the grid read instead of after it. The Long Queries tab starts its trace check beside its two grid reads instead of before them. A failed trace check no longer fails that load. The status bar's Database size comes from the size the service records on its hourly sweep. When no size is recorded, or the recorded size cannot be read, the Viewer measures the live database. After a timeout it keeps the last size shown instead. Either way the cause is logged once. A tab load slower than 3 seconds logs its phase split, times the baseline-comparison read as a store read, and names every tab.
- **Two services starting against one PostgreSQL store no longer fail each other's role provisioning** ([#5566]) - the role and privilege batch that runs at start, and the reload's statement_timeout re-assert, failed with "tuple concurrently updated" when a second service ran the same statements at once. That left the viewer and MCP roles stale until the next start. Both now take an advisory lock first, so the second waits for the first. The wait is bounded at 12 seconds at start and 5 seconds on a reload. If something else holds the lock for longer, one warning names the session that holds it and the write runs without the lock. A write that fails because the other session wrote the same row first is run again up to twice. The self-managed store's password-rules step takes the same lock.
- **The Query Store interval purge finishes on a large store** ([#5572]) - On a large store, the purge of the wide and latest Query Store interval tables never removed anything. It deleted a whole day in one statement, and that statement timed out on every pass. The purge now deletes in batches of up to 50,000 rows and commits each batch. A batch that times out is retried at half the size. Each batch starts where the last one ended, so a backlog drains over a few passes. The purge of the plan content table now also starts each batch where the last one ended.
- **Running Jobs in Lite and the Viewer, and the get_running_jobs tool, list only jobs the collector's latest successful run found** ([#5554]) - A snapshot older than the long-running-job alert's bound is not listed. That bound is three missed cycles at the server's running_jobs cadence, at least 10 minutes. When that hides the jobs, the tab and the tool say collection is not current and give the time of the last good collection. A failed read shows "The running jobs could not be read". It no longer shows "No SQL Agent jobs are running." The empty grid says so in words. The column headers are wide enough to read.
- **Each File I/O chart draws its own ten files, so Read Latency no longer goes blank when logs are busiest** ([#5554]) - The read chart takes the ten busiest files by reads and the write chart the ten busiest by writes. Each chart draws its files exactly as the read ranked them. The read says which ten each file is in. The ranking puts NULLs last and breaks ties by file name the same way in the DuckDB and PostgreSQL stores. The Overview I/O Latency lane weights read latency by reads.
- **Lite's own queries no longer top Top Queries by Duration or Query Store by Duration** ([#5554]) - That covers its Query Store probe, its plan and text fetches, its connect-time detection query and its failed-jobs and job-step reads.
- **The Live Snapshot button and the Get Actual Plan buttons in Lite judge statement text and plans with the screens' statement filter** ([#5554]) - The Live Snapshot button and the six Get Actual Plan sites use the same statement filter as the screens. The filter runs off the UI thread. A plan the filter withholds is refused on save. The test that lists every place Lite opens its own server connection now covers all of Lite, with a reason for each file.
- **Select All in the Databases filter, or ticking every collected database, now means All** ([#5554]) - Databases collected later are then included. A filter for databases that are not collected yet stays a filter when the read of collected names fails.
- **Empty server-tab grids in Lite and the Viewer say why they are empty, and screen readers get names for toolbar combos and plan operators** ([#5554]) - Empty Trace Flags, Running Jobs and Query Store Regressions grids say why. Configuration and Index Analysis headers and notes read in plain words. The toolbar combos and plan operators have names for screen readers. The disabled Compare box says where it works. An empty comparison period says so. The Repro script's Generated line is in UTC.
- **The web dashboard's footer time, Job History messages, saved views, offline fleet cards and service log read correctly** ([#5554]) - The footer Updated time follows the page's own latest load and keeps its last good value when a poll fails. A read narrowed to its limit and then answered is not a failure. Job History messages are readable and open in full. A saved view opens on its server and says whose pick the scope is. It says all servers when its own setting is All. The Databases popover closes on a tab change. A server dark past the fleet read's 48 hours shows the real time of its last collection on its card. Availability Group counts and several empty-state sentences read correctly. A failed web request leaves exactly one service-log line, and it names the server and the cause. A failure before sign-in from one address is logged once per ten minutes. An unknown server is reported as not found. A registry lookup that fails no longer reads as "not registered". The offline-age read is cached and holds one pooled connection at a time.

[#4902]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/4902
[#4944]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/4944
Expand Down Expand Up @@ -576,3 +587,8 @@ compacted index for every version, this one included, and is where `[Unreleased]
[#5544]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5544
[#5552]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5552
[#5553]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5553
[#5554]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5554
[#5556]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5556
[#5564]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5564
[#5566]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5566
[#5572]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5572
2 changes: 1 addition & 1 deletion tools/changelog/archive-census.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# fails CI. It is the durable half of the proof; `roundtrip` is the whole-document half and
# needs the pre-split revision to compare against.

3.10.0 265 1431fd261121aecc257ab39de95dcfef5292a17482977972618690b84f49426c
3.10.0 276 f7f7c48982a27d3e48b95c7529da8cfd2edbbb63680ea8001290fc8197f69919
3.9.0 760 3b0001be584135029dc4dc921cae4c9f15ca09ace77230625ec0974a22d7ede8
3.8.0 35 7c531d7f349f1432913ae72b9ea8542821878e15f1aafe9c8a773abc55e7a5e1
3.7.0 279 8912147a684e50dbd37b772b44688d68b71f46b854b5f90a2cfd9aeca5c71021
Expand Down
Loading