pg_upgrade stores an invalid datminmxid/relminmxid when the old cluster's newest multixact is 0xFFFFFFFF

From: Manu <manuelreyesbravo(at)gmail(dot)com>
To: pgsql-hackers(at)lists(dot)postgresql(dot)org
Cc: Heikki Linnakangas <hlinnaka(at)iki(dot)fi>, Noah Misch <noah(at)leadboat(dot)com>, Zsolt Parragi <zsolt(dot)parragi(at)percona(dot)com>
Subject: pg_upgrade stores an invalid datminmxid/relminmxid when the old cluster's newest multixact is 0xFFFFFFFF
Date: 2026-10-17 07:45:01
Message-ID: 179222310109.2552144.6852303936733376629@gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

While testing pg_upgrade's multixact conversion around commit 2323f03,
I ran into an adjacent, pre-existing issue.

When the old cluster's newest multixact is 0xFFFFFFFF, its checkpoint
has NextMultiXactId = 0. copy_xact_xlog_xid() maps that to
FirstMultiXactId for pg_resetwal, but set_frozenxids() writes the raw 0
into pg_database.datminmxid and pg_class.relminmxid (the code dates to
a61daa14d56, 2014).

The effect:
- on assert-enabled builds, VACUUM fails Assert(MultiXactIdIsValid(...));
- otherwise template0 keeps datminmxid = 0 (mxid_age 2147483647) and
multixact truncation is skipped ("cannot truncate up to MultiXact 0
... skipping truncation") until autovacuum vacuums template0 -- which
it does within ~60 s by default, but never with autovacuum = off.

19's new oldestMultiXid consistency check does not catch it: it uses
modular arithmetic, so 0 "follows" 0xFFFFFFFF and passes. It
reproduces with pg_upgrade 18 and master.

The attached patch applies the same adjustment in set_frozenxids(), not
in controldata.c: the raw nextMulti = 0 is still needed so the multixact
reader sees that 0xFFFFFFFF is the newest multixid -- the case 2323f03
fixed. It also adds a case to t/007_multixact_conversion.pl.

Measured on cassert builds from 14..18 across 8 offset/multixid
wraparound boundaries (40 upgrades, plus --link from 18): with the fix,
no invalid datminmxid/relminmxid and no other datminmxid change (only
template0's 0 -> 1 in the 8 affected upgrades); without it, VACUUM traps
and the two new test checks fail. check-world passes.

So the severity is low with the default autovacuum, persistent with
autovacuum off, and a hard failure on assert-enabled builds.

Regards,
Manu

Attachment Content-Type Size
v2-0001-pg_upgrade-Don-t-store-an-invalid-datminmxid-relm.patch text/x-patch 4.9 KB

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Zsolt Parragi 2026-10-17 08:11:54 Re: pg_upgrade stores an invalid datminmxid/relminmxid when the old cluster's newest multixact is 0xFFFFFFFF
Previous Message Manu 2026-10-17 07:31:10 Re: [PG19] Eager aggregation runs a volatile join clause once per group