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
28 changes: 28 additions & 0 deletions tools/pg-verification-rig/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,34 @@ defects survived long enough to be found here.
EXECUTE; a superuser must grant it explicitly. That grant also exposes `pg_hba.conf`, which is why the
plan-capture collector reports its absence as a grant the operator must choose to give.

## Two majors at once, for version drift

```bash
docker compose --profile multiversion up -d # adds a plain PostgreSQL 18 target on 55418
```

Some of what this product reads is not stable across majors, and every one of those differences is silent:
17 gutted `pg_stat_bgwriter`, moving five columns to `pg_stat_checkpointer` and deleting `buffers_backend`
outright; 18 removed `pg_stat_io`'s `op_bytes` and replaced it with measured `read_bytes` / `write_bytes` /
`extend_bytes`. A collector that guards the difference correctly and a read that quietly returns NULL look
identical from one server.

Register **both** targets in `darling.json` and the difference becomes an observable, which is how #2653 and
#2655 were found and verified:

- the registry stamps `postgres_major_version` 17 and 18 side by side
- `pg_io_stats` splits cleanly — 17's rows carry `op_bytes` and no `read_bytes`, 18's the reverse
- `get_pg_io_stats` answers `estimated_from_block_size` for one and `measured` for the other

It also quantifies things reasoning gets wrong. 18's vectored reads mean one entry in `reads` can cover
several blocks, so the pre-18 `reads x block_size` estimate undercounts — measured here, by **10× to 16×**,
not the few percent it sounds like.

The 18 target is the **plain image**, not the extension build. The PGDG extension packages do not track a
new major immediately, and pinning to them would make the rig fail to build on the day a major ships —
exactly when this target is most useful. It exercises the core catalog views, which is where version drift
lives; the extension-backed collectors belong on the 17 target.

## Reproducing the Aurora-only paths

You cannot, from here, and that is fine. `pg_wait_stats` and the RDS log API need a managed target. Their
Expand Down
23 changes: 23 additions & 0 deletions tools/pg-verification-rig/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,29 @@ services:
- -c
- pg_qualstats.sample_rate=1

# A SECOND target, pinned to the newest major, for the version-difference work. Some of what this
# product reads is not stable across majors and the differences are silent: 17 gutted pg_stat_bgwriter
# and 18 removed pg_stat_io's op_bytes outright, replacing it with measured byte totals (#2655). A
# collector can only be checked against that by having both majors present AT ONCE - one target shows a
# column missing, two show which one has it and which quantity each is reporting.
#
# Deliberately the PLAIN image, not the extension build above. The PGDG extension packages do not track
# a new major immediately, and pinning this to them would make the whole rig fail to build on the day a
# major ships - exactly when this target is most useful. It exercises the CORE catalog views, which is
# what version drift lives in; the extension-backed collectors belong on the 17 target.
#
# Opt-in, so the default `up -d` stays a two-container rig:
# docker compose --profile multiversion up -d
target18:
image: postgres:18
profiles: ["multiversion"]
restart: unless-stopped
environment:
POSTGRES_PASSWORD: targetpw
POSTGRES_DB: appdb
ports:
- "55418:5432"

store:
image: postgres:17
restart: unless-stopped
Expand Down
Loading