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
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ Full entries: [docs/changelog/3.10.md](docs/changelog/3.10.md)
- **Filter web grid columns by number, text operator or empty cell** ([#5255])
- **Web sidebar search and tag grouping** ([#5259])
- **Lite has a DuckDB memory limit setting** ([#5553])
- **Column filters list a text column's values to tick, like Excel, and stay set across refreshes and restarts** ([#5577])
- **One time range picker for Lite, the Darling Viewer and the Darling web pages** ([#5570])

### Changed

Expand Down Expand Up @@ -179,6 +181,9 @@ Full entries: [docs/changelog/3.10.md](docs/changelog/3.10.md)
- **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])
- **The Query Store interval tables are partitioned by day** ([#5573])
- **A long one-counter perfmon trend loads faster** ([#5579])
- **The retention purge gives way to collection** ([#5595])

### Fixed

Expand Down Expand Up @@ -312,6 +317,15 @@ Full entries: [docs/changelog/3.10.md](docs/changelog/3.10.md)
- **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])
- **The module map refresh no longer holds back the collectors at service start** ([#5580])
- **The module map's daily refresh no longer sorts every raw procedure_stats row** ([#5584])
- **The first Query Store read after a big retention drain is no longer slow** ([#5585])
- **Web charts draw at the panel's real width** ([#5590])
- **Autovacuum on the Query Store interval tables can finish again** ([#5593])
- **The Darling whole-tree guards CI job no longer fails after every test passes** ([#5598])
- **"Collection Falling Behind" no longer fires in the first hour after every start** ([#5599])
- **A hung test shard names its test and keeps its logs** ([#5591])
- **One-day Custom Views panels on Query Store data read an hourly rollup, or are refused up front** ([#5588], [#5610])

## [3.9.0] - 2026-10-02

Expand Down Expand Up @@ -5158,3 +5172,18 @@ Full entries: [docs/changelog/3.0.md](docs/changelog/3.0.md)
[#5564]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5564
[#5566]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5566
[#5572]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5572
[#5570]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5570
[#5573]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5573
[#5577]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5577
[#5579]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5579
[#5580]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5580
[#5584]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5584
[#5585]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5585
[#5588]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5588
[#5590]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5590
[#5591]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5591
[#5593]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5593
[#5595]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5595
[#5598]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5598
[#5599]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5599
[#5610]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5610
29 changes: 29 additions & 0 deletions docs/changelog/3.10.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ compacted index for every version, this one included, and is where `[Unreleased]
- **Filter web grid columns by number, text operator or empty cell** ([#5255]) - a column filter can now match greater/less than, equals, not equals, starts with, ends with, is empty and is not empty, comparing the real numbers rather than the formatted text; plain typing still does a contains match.
- **Web sidebar search and tag grouping** ([#5259]) - the web sidebar's server list has a search box (name, server name or tag) and a Group by tag toggle with Favourites first, the tag tree, then Untagged. The search term lasts across refreshes; the toggle and collapsed groups are remembered per browser.
- **Lite has a DuckDB memory limit setting** ([#5553]) - Settings, Dashboard Defaults, "DuckDB memory limit" sets the main DuckDB connection's memory limit (default 2 GB, range 1 GB to 80% of memory, applied after a restart). The thread count follows it as the smaller of 8, the core count and the limit divided by 256 MB, and out-of-memory errors name the setting and its current value, and so does the log.
- **Column filters list a text column's values to tick, like Excel, and stay set across refreshes and restarts** ([#5577]) - A text column's filter lists its values, with a search box, Select All and "(Blanks)", in Lite, the Darling viewer and the web dashboard. Unticking values hides only them, so a new login after a refresh still shows, and ticking values shows only those. The filter stays set across refreshes, tab switches and restarts, per server, grid and column. Lite and the viewer keep it in a file next to their settings, and the web dashboard keeps it in the browser. Number and time columns keep the text match only. Query text, plan, XML, message, detail, description, reason, error and script columns also keep the text match only, and that match lasts for the session.
- **One time range picker for Lite, the Darling Viewer and the Darling web pages** ([#5570]) - It has more presets, calendar periods (today, this week, last month and so on) and typed ranges such as `last 3 days`, `Oct 1 - Oct 2` or `since 9am`. All three front ends read a typed range the same way. A range they cannot read is refused with a plain reason, never quietly changed. On the web, each server tab offers only the periods its data reaches. The query, procedure and Query Store duration trends on the web and in MCP can now reach back 90 days.

### Changed

Expand Down Expand Up @@ -163,6 +165,9 @@ compacted index for every version, this one included, and is where `[Unreleased]
- **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.
- **The Query Store interval tables are partitioned by day** ([#5573]) - On the PostgreSQL store, the two Query Store interval tables now hold one partition per day. Retention drops a whole expired day instead of deleting its rows, and reads with a time range skip the days outside it. The upgrade copies no data. It attaches the current table as a legacy partition without a scan and checks the bound in the background. On a large store the two upgrade steps took 1.1 s and 20 ms. The legacy partition empties through retention and is then dropped. If it holds a row dated far in the future, the table stays as it is, with one warning, until that row is gone.
- **A long one-counter perfmon trend loads faster** ([#5579]) - perfmon data is now compressed per counter as well as per server. Reading one counter (for example Batch Requests/sec) over 30 days opens only that counter's batches, not every counter's. Older compressed chunks are re-grouped in the background, back to 30 days or to the day before retention drops them, whichever is sooner. The loop takes one chunk at a time, newest first, and after each one it pauses as long as that chunk took. A read beside a re-group waits a few seconds at most. The web viewer's perfmon trend and the `get_perfmon_trend` MCP tool now reach 30 days instead of 7.
- **The retention purge gives way to collection** ([#5595]) - On a large store, the first purge after the 3.10 upgrade deleted about 18 M rows in 40 minutes. Collection fell behind while it ran. Each batch now waits while collection is skipping slots or the service has just started, and pauses after it runs. A pass stops after 30 minutes, and the next one comes due within an hour until every table is drained. This applies to the daily purge and to purge_now.

### Fixed

Expand Down Expand Up @@ -312,6 +317,15 @@ compacted index for every version, this one included, and is where `[Unreleased]
- **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.
- **The module map refresh no longer holds back the collectors at service start** ([#5580]) - On a large store, the start-up module map refresh read procedure_stats for about 55 seconds before any collector started, on every restart. The start path now only creates the table. The refresh runs after the collectors start, from the hourly tick and the daily purge.
- **The module map's daily refresh no longer sorts every raw procedure_stats row** ([#5584]) - On a large store the refresh read 10.6 M rows to find 21,636 handles. It took 35.5 s, most of it a sort that spilled 2.19 GB to disk. It now groups the rows by handle and names first. On a copy of that store the same window ran in 8.3 s with no spill. The map and its watermark come out the same.
- **The first Query Store read after a big retention drain is no longer slow** ([#5585]) - After the retention purge removed the oldest Query Store interval rows, each server's first floor read walked every dead index entry. On a large store that took 19.6 s for one server. The purge now runs that read once per server in the background when it finishes, one server at a time. It runs only when the purge deleted rows or failed. A pass that only drops whole day partitions skips it, because a dropped partition takes its index entries with it. It skips a server whose table is locked.
- **Web charts draw at the panel's real width** ([#5590]) - Line and scatter charts were stretched sideways to fit the panel. At 2,000 px their axis text was drawn at about twice its normal size, and the bar chart's labels grew with the panel too. All three now draw at the panel's width, and a resize redraws them with their zoom kept. Time labels follow the width, so none overlap on a phone or repeat on a short zoomed window. Across a clock change, each time label shows its time zone. The bar chart sizes its columns to the text, and printing scales each chart to the page width.
- **Autovacuum on the Query Store interval tables can finish again** ([#5593]) - The BRIN index on their collection time asked for each new range to be summarized. After a large retention purge, those requests cancelled the running autovacuum about every 2 minutes, so dead rows piled up. The index no longer does that. The service now summarizes new ranges once an hour, and it gives up rather than cancel a vacuum.
- **The Darling whole-tree guards CI job no longer fails after every test passes** ([#5598]) - WPF left a process-exit handler for each test thread that used a bound control. Each one waited out a 300 millisecond timeout, so the test process outlived the runner's 11-second exit window. The runner then forced exit code 1 with no failed test. Both test projects now set the WPF switch that skips the wait. This is a CI-only fix: no product code changed.
- **"Collection Falling Behind" no longer fires in the first hour after every start** ([#5599]) - It fired minutes after a start. The alert now leaves out what was counted in the first 15 minutes after the service starts. A store that stays behind fires about 30 minutes after the start. A stall, a clock step, a pause ending or the launch guard's release does not give those minutes again. The alert text names the minutes it judged, and in the first hour the log line says "last N minutes, since the service started". Slots due while a server's connect run was still seeding its schedule are no longer counted as skipped.
- **A hung test shard names its test and keeps its logs** ([#5591]) - A shard that ran into the job timeout lost its log and its timing. The Darling and Lite test steps now have their own timeout under the job's, so the upload steps still run. The runner reports any test that has run for 5 minutes, and its output is uploaded. The nightly runs get the same report. One test waited up to an hour while holding a lock. It now gives up after 60 seconds.
- **One-day Custom Views panels on Query Store data read an hourly rollup, or are refused up front** ([#5588], [#5610]) - On a large store, a one-day panel read 8.46 M rows and took 55.2 s against the 60 s limit. Darling now keeps an hourly rollup of the Query Store wide table and reads closed hours from it. The answer is exactly what the wide table returns. A panel over the row limit is refused up front with the reason. A ranked panel reads its rows once only when that cannot fill the temp file limit. A rollup build waits only for an open write to the wide table that began before its hour was safe to build. A long wait is logged as a warning that names the session. A schema upgrade that cannot get its table lock in time logs every session that holds a lock on the store's tables.

[#4902]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/4902
[#4944]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/4944
Expand Down Expand Up @@ -591,4 +605,19 @@ compacted index for every version, this one included, and is where `[Unreleased]
[#5556]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5556
[#5564]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5564
[#5566]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5566
[#5570]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5570
[#5572]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5572
[#5573]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5573
[#5577]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5577
[#5579]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5579
[#5580]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5580
[#5584]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5584
[#5585]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5585
[#5588]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5588
[#5590]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5590
[#5591]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5591
[#5593]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5593
[#5595]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5595
[#5598]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5598
[#5599]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5599
[#5610]: https://github.com/erikdarlingdata/PerformanceMonitor/pull/5610
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 276 f7f7c48982a27d3e48b95c7529da8cfd2edbbb63680ea8001290fc8197f69919
3.10.0 290 131a86b75911d57c3c760e79fc9bec8e346d4bbb2be790ce4c113cb2c00658f7
3.9.0 760 3b0001be584135029dc4dc921cae4c9f15ca09ace77230625ec0974a22d7ede8
3.8.0 35 7c531d7f349f1432913ae72b9ea8542821878e15f1aafe9c8a773abc55e7a5e1
3.7.0 279 8912147a684e50dbd37b772b44688d68b71f46b854b5f90a2cfd9aeca5c71021
Expand Down
Loading