Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vsdO2-00B18I-17 for pgsql-bugs@arkaria.postgresql.org; Wed, 18 Feb 2026 08:58:23 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vsdO1-00F4KT-1A for pgsql-bugs@arkaria.postgresql.org; Wed, 18 Feb 2026 08:58:21 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vsdO0-00F4KF-2t for pgsql-bugs@lists.postgresql.org; Wed, 18 Feb 2026 08:58:21 +0000 Received: from forwardcorp1b.mail.yandex.net ([2a02:6b8:c02:900:1:45:d181:df01]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1vsdNy-00000001KpC-2g71 for pgsql-bugs@lists.postgresql.org; Wed, 18 Feb 2026 08:58:20 +0000 Received: from mail-nwsmtp-smtp-corp-canary-81.sas.yp-c.yandex.net (mail-nwsmtp-smtp-corp-canary-81.sas.yp-c.yandex.net [IPv6:2a02:6b8:c37:8aa5:0:640:e6ae:0]) by forwardcorp1b.mail.yandex.net (Yandex) with ESMTPS id C01A58086C; Wed, 18 Feb 2026 11:58:15 +0300 (MSK) Received: from smtpclient.apple (unknown [2a02:6bf:8080:26::1:2a]) by mail-nwsmtp-smtp-corp-canary-81.sas.yp-c.yandex.net (smtpcorp/Yandex) with ESMTPSA id DwV5bB3AnqM0-YPvI5oCI; Wed, 18 Feb 2026 11:58:15 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex-team.ru; s=default; t=1771405095; bh=U95LwSjcTnh8o16SyWKcTwmavtfXLdm9EhG68ylPULA=; h=References:To:Cc:In-Reply-To:Date:From:Message-Id:Subject; b=e34PmIHMh5jYowAUpN4Ge/F1vG9Rs5TRmjwcgDEDNfkiAjoyudyLcuH9LRBvCNHGi 4tMYAK+IQaSTyK8YD8jVoVwD33VxI5dVkXF3ezHJPuX6vAIQmZIbSFVsM421MjMa88 YHg5PB6CbrhU3yvA8h+1/unRKy75PPyQGs5QBkdI= Authentication-Results: mail-nwsmtp-smtp-corp-canary-81.sas.yp-c.yandex.net; dkim=pass header.i=@yandex-team.ru From: Andrey Borodin Message-Id: <3EA622D2-635C-4C3E-9B64-90D1BAFD5C11@yandex-team.ru> Content-Type: multipart/mixed; boundary="Apple-Mail=_B2948CE5-F505-4241-8EB5-AA0D470573ED" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.300.41.1.7\)) Subject: Re: 17.8 standby crashes during WAL replay from 17.5 primary: "could not access status of transaction" Date: Wed, 18 Feb 2026 13:58:03 +0500 In-Reply-To: <79171a15-1bb9-44ea-b2a9-1904f13364e6@iki.fi> Cc: Kirill Reshke , Sebastian Webber , pgsql-bugs@lists.postgresql.org, Andrey Borodin , =?utf-8?Q?=C3=81lvaro_Herrera?= , Dmitry Yurichev , Chao Li , Ivan Bykov To: Heikki Linnakangas References: <349f9c82-3a8b-48ad-8cc4-fe81553793dd@iki.fi> <79171a15-1bb9-44ea-b2a9-1904f13364e6@iki.fi> X-Mailer: Apple Mail (2.3864.300.41.1.7) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_B2948CE5-F505-4241-8EB5-AA0D470573ED Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii > On 16 Feb 2026, at 21:01, Heikki Linnakangas wrote: >=20 > Andrey if you can verify with your TAP test, too, that'd be great. Here's a hand-wavy test on top of REL_17_STABLE. It modifies binaries to = simulate old WAL write behavior. I tried to hack it with -DDEMO_SIMULATE_OLD_MULTIXACT_BEHAVIOR, but gave = up and just hardcoded. We are not going to commit it, aren't we? If we comment out this line (patch does it) = pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number, pageno); the test will pass. Either way it will hang indefinitely because 2026-02-18 13:44:12.238 +05 [52360] LOG: started streaming WAL from = primary at 0/3000000 on timeline 1 2026-02-18 13:44:12.250 +05 [52359] FATAL: could not access status of = transaction 4096 2026-02-18 13:44:12.250 +05 [52359] DETAIL: Could not read from file = "pg_multixact/offsets/0000" at offset 16384: read too few bytes. 2026-02-18 13:44:12.250 +05 [52359] CONTEXT: WAL redo at 0/30245E0 for = MultiXact/CREATE_ID: 4095 offset 8189 nmembers 2: 4835 (sh) 4835 (upd) Most hand-wavy part is test_multixact_write_truncate_wal(): truncation = is synthetic. FWIW, a lot of calculations and commenting done by LLM. Let me know if = such a verbosity is not good for readability. Best regards, Andrey Borodin. --Apple-Mail=_B2948CE5-F505-4241-8EB5-AA0D470573ED Content-Disposition: attachment; filename=0001-Test-Multixact-truncation-near-page-boundary-replay-.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="0001-Test-Multixact-truncation-near-page-boundary-replay-.patch" Content-Transfer-Encoding: quoted-printable =46rom=20465eb45cffab0f8503a66288246a0416a0702071=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Andrey=20Borodin=20=0ADate:=20= Wed,=2018=20Feb=202026=2010:11:26=20+0500=0ASubject:=20[PATCH]=20Test=20= Multixact=20truncation=20near=20page-boundary=20replay=20on=0A=20standby=0A= =0AAdd=20a=20TAP=20test=20that=20reproduces=20the=20bug=20fixed=20by=20= commit=204a36c89f165:=0ATRUNCATE_ID=20WAL=20replay=20resets=20= latest_page_number,=20breaking=20the=0Ainit-next-page=20check=20in=20= RecordNewMultiXact.=20=20When=20a=20page-crossing=0ACREATE_ID=20is=20= replayed=20after=20a=20TRUNCATE_ID=20whose=20endTruncOff=20lands=20on=0A= a=20different=20page,=20the=20standby=20startup=20process=20crashes=20= with:=0A=0A=20=20FATAL:=20could=20not=20access=20status=20of=20= transaction=20...=0A=20=20DETAIL:=20Could=20not=20read=20from=20file=20= "pg_multixact/offsets/..."=20read=20too=20few=20bytes.=0A=0ATo=20trigger=20= the=20bug=20reliably=20in=20a=20single-binary=20test,=20two=20additional=0A= changes=20to=20multixact.c=20simulate=20WAL=20from=20older=20minor=20= versions=0A(pre-8ba61bc063):=0A=0A=20=20-=20= ExtendMultiXactOffset(result)=20instead=20of=20(result=20+=201),=20so=20= the=0A=20=20=20=20primary=20does=20not=20pre-zero=20the=20next=20page=20= before=20the=20CREATE_ID.=0A=20=20-=20The=20"set=20next=20multixid's=20= offset"=20block=20in=20RecordNewMultiXact=20is=0A=20=20=20=20skipped=20= on=20the=20primary=20(!InRecovery)=20but=20kept=20during=20recovery,=0A=20= =20=20=20so=20the=20standby=20still=20tries=20to=20read=20the=20next=20= page.=0A=0AA=20helper=20function=20test_multixact_write_truncate_wal()=20= injects=20a=0ATRUNCATE_ID=20WAL=20record=20with=20a=20controlled=20= endTruncOff,=20simulating=0Athe=20concurrent=20truncation=20+=20= multixact=20creation=20that=20occurs=20in=0Aproduction.=0A=0AApply=20the=20= fix=20(0002-Don-t-reset-latest_page_number-when-replaying-=0A= multix.patch)=20on=20top=20of=20this=20patch=20to=20verify=20the=20test=20= passes.=0A---=0A=20src/backend/access/transam/multixact.c=20=20=20=20=20=20= =20=20|=20=2015=20++-=0A=20src/test/modules/test_slru/Makefile=20=20=20=20= =20=20=20=20=20=20=20|=20=20=204=20+-=0A=20= src/test/modules/test_slru/meson.build=20=20=20=20=20=20=20=20|=20=20=20= 6=20+=0A=20.../t/002_multixact_truncation_replay.pl=20=20=20=20=20=20|=20= =2095=20++++++++++++++++=0A=20= src/test/modules/test_slru/test_multixact.c=20=20=20|=20105=20= ++++++++++++++++++=0A=20src/test/modules/test_slru/test_slru--1.0.sql=20= |=20=20=207=20++=0A=206=20files=20changed,=20228=20insertions(+),=204=20= deletions(-)=0A=20create=20mode=20100644=20= src/test/modules/test_slru/t/002_multixact_truncation_replay.pl=0A=20= create=20mode=20100644=20src/test/modules/test_slru/test_multixact.c=0A=0A= diff=20--git=20a/src/backend/access/transam/multixact.c=20= b/src/backend/access/transam/multixact.c=0Aindex=20= c863e4e0556..e1fc55d0745=20100644=0A---=20= a/src/backend/access/transam/multixact.c=0A+++=20= b/src/backend/access/transam/multixact.c=0A@@=20-996,7=20+996,15=20@@=20= RecordNewMultiXact(MultiXactId=20multi,=20MultiXactOffset=20offset,=0A=20= =0A=20=09/*=0A=20=09=20*=20Set=20the=20next=20multixid's=20offset=20to=20= the=20end=20of=20this=20multixid's=20members.=0A+=09=20*=0A+=09=20*=20On=20= the=20primary=20(!InRecovery),=20skip=20this=20to=20produce=20WAL=20= without=20the=20next=0A+=09=20*=20offset=20already=20set=20=E2=80=94=20= simulating=20pre-8ba61bc063=20behavior.=20=20During=0A+=09=20*=20= recovery,=20keep=20this=20code=20so=20the=20standby=20tries=20to=20read=20= the=20next=20page,=0A+=09=20*=20triggering=20the=20bug=20when=20the=20= init-next-page=20check=20fails=20due=20to=0A+=09=20*=20truncation=20= resetting=20latest_page_number.=0A=20=09=20*/=0A+=09if=20(InRecovery)=0A= +=09{=0A=20=09if=20(next_pageno=20=3D=3D=20pageno)=0A=20=09{=0A=20=09=09= next_offptr=20=3D=20offptr=20+=201;=0A@@=20-1027,6=20+1035,7=20@@=20= RecordNewMultiXact(MultiXactId=20multi,=20MultiXactOffset=20offset,=0A=20= =09=09*next_offptr=20=3D=20next_offset;=0A=20=09=09= MultiXactOffsetCtl->shared->page_dirty[slotno]=20=3D=20true;=0A=20=09}=0A= +=09}=0A=20=0A=20=09/*=20Release=20MultiXactOffset=20SLRU=20lock.=20*/=0A= =20=09LWLockRelease(lock);=0A@@=20-1227,7=20+1236,7=20@@=20= GetNewMultiXactId(int=20nmembers,=20MultiXactOffset=20*offset)=0A=20=09=20= *=20Make=20sure=20there=20is=20room=20for=20the=20next=20MXID=20in=20the=20= file.=20=20Assigning=20this=0A=20=09=20*=20MXID=20sets=20the=20next=20= MXID's=20offset=20already.=0A=20=09=20*/=0A-=09= ExtendMultiXactOffset(result=20+=201);=0A+=09= ExtendMultiXactOffset(result);=0A=20=0A=20=09/*=0A=20=09=20*=20Reserve=20= the=20members=20space,=20similarly=20to=20above.=20=20Also,=20be=20= careful=20not=20to=0A@@=20-3603,8=20+3612,8=20@@=20= multixact_redo(XLogReaderState=20*record)=0A=20=09=09=20*=20= SimpleLruTruncate.=0A=20=09=09=20*/=0A=20=09=09pageno=20=3D=20= MultiXactIdToOffsetPage(xlrec.endTruncOff);=0A-=09=09= pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,=0A-=09= =09=09=09=09=09=09pageno);=0A+=09=09//=20= pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,=0A+=09= =09//=20=09=09=09=09=09pageno);=0A=20=09=09= PerformOffsetsTruncation(xlrec.startTruncOff,=20xlrec.endTruncOff);=0A=20= =0A=20=09=09LWLockRelease(MultiXactTruncationLock);=0Adiff=20--git=20= a/src/test/modules/test_slru/Makefile=20= b/src/test/modules/test_slru/Makefile=0Aindex=20936886753b7..8870e49da85=20= 100644=0A---=20a/src/test/modules/test_slru/Makefile=0A+++=20= b/src/test/modules/test_slru/Makefile=0A@@=20-3,7=20+3,8=20@@=0A=20= MODULE_big=20=3D=20test_slru=0A=20OBJS=20=3D=20\=0A=20=09$(WIN32RES)=20\=0A= -=09test_slru.o=0A+=09test_slru.o=20\=0A+=09test_multixact.o=0A=20= PGFILEDESC=20=3D=20"test_slru=20-=20test=20module=20for=20SLRUs"=0A=20=0A= =20EXTENSION=20=3D=20test_slru=0A@@=20-11,6=20+12,7=20@@=20DATA=20=3D=20= test_slru--1.0.sql=0A=20=0A=20REGRESS_OPTS=20=3D=20--temp-config=20= $(top_srcdir)/src/test/modules/test_slru/test_slru.conf=0A=20REGRESS=20=3D= =20test_slru=0A+TAP_TESTS=20=3D=201=0A=20#=20Disabled=20because=20these=20= tests=20require=20"shared_preload_libraries=3Dtest_slru",=0A=20#=20which=20= typical=20installcheck=20users=20do=20not=20have=20(e.g.=20buildfarm=20= clients).=0A=20NO_INSTALLCHECK=20=3D=201=0Adiff=20--git=20= a/src/test/modules/test_slru/meson.build=20= b/src/test/modules/test_slru/meson.build=0Aindex=20= ce91e606313..f589b3ec358=20100644=0A---=20= a/src/test/modules/test_slru/meson.build=0A+++=20= b/src/test/modules/test_slru/meson.build=0A@@=20-2,6=20+2,7=20@@=0A=20=0A= =20test_slru_sources=20=3D=20files(=0A=20=20=20'test_slru.c',=0A+=20=20= 'test_multixact.c',=0A=20)=0A=20=0A=20if=20host_system=20=3D=3D=20= 'windows'=0A@@=20-32,4=20+33,9=20@@=20tests=20+=3D=20{=0A=20=20=20=20=20= 'regress_args':=20['--temp-config',=20files('test_slru.conf')],=0A=20=20=20= =20=20'runningcheck':=20false,=0A=20=20=20},=0A+=20=20'tap':=20{=0A+=20=20= =20=20'tests':=20[=0A+=20=20=20=20=20=20= 't/002_multixact_truncation_replay.pl',=0A+=20=20=20=20],=0A+=20=20},=0A=20= }=0Adiff=20--git=20= a/src/test/modules/test_slru/t/002_multixact_truncation_replay.pl=20= b/src/test/modules/test_slru/t/002_multixact_truncation_replay.pl=0Anew=20= file=20mode=20100644=0Aindex=2000000000000..4a4140e8bd2=0A---=20= /dev/null=0A+++=20= b/src/test/modules/test_slru/t/002_multixact_truncation_replay.pl=0A@@=20= -0,0=20+1,95=20@@=0A+#=20Copyright=20(c)=202024-2026,=20PostgreSQL=20= Global=20Development=20Group=0A+=0A+#=20Test=20multixact=20SLRU=20= truncation=20replay=20on=20standby.=0A+#=0A+#=20Reproduces=20the=20bug=20= fixed=20by=20commit=204a36c89f165:=20during=20TRUNCATE_ID=20replay,=0A+#=20= latest_page_number=20was=20reset=20to=20= MultiXactIdToOffsetPage(endTruncOff).=20=20This=0A+#=20broke=20the=20= init-next-page=20check=20in=20RecordNewMultiXact,=20which=20compares=0A= +#=20latest_page_number=20=3D=3D=20pageno.=20=20If=20a=20CREATE_ID=20= that=20crosses=20a=20page=20boundary=0A+#=20is=20replayed=20AFTER=20a=20= TRUNCATE_ID=20whose=20endTruncOff=20is=20on=20a=20different=20page,=0A+#=20= the=20init=20check=20doesn't=20fire,=20the=20next=20page=20isn't=20= initialized,=20and=0A+#=20SimpleLruReadPage=20fails=20with=20FATAL.=0A+#=0A= +#=20The=20test=20uses=20test_multixact_write_truncate_wal()=20to=20= inject=20a=20TRUNCATE_ID=0A+#=20WAL=20record=20with=20endTruncOff=20on=20= page=200,=20placed=20between=20two=20batches=20of=0A+#=20CREATE_IDs.=20=20= This=20simulates=20the=20real-world=20scenario=20where=20truncation=20= runs=0A+#=20concurrently=20with=20multixact=20creation.=0A+#=0A+#=20To=20= produce=20WAL=20without=20a=20pre-zeroed=20next=20page=20(as=20older=20= minor=20versions=20did=0A+#=20before=208ba61bc063),=20two=20changes=20in=20= multixact.c=20are=20required:=0A+#=20=20=20-=20= ExtendMultiXactOffset(result)=20instead=20of=20(result=20+=201)=0A+#=20=20= =20-=20next-offset=20write=20in=20RecordNewMultiXact=20skipped=20on=20= primary=0A+=0A+use=20strict;=0A+use=20warnings=20FATAL=20=3D>=20'all';=0A= +=0A+use=20PostgreSQL::Test::Cluster;=0A+use=20PostgreSQL::Test::Utils;=0A= +=0A+use=20Test::More;=0A+=0A+#=20MULTIXACT_OFFSETS_PER_PAGE=20=3D=20= BLCKSZ/4=20=3D=202048=20(for=208kB=20blocks).=0A+#=0A+#=20Scenario:=0A+#=20= =20=201.=20Create=202046=20multixacts=20(multis=201..2046).=20=20= nextMXact=20=3D=202047,=20page=200.=0A+#=20=20=202.=20Take=20backup.=0A= +#=20=20=203.=20Create=202048=20MORE=20multixacts=20(2047..4094).=20=20= Multi=202047=20crosses=20page=200->1.=0A+#=20=20=204.=20Inject=20= TRUNCATE_ID=20with=20endTruncOff=20=3D=2010=20(page=200).=0A+#=20=20=20= 5.=20Create=201=20more=20multixact=20(4095),=20last=20entry=20on=20page=20= 1,=20crossing=20to=20page=202.=0A+#=0A+#=20On=20the=20standby:=0A+#=20=20= =20-=20StartupMultiXact=20sets=20latest_page_number=20=3D=20page(2047)=20= =3D=200=0A+#=20=20=20-=20CREATE_ID(2047)=20crosses=20page=200->1:=20init=20= check=20fires=20(0=3D=3D0),=20zeros=20page=201,=0A+#=20=20=20=20=20= latest_page_number=20updated=20to=201=20by=20SimpleLruZeroPage=0A+#=20=20= =20-=20CREATE_IDs=20for=202048..4094=20on=20page=201=20(no=20crossings)=0A= +#=20=20=20-=20TRUNCATE_ID(endTruncOff=3D10):=20latest_page_number=20= reset=20to=20page(10)=20=3D=200=0A+#=20=20=20-=20CREATE_ID(4095):=20= pageno=3D1,=20next_pageno=3D2=0A+#=20=20=20=20=20Init=20check:=20= latest_page_number(0)=20!=3D=20pageno(1)=20->=20SKIP=0A+#=20=20=20=20=20= RecordNewMultiXact=20tries=20SimpleLruReadPage(page=202)=20->=20FATAL=0A= +#=0A+#=20With=20the=20fix=20(not=20resetting=20latest_page_number=20in=20= TRUNCATE_ID=20replay):=0A+#=20=20=20-=20latest_page_number=20stays=201=20= after=20the=20page=200->1=20crossing=0A+#=20=20=20-=20Init=20check=20at=20= CREATE_ID(4095):=20latest_page_number(1)=20=3D=3D=20pageno(1)=20->=20= fires=0A+#=20=20=20-=20Page=202=20is=20initialized=20->=20replay=20= succeeds=0A+=0A+my=20$node_primary=20=3D=20= PostgreSQL::Test::Cluster->new('main');=0A= +$node_primary->init(allows_streaming=20=3D>=20'physical');=0A= +$node_primary->append_conf('postgresql.conf',=0A+=09= "shared_preload_libraries=20=3D=20'test_slru'");=0A= +$node_primary->start;=0A+$node_primary->safe_psql('postgres',=20= q(CREATE=20EXTENSION=20test_slru));=0A+=0A+#=20Fill=20page=200:=20multis=20= 1..2046,=20nextMXact=20=3D=202047=0A= +$node_primary->safe_psql('postgres',=20q{SELECT=20= test_create_multixacts(2046)});=0A+=0A= +$node_primary->backup('mx_backup');=0A+=0A+#=20Fill=20page=201:=20= multis=202047..4094,=20nextMXact=20=3D=204095.=0A+#=20Multi=202047=20= crosses=20page=200->1;=20on=20the=20standby=20the=20init=20check=20zeros=20= page=201.=0A+$node_primary->safe_psql('postgres',=20q{SELECT=20= test_create_multixacts(2048)});=0A+=0A+#=20Inject=20TRUNCATE_ID=20with=20= endTruncOff=20on=20page=200.=0A+#=20On=20the=20standby=20this=20resets=20= latest_page_number=20from=201=20back=20to=200.=0A= +$node_primary->safe_psql('postgres',=0A+=09q{SELECT=20= test_multixact_write_truncate_wal('10'::xid)});=0A+=0A+#=20Create=20= multi=204095=20(page=201,=20entry=202047)=20which=20crosses=20to=20page=20= 2.=0A+#=20Without=20the=20fix=20the=20standby=20crashes=20here:=20= latest_page_number(0)=20!=3D=20pageno(1).=0A= +$node_primary->safe_psql('postgres',=20q{SELECT=20= test_create_multixact()});=0A+$node_primary->safe_psql('postgres',=20= q{SELECT=20pg_switch_wal()});=0A+=0A+my=20$node_standby=20=3D=20= PostgreSQL::Test::Cluster->new('standby');=0A= +$node_standby->init_from_backup($node_primary,=20'mx_backup',=0A+=09= has_streaming=20=3D>=201);=0A+$node_standby->start;=0A+=0A+my=20= $primary_lsn=20=3D=20$node_primary->lsn('flush');=0A+my=20$replayed=20=3D=20= $node_standby->poll_query_until('postgres',=0A+=09qq{SELECT=20= '$primary_lsn'::pg_lsn=20<=3D=20pg_last_wal_replay_lsn()});=0A+=0A= +ok($replayed,=20"standby=20replayed=20TRUNCATE_ID=20+=20page-crossing=20= CREATE_ID");=0A+=0A+$node_standby->stop=20if=20$replayed;=0A= +$node_primary->stop;=0A+=0A+done_testing();=0Adiff=20--git=20= a/src/test/modules/test_slru/test_multixact.c=20= b/src/test/modules/test_slru/test_multixact.c=0Anew=20file=20mode=20= 100644=0Aindex=2000000000000..e2f6f6a738d=0A---=20/dev/null=0A+++=20= b/src/test/modules/test_slru/test_multixact.c=0A@@=20-0,0=20+1,105=20@@=0A= +/*-----------------------------------------------------------------------= --=0A+=20*=0A+=20*=20test_multixact.c=0A+=20*=09=09Support=20code=20for=20= multixact=20testing=0A+=20*=0A+=20*=20Portions=20Copyright=20(c)=20= 1996-2024,=20PostgreSQL=20Global=20Development=20Group=0A+=20*=20= Portions=20Copyright=20(c)=201994,=20Regents=20of=20the=20University=20= of=20California=0A+=20*=0A+=20*=20IDENTIFICATION=0A+=20*=09=09= src/test/modules/test_slru/test_multixact.c=0A+=20*=0A+=20*=20= -------------------------------------------------------------------------=0A= +=20*/=0A+=0A+#include=20"postgres.h"=0A+=0A+#include=20= "access/multixact.h"=0A+#include=20"access/xact.h"=0A+#include=20= "access/xlog.h"=0A+#include=20"access/xloginsert.h"=0A+#include=20= "fmgr.h"=0A+#include=20"miscadmin.h"=0A+#include=20"utils/pg_lsn.h"=0A+=0A= +PG_FUNCTION_INFO_V1(test_create_multixact);=0A= +PG_FUNCTION_INFO_V1(test_create_multixacts);=0A= +PG_FUNCTION_INFO_V1(test_multixact_write_truncate_wal);=0A+=0A+/*=0A+=20= *=20Produces=20multixact=20with=202=20current=20xids=0A+=20*/=0A+Datum=0A= +test_create_multixact(PG_FUNCTION_ARGS)=0A+{=0A+=09MultiXactId=20id;=0A= +=0A+=09MultiXactIdSetOldestMember();=0A+=09id=20=3D=20= MultiXactIdCreate(GetCurrentTransactionId(),=20MultiXactStatusUpdate,=0A= +=09=09=09=09=09=09=20=20=20GetCurrentTransactionId(),=20= MultiXactStatusForShare);=0A+=09PG_RETURN_TRANSACTIONID(id);=0A+}=0A+=0A= +/*=0A+=20*=20Create=20n=20multixacts.=20=20Used=20to=20quickly=20fill=20= offset=20pages=20for=20truncation=20tests.=0A+=20*=0A+=20*=20Each=20= iteration=20uses=20a=20subtransaction=20so=20that=20= GetCurrentTransactionId()=0A+=20*=20returns=20a=20different=20xid,=20= preventing=20mXactCacheGetBySet=20from=20returning=20a=0A+=20*=20cached=20= result=20and=20ensuring=20a=20new=20MultiXactId=20is=20allocated=20every=20= time.=0A+=20*/=0A+Datum=0A+test_create_multixacts(PG_FUNCTION_ARGS)=0A+{=0A= +=09int32=09=09n=20=3D=20PG_GETARG_INT32(0);=0A+=09MultiXactId=20= first_id=20=3D=20InvalidMultiXactId;=0A+=0A+=09if=20(n=20<=3D=200)=0A+=09= =09ereport(ERROR,=0A+=09=09=09=09= (errcode(ERRCODE_INVALID_PARAMETER_VALUE),=0A+=09=09=09=09=20errmsg("n=20= must=20be=20positive")));=0A+=0A+=09for=20(int=20i=20=3D=200;=20i=20<=20= n;=20i++)=0A+=09{=0A+=09=09MultiXactId=20id;=0A+=0A+=09=09= BeginInternalSubTransaction(NULL);=0A+=09=09= MultiXactIdSetOldestMember();=0A+=09=09id=20=3D=20= MultiXactIdCreate(GetCurrentTransactionId(),=20MultiXactStatusUpdate,=0A= +=09=09=09=09=09=09=09=20=20=20GetCurrentTransactionId(),=20= MultiXactStatusForShare);=0A+=09=09ReleaseCurrentSubTransaction();=0A+=0A= +=09=09if=20(i=20=3D=3D=200)=0A+=09=09=09first_id=20=3D=20id;=0A+=09}=0A= +=0A+=09PG_RETURN_TRANSACTIONID(first_id);=0A+}=0A+=0A+/*=0A+=20*=20= Write=20a=20TRUNCATE_ID=20WAL=20record=20with=20the=20given=20= endTruncOff.=0A+=20*=0A+=20*=20This=20is=20used=20to=20simulate=20a=20= truncation=20that=20sets=20latest_page_number=20to=20a=0A+=20*=20= specific=20page=20during=20standby=20replay,=20without=20actually=20= truncating=20anything=0A+=20*=20on=20the=20primary.=20=20The=20standby's=20= multixact_redo=20handler=20will=20reset=0A+=20*=20latest_page_number=20=3D= =20MultiXactIdToOffsetPage(endTruncOff).=0A+=20*/=0A+Datum=0A= +test_multixact_write_truncate_wal(PG_FUNCTION_ARGS)=0A+{=0A+=09= MultiXactId=20endTruncOff=20=3D=20PG_GETARG_TRANSACTIONID(0);=0A+=09= xl_multixact_truncate=20xlrec;=0A+=09XLogRecPtr=09recptr;=0A+=0A+=09= xlrec.oldestMultiDB=20=3D=20MyDatabaseId;=0A+=09xlrec.startTruncOff=20=3D=20= 1;=0A+=09xlrec.endTruncOff=20=3D=20endTruncOff;=0A+=09= xlrec.startTruncMemb=20=3D=200;=0A+=09xlrec.endTruncMemb=20=3D=200;=0A+=0A= +=09XLogBeginInsert();=0A+=09XLogRegisterData((char=20*)=20&xlrec,=20= SizeOfMultiXactTruncate);=0A+=09recptr=20=3D=20= XLogInsert(RM_MULTIXACT_ID,=20XLOG_MULTIXACT_TRUNCATE_ID);=0A+=09= XLogFlush(recptr);=0A+=0A+=09PG_RETURN_LSN(recptr);=0A+}=0Adiff=20--git=20= a/src/test/modules/test_slru/test_slru--1.0.sql=20= b/src/test/modules/test_slru/test_slru--1.0.sql=0Aindex=20= 202e8da3fde..0d6271473bf=20100644=0A---=20= a/src/test/modules/test_slru/test_slru--1.0.sql=0A+++=20= b/src/test/modules/test_slru/test_slru--1.0.sql=0A@@=20-19,3=20+19,10=20= @@=20CREATE=20OR=20REPLACE=20FUNCTION=20test_slru_page_truncate(bigint)=20= RETURNS=20VOID=0A=20=20=20AS=20'MODULE_PATHNAME',=20= 'test_slru_page_truncate'=20LANGUAGE=20C;=0A=20CREATE=20OR=20REPLACE=20= FUNCTION=20test_slru_delete_all()=20RETURNS=20VOID=0A=20=20=20AS=20= 'MODULE_PATHNAME',=20'test_slru_delete_all'=20LANGUAGE=20C;=0A+=0A= +CREATE=20OR=20REPLACE=20FUNCTION=20test_create_multixact()=20RETURNS=20= xid=0A+=20=20AS=20'MODULE_PATHNAME',=20'test_create_multixact'=20= LANGUAGE=20C;=0A+CREATE=20OR=20REPLACE=20FUNCTION=20= test_create_multixacts(int)=20RETURNS=20xid=0A+=20=20AS=20= 'MODULE_PATHNAME',=20'test_create_multixacts'=20LANGUAGE=20C;=0A+CREATE=20= OR=20REPLACE=20FUNCTION=20test_multixact_write_truncate_wal(xid)=20= RETURNS=20pg_lsn=0A+=20=20AS=20'MODULE_PATHNAME',=20= 'test_multixact_write_truncate_wal'=20LANGUAGE=20C;=0A--=20=0A2.51.2=0A=0A= --Apple-Mail=_B2948CE5-F505-4241-8EB5-AA0D470573ED--