64-bit MultiXactOffset vs. 9.3->9.4 upgrade, pg_resetwal, "wraparound" msg

From: Noah Misch <noah(at)leadboat(dot)com>
To: hlinnaka(at)iki(dot)fi, orlovmg(at)gmail(dot)com
Cc: pgsql-hackers(at)postgresql(dot)org
Subject: 64-bit MultiXactOffset vs. 9.3->9.4 upgrade, pg_resetwal, "wraparound" msg
Date: 2026-08-27 23:17:57
Message-ID: 20260827231757.78.noahmisch@microsoft.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

commit bd8d9c9 wrote:
> Commit: Heikki Linnakangas <heikki(dot)linnakangas(at)iki(dot)fi>
> CommitDate: Tue Dec 9 13:53:03 2025 +0200
>
> Widen MultiXactOffset to 64 bits

> --- a/src/bin/pg_upgrade/pg_upgrade.c
> +++ b/src/bin/pg_upgrade/pg_upgrade.c

> + nxtmulti = old_cluster.controldata.chkpnt_nxtmulti;
> + if (old_cluster.controldata.cat_ver >= MULTIXACT_FORMATCHANGE_CAT_VER)
> + {
> + /* Versions 9.3 - 18: convert all multixids */
> + oldstMulti = old_cluster.controldata.chkpnt_oldstMulti;

If a cluster's upgrade history includes an upgrade from 9.3 to early 9.4, it
may have a wrong value here. Specifically, upgrades done before a61daa14
(2014-07 commit) have that hazard. We still have backend code to detect such
cases and reduce damage:

ereport(LOG,
(errmsg("cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
newOldestMulti)));

However, the pg_upgrade side from the v19 commit lacks such protection. If
heap tuples still reference older multixacts than the faulty control data
suggests, pg_upgrade will copy too small a range, making affected tuples
unreadable.

I also had Opus 4.8 look for defects in this change and write test cases. It
didn't find the above problem, but it had other findings. I'm attaching the
full report. I recommend fixing at least these before release:

> +| 5 | `resetwal-nextmxoff-zero` | `src/bin/pg_resetwal/pg_resetwal.c:703`, and `-O` with no zero check at 297-307 | `pg_resetwal -f` (or `-O 0`) leaves `nextMultiOffset = 0`, the reserved "invalid offset"; first multixact created afterwards is permanently unreadable: `ERROR: MultiXact 1 has invalid offset` | Yes — `src/test/modules/test_slru/t/003_multixact_offset.pl` |

> +| 7 | `members-truncation-apparent-wraparound` | `src/backend/access/transam/multixact.c:2642-2647` | When `nextOffset` lands on a members page boundary, truncation logs `could not truncate directory "pg_multixact/members": apparent wraparound` (impossible for a 64-bit counter) and reclaims nothing | Yes — `003_multixact_offset.pl` |

Others are more optional or already reported. In particular, two other
findings were already reported and apparently fixed after the Opus run, in
thread "pg_upgrade silently truncates nextMultiOffset to 32 bits":
https://www.postgresql.org/message-id/CAD21AoCvzerscfU8o4ARQ793yAGHpQ72r2x5apeC_W2-k%3DSLCQ%40mail.gmail.com

Attachment Content-Type Size
bd8d9c9-MultiXactOffset-tests-v0.patch text/plain 50.8 KB

Browse pgsql-hackers by date

  From Date Subject
Next Message Henson Choi 2026-08-28 00:12:17 Re: Row pattern recognition
Previous Message Bharath Rupireddy 2026-08-27 22:51:35 Re: REPACK (CONCURRENTLY) doesn't check the table AM