On 15/10/2026 22:27, Zsolt Parragi wrote:
I/Claude found another corner case in the multixact offset conversion,
not covered by the issues in Noah's thread [1].

In 18 and below if the members of the newest multixid end exactly at
2^32 the shutdown checkpoint stores NextMultiOffset = 0, and the
server handles this scenario properly.

But PG19 after the upgrade doesn't:

     select count(*) from t;
     ERROR:  MultiXact 1 has invalid offset
     vacuum freeze t;
     ERROR:  MultiXact 1 has invalid offset
     CONTEXT:  while scanning block 0 offset 1 of relation "public.t"

pg_upgrade --check doesn't notice anything.

Reproducing it on an 18 cluster:

     pg_resetwal -O 4294967294 old
     # create the zeroed members segment for that offset (14078)
     create table t(id int primary key, v int); insert into t values (1,0);
     -- session 1
     begin; select 1 from t where id = 1 for key share;
     -- session 2
     update t set v = 1 where id = 1;
     -- session 1
     commit;

then stop the server and upgrade it.

This needs the last multixid before the upgrade to end exactly at the
boundary, so it is definitely a corner case.

The attached patch moves the zero check into the branch that reads the
next multixid's slot, matching what the server does. The existing
length calculation already handles the wrap, since both offsets are
uint32.

It also adds a scenario to 007_multixact_conversion.pl (only runs with
oldinstall set to a pre-19 installation, like the wraparound one).

Committed, thanks!

- Heikki



Reply via email to