Files
james.maesandClaude Fable 5.1 d46b6ca222
QRun-IO/ci-policy: ci / fork-guard (push) Skipped
QRun-IO/ci-policy: ci / gradle-0 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-2 (push) Skipped
QRun-IO/ci-policy: ci / node-3 (push) Skipped
QRun-IO/ci-policy: ci / node-4 (push) Skipped
QRun-IO/ci-policy: ci / source-config-5 (push) Skipped
QRun-IO/ci-policy: ci / not-enrolled (push) Skipped
QBit CodeQL / Analyze branch source (push) Canceled after 0s
CodeQL / analyze (push) Canceled after 0s
QRun-IO/ci-policy: Shared Java Maven CI with Docker / verify (push) Successful in 3m47s
QRun-IO/ci-policy: Shared Java Maven CI with Docker / secrets (push) Successful in 11s
QRun-IO/ci-policy: Shared Java Maven CI with Docker / gate (push) Successful in 9s
QRun-IO/ci-policy: ci / java-docker-1 (push) Successful in 40m46s
QRun-IO/ci-policy: ci / ci-result (push) Successful in 4s
feat(provider): H2 statistics provider and per-area capabilities (#34)
H2StatsProvider over INFORMATION_SCHEMA (statements via QUERY_STATISTICS, sessions, blocking, connections, indexes, size, settings, approximated table rows and sizes, text plans); per-area provider capabilities with rules skipped where a provider lacks the data; a vendor registry with a seam for MySQL/MariaDB; provider-specific setup and health checks; an Enable statement statistics action; and the H2 plan guard (single SELECT/WITH only, side-effecting functions refused, EXPLAIN ANALYZE only for non-admin users, read-only connection, always rolled back).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-01 06:14:44 -06:00

5.6 KiB

Changelog

All notable changes are documented here. This project follows Keep a Changelog and semantic versioning.

[Unreleased]

Added

  • H2 2.x support (H2StatsProvider) from INFORMATION_SCHEMA: statement statistics from QUERY_STATISTICS (when the database runs with QUERY_STATISTICS=TRUE), sessions with blocking and idle-in-transaction detection, connection counts, table row estimates and sizes, index definitions, settings, and text query plans (EXPLAIN; EXPLAIN ANALYZE only for non-admin H2 users, since H2 has no read-only transaction: plans refuse side-effecting functions such as FILE_WRITE, DDL/DML keywords, user-defined aliases and multiple statements). The enterprise test server showed UNSUPPORTED on H2; it now collects.
  • Per-area capabilities (StatsFeature): providers declare which statistics areas they can supply and ProviderCapabilities.features() reports what is available on a connection. Snapshot cache-hit ratio and connection limit stay empty when the vendor has none, and analysis rules declare the areas they need (DbPerfRule.requires()) and are skipped on providers that cannot supply them, so H2 never gets "unused index" or "low cache hit" findings from missing counters.
  • Provider registry keyed by JDBC product name (DbStatsProviders.register), with docs/PROVIDERS.md describing what MySQL/MariaDB and SQLite would map to.
  • Enable statement statistics action on Settings (dbPerfEnableStatementStatistics, manage settings): on H2 runs SET QUERY_STATISTICS_MAX_ENTRIES 1000 and SET QUERY_STATISTICS TRUE as an admin; on PostgreSQL explains the manual extension setup. It is the qbit's only change to the monitored database and is explicit.

Changed

  • Health and the Setup panel take their prerequisite checks and remedies from the backend's provider: PostgreSQL still names pg_stat_statements and pg_read_all_stats; H2 names QUERY_STATISTICS and the admin role (new access codes NO_QUERY_STATISTICS and NOT_ADMIN).
  • The previous-snapshot baseline no longer depends on a PostgreSQL-only counter (it uses the database size every supported provider records).

Fixed

  • Query-spike alerts no longer hold seven days of query snapshots as records on every snapshot evaluation (~230,000 rows at kof22's rate). SnapshotEvaluator reads the window in 1,000-row keyset pages and keeps only each statement's current interval time, latest capture time and earlier interval times as primitive doubles; the spike rule (twelve prior samples, median, absence after an hour) is unchanged.
  • The Attribution home panel no longer loads a day of attribution detail into the heap. It sums statements and time per unit and table in the database (at most 5,000 groups), so a render holds about a thousand aggregate rows instead of the roughly 570,000 detail rows (540 MB in PostgreSQL) that ran the kof22 web pod out of memory on 2026-10-16. The daily attribution rollup reads the day in 1,000-row keyset pages (DbPerfStore.forEachPage), so worker memory is bounded by distinct dimension keys, not by the day's row count. The hourly analysis (dbPerfAnalyze) reads attribution the same way: RuleContext.window("attribution", ...) returns database sums per unit, table and operation instead of every detail row (it filled the kof22 worker heap to ~1.8 GB every hour).
  • Collection no longer stops at RUNNING on large production statement sets: list folding in the SQL normalizer is a linear token scan (the nested-repetition regular expressions overflowed the stack on 60 KB statements with long IN/VALUES lists). Any failure, including an Error, now closes the run as FAILED with the exception class, logs it at ERROR (class and frame only, never SQL text) and raises the collection alert; runs left RUNNING by a crash are closed as FAILED after three intervals.
  • Only one runtime attributes per JVM: starting attribution on a newer instance (a hot swap, or repeated server starts in tests) stops the previous one, so old instances are never pinned by a forgotten listener and flusher.
  • Each table has its own icon (the app icon is now storage), so nav entries are distinguishable and do not repeat icons used elsewhere.
  • Home tables keep at most four columns with plain headers (readable at every width): secondary facts such as calls and mean time, the session's query text, and a unit's kind and top table move into a second line of the first cell.

Added

  • QQQ attribution and N+1 detection: a core statement execution listener (QQQ 4.1.0-RC.13) aggregates database time per route, scheduled job, process, table and statement shape in bounded memory, records repeated statement shapes per unit of work, and each pod flushes one batched insert per table every attribution_flush_seconds. Hosts without QQQ's application launcher call DbPerfRuntime.of(instance).startAttribution() after startup.

  • Secured database-performance tables, PostgreSQL statistics snapshots, daily rollups and configurable retention.

  • Audited PLAN/GENERIC and read-only ANALYZE query viewer with SQL validation, timeout, rollback and transient parameter handling.

  • Query plan statement action with readable plan text, cost, SQL Workbench link and a sanitized assistant prompt.

  • UI API extension 1.0.0 with overview, live activity, explain and statement lookup, plus its committed OpenAPI contract.

  • Eight full-width typed home panels with pagination, record links, guided empty states and permission-gated live activity.

  • Maven-versioned QBIT help bundle, complete metadata coverage checks, rule threshold guidance and adoption documentation.

  • PostgreSQL security acceptance tests and H2 API/widget fixtures.