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 1wTOiO-000V2G-2e for pgsql-bugs@arkaria.postgresql.org; Sat, 30 May 2026 18:47:21 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wTOiM-006HaU-2G for pgsql-bugs@arkaria.postgresql.org; Sat, 30 May 2026 18:47:19 +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 1wTOiM-006HaK-0q for pgsql-bugs@lists.postgresql.org; Sat, 30 May 2026 18:47:18 +0000 Received: from forwardcorp1d.mail.yandex.net ([178.154.239.200]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wTOiH-00000000Lgk-28L9 for pgsql-bugs@lists.postgresql.org; Sat, 30 May 2026 18:47:18 +0000 Received: from mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net (mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net [IPv6:2a02:6b8:c42:65a0:0:640:e1de:0]) by forwardcorp1d.mail.yandex.net (Yandex) with ESMTPS id 21F0480725; Sat, 30 May 2026 21:47:12 +0300 (MSK) Received: from smtpclient.apple (unknown [2a02:6bf:8080:85d::1:e]) by mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net (smtpcorp) with ESMTPSA id Alh1Ur0X5Sw0-xIrEZ2Jy; Sat, 30 May 2026 21:47:11 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex-team.ru; s=default; t=1780166831; bh=VbBp724FDFwg5BlUZGUSCX8YpWK7jjELhQ2SNzkZJcM=; h=References:To:Cc:In-Reply-To:Date:From:Message-Id:Subject; b=MmDwpqP/phsCjcwmv/FFLkaZjBXfFS3Jkk3or5r0KLNvWhp1DFCZw6CcW93Zu8X9q WPFLRGP1Ev+qoF5qGixNs7pbTK4jZONVQUctIf5rqrxocEf057Z9ViLIH9UdlJR0pb Qhz7JL00Q6ymmb4tk8KUuQGJiVZ2j6KFbl8z2Ads= Authentication-Results: mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net; dkim=pass header.i=@yandex-team.ru From: Andrey Borodin Message-Id: <1F2F4318-437C-4AE1-8413-F94FBDD5AB68@yandex-team.ru> Content-Type: multipart/mixed; boundary="Apple-Mail=_4A6A8366-D42D-4F1F-932A-B24B0FB9722D" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.600.51.1.1\)) Subject: Re: Possible G2-item at SERIALIZABLE Date: Sat, 30 May 2026 23:47:00 +0500 In-Reply-To: <165342c0-0c75-461e-b334-b997639ad48d@aphyr.com> Cc: PostgreSQL mailing lists , samokhvalov@gmail.com, Kirk Wolak To: Kyle Kingsbury References: <165342c0-0c75-461e-b334-b997639ad48d@aphyr.com> X-Mailer: Apple Mail (2.3864.600.51.1.1) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_4A6A8366-D42D-4F1F-932A-B24B0FB9722D Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii > On 22 May 2026, at 21:44, Kyle Kingsbury wrote: >=20 > If y'all have any luck reproducing this, I'd love to hear about it! It looks like I've reproduced something similar with savepoints on HEAD = and REL_18_STABLE. I can't tell if it's really all what you observe. But, = probably, part of it. If that error is raised inside a subtransaction, ROLLBACK TO SAVEPOINT = swallows it and the transaction is free to COMMIT, defeating serializable isolation. I did not try beyond 18, but I think it always has been there. PFA attached isolation tester and hand-wavy fix. But I suspect there are = more G-items around. Full Jepsen test you proposed is currently tried by Nik's machines(in = cc). Best regards, Andrey Borodin. --Apple-Mail=_4A6A8366-D42D-4F1F-932A-B24B0FB9722D Content-Disposition: attachment; filename=v1-0001-Add-isolation-test-SSI-serialization-failure-swal.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v1-0001-Add-isolation-test-SSI-serialization-failure-swal.patch" Content-Transfer-Encoding: quoted-printable =46rom=205f0e1dce5974c48eaecb855d4676e497abfc0b1a=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Andrey=20Borodin=20=0ADate:=20= Sat,=2030=20May=202026=2023:07:39=20+0500=0ASubject:=20[PATCH=20v1=20= 1/2]=20Add=20isolation=20test:=20SSI=20serialization=20failure=0A=20= swallowed=20by=20SAVEPOINT=0A=0AIf=20that=20error=20is=20raised=20inside=20= a=20subtransaction,=20ROLLBACK=20TO=20SAVEPOINT=0Aswallows=20it=20and=20= the=20transaction=20is=20free=20to=20COMMIT,=20defeating=0Aserializable=20= isolation.=0A---=0A=20.../expected/serializable-savepoint.out=20=20=20=20= =20=20=20|=2025=20+++++++++=0A=20src/test/isolation/isolation_schedule=20= =20=20=20=20=20=20=20=20|=20=202=20+=0A=20= .../specs/serializable-savepoint.spec=20=20=20=20=20=20=20=20=20|=2052=20= +++++++++++++++++++=0A=203=20files=20changed,=2079=20insertions(+)=0A=20= create=20mode=20100644=20= src/test/isolation/expected/serializable-savepoint.out=0A=20create=20= mode=20100644=20src/test/isolation/specs/serializable-savepoint.spec=0A=0A= diff=20--git=20a/src/test/isolation/expected/serializable-savepoint.out=20= b/src/test/isolation/expected/serializable-savepoint.out=0Anew=20file=20= mode=20100644=0Aindex=2000000000000..0dd4f787efd=0A---=20/dev/null=0A+++=20= b/src/test/isolation/expected/serializable-savepoint.out=0A@@=20-0,0=20= +1,25=20@@=0A+Parsed=20test=20spec=20with=203=20sessions=0A+=0A+starting=20= permutation:=20r1=20w2=20w1=20c1=20sp2=20r2=20rb2=20c2=20rall=0A+step=20= r1:=20SELECT=20v=20FROM=20t=20WHERE=20id=20=3D=202;=0A+v=0A+-=0A+0=0A+(1=20= row)=0A+=0A+step=20w2:=20UPDATE=20t=20SET=20v=20=3D=201=20WHERE=20id=20=3D= =202;=0A+step=20w1:=20UPDATE=20t=20SET=20v=20=3D=201=20WHERE=20id=20=3D=20= 1;=0A+step=20c1:=20COMMIT;=0A+step=20sp2:=20SAVEPOINT=20f;=0A+step=20r2:=20= SELECT=20v=20FROM=20t=20WHERE=20id=20=3D=201;=0A+ERROR:=20=20could=20not=20= serialize=20access=20due=20to=20read/write=20dependencies=20among=20= transactions=0A+step=20rb2:=20ROLLBACK=20TO=20SAVEPOINT=20f;=0A+step=20= c2:=20COMMIT;=0A+ERROR:=20=20could=20not=20serialize=20access=20due=20to=20= read/write=20dependencies=20among=20transactions=0A+step=20rall:=20= SELECT=20id,=20v=20FROM=20t=20ORDER=20BY=20id;=0A+id|v=0A+--+-=0A+=201|1=0A= +=202|0=0A+(2=20rows)=0A+=0Adiff=20--git=20= a/src/test/isolation/isolation_schedule=20= b/src/test/isolation/isolation_schedule=0Aindex=20= 15c33fad4c5..62a334ad3d9=20100644=0A---=20= a/src/test/isolation/isolation_schedule=0A+++=20= b/src/test/isolation/isolation_schedule=0A@@=20-127,3=20+127,5=20@@=20= test:=20matview-write-skew=0A=20test:=20lock-nowait=0A=20test:=20= for-portion-of=0A=20test:=20ddl-dependency-locking=0A+=0A+test:=20= serializable-savepoint=0Adiff=20--git=20= a/src/test/isolation/specs/serializable-savepoint.spec=20= b/src/test/isolation/specs/serializable-savepoint.spec=0Anew=20file=20= mode=20100644=0Aindex=2000000000000..de61b615529=0A---=20/dev/null=0A+++=20= b/src/test/isolation/specs/serializable-savepoint.spec=0A@@=20-0,0=20= +1,52=20@@=0A+#=20Test=20that=20a=20serialization=20failure=20raised=20= while=20*checking*=20a=20read=20(the=0A+#=20"conflict=20out=20to=20= pivot,=20during=20read"=20cancellation)=20cannot=20be=20discarded=20by=0A= +#=20rolling=20back=20to=20a=20SAVEPOINT.=0A+#=0A+#=20s1=20and=20s2=20= form=20the=20classic=20write-skew=20dangerous=20structure=20under=20= SERIALIZABLE:=0A+#=20=20=20s1=20reads=20row=202=20and=20writes=20row=201=0A= +#=20=20=20s2=20writes=20row=202=20and=20reads=20row=201=0A+#=20s1=20= commits=20first.=20=20When=20s2=20then=20reads=20row=201=20it=20is=20= correctly=20identified=20as=20the=0A+#=20pivot=20of=20a=20dangerous=20= structure=20and=20PostgreSQL=20raises=0A+#=20=20=20ERROR:=20=20could=20= not=20serialize=20access=20...=0A+#=20=20=20(Canceled=20on=20conflict=20= out=20to=20pivot=20...,=20during=20read).=0A+#=0A+#=20Crucially,=20s2's=20= *write*=20to=20row=202=20happened=20BEFORE=20the=20savepoint,=20so=20it=20= is=20not=0A+#=20undone.=20=20s2=20only=20wraps=20the=20offending=20READ=20= in=20a=20SAVEPOINT,=20rolls=20back=20to=20it=0A+#=20(swallowing=20the=20= error)=20and=20commits.=20=20That=20COMMIT=20must=20fail:=20allowing=20= it=0A+#=20leaves=20both=20s1's=20and=20s2's=20writes=20committed,=20= which=20is=20the=20write-skew=20anomaly=0A+#=20SSI=20is=20supposed=20to=20= prevent=20(no=20serial=20order=20exists).=0A+=0A+setup=0A+{=0A+=20=20= CREATE=20TABLE=20t=20(id=20int=20PRIMARY=20KEY,=20v=20int);=0A+=20=20= INSERT=20INTO=20t=20VALUES=20(1,=200),=20(2,=200);=0A+}=0A+=0A+teardown=0A= +{=0A+=20=20DROP=20TABLE=20t;=0A+}=0A+=0A+session=20s1=0A+setup=20{=20= BEGIN=20ISOLATION=20LEVEL=20SERIALIZABLE;=20}=0A+step=20r1=20=20{=20= SELECT=20v=20FROM=20t=20WHERE=20id=20=3D=202;=20}=0A+step=20w1=20=20{=20= UPDATE=20t=20SET=20v=20=3D=201=20WHERE=20id=20=3D=201;=20}=0A+step=20c1=20= =20{=20COMMIT;=20}=0A+=0A+session=20s2=0A+setup=20{=20BEGIN=20ISOLATION=20= LEVEL=20SERIALIZABLE;=20}=0A+step=20w2=20=20=20{=20UPDATE=20t=20SET=20v=20= =3D=201=20WHERE=20id=20=3D=202;=20}=0A+step=20sp2=20=20{=20SAVEPOINT=20= f;=20}=0A+step=20r2=20=20=20{=20SELECT=20v=20FROM=20t=20WHERE=20id=20=3D=20= 1;=20}=0A+step=20rb2=20=20{=20ROLLBACK=20TO=20SAVEPOINT=20f;=20}=0A+step=20= c2=20=20=20{=20COMMIT;=20}=0A+=0A+#=20Used=20to=20observe=20the=20final=20= committed=20state.=0A+session=20s3=0A+step=20rall=20{=20SELECT=20id,=20v=20= FROM=20t=20ORDER=20BY=20id;=20}=0A+=0A+#=20s2=20takes=20its=20snapshot=20= at=20w2=20(before=20s1=20commits),=20writes=20row=202,=20then=20after=20= s1=0A+#=20commits=20it=20reads=20row=201=20inside=20a=20savepoint=20and=20= is=20cancelled.=20=20After=20rolling=0A+#=20back=20to=20the=20savepoint=20= it=20must=20not=20be=20able=20to=20commit.=20=20If=20it=20does=20(the=20= bug),=0A+#=20rall=20shows=20both=20rows=20updated=20--=20the=20= non-serializable=20write-skew=20outcome.=0A+permutation=20r1=20w2=20w1=20= c1=20sp2=20r2=20rb2=20c2=20rall=0A--=20=0A2.50.1=20(Apple=20Git-155)=0A=0A= --Apple-Mail=_4A6A8366-D42D-4F1F-932A-B24B0FB9722D Content-Disposition: attachment; filename=v1-0002-Doom-serializable-transaction-before-raising-seri.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v1-0002-Doom-serializable-transaction-before-raising-seri.patch" Content-Transfer-Encoding: quoted-printable =46rom=2028762ab32aaf01a07d8394886d6464de3a91cdb7=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Andrey=20Borodin=20=0ADate:=20= Sat,=2030=20May=202026=2023:07:47=20+0500=0ASubject:=20[PATCH=20v1=20= 2/2]=20Doom=20serializable=20transaction=20before=20raising=0A=20= serialization=20error=0A=0AOnConflict_CheckForSerializationFailure()=20= cancels=20the=20current=0Aserializable=20transaction=20with=20= ereport(ERROR)=20when=20it=20is=20identified=20as=20a=0Apivot,=20both=20= on=20the=20"during=20write"=20and=20the=20"during=20read"=20paths.=20=20= In=20both=0Acases=20it=20released=20SerializableXactHashLock=20and=20= raised=20the=20error=20without=0Asetting=20SXACT_FLAG_DOOMED=20on=20= MySerializableXact=20first;=20the=20writer=20is=20only=0Adoomed=20= afterwards,=20which=20the=20ereport()=20longjmp=20skips=20for=20the=20= current=0Atransaction.=0A=0AIf=20the=20error=20is=20caught=20by=20a=20= subtransaction=20abort=20(ROLLBACK=20TO=0ASAVEPOINT),=20the=20= transaction=20is=20not=20doomed=20and=20is=20allowed=20to=20COMMIT,=0A= which=20violates=20serializability.=20=20Set=20SXACT_FLAG_DOOMED=20on=20= ourselves=0Abefore=20raising=20the=20error=20so=20that=20= PreCommit_CheckForSerializationFailure()=0Acatches=20the=20transaction=20= at=20commit=20time=20even=20if=20the=20error=20was=20swallowed.=0A---=0A=20= src/backend/storage/lmgr/predicate.c=20|=2013=20+++++++++++--=0A=201=20= file=20changed,=2011=20insertions(+),=202=20deletions(-)=0A=0Adiff=20= --git=20a/src/backend/storage/lmgr/predicate.c=20= b/src/backend/storage/lmgr/predicate.c=0Aindex=20= 0ae85b7d5b4..461e899727b=20100644=0A---=20= a/src/backend/storage/lmgr/predicate.c=0A+++=20= b/src/backend/storage/lmgr/predicate.c=0A@@=20-4589,6=20+4589,12=20@@=20= OnConflict_CheckForSerializationFailure(const=20SERIALIZABLEXACT=20= *reader,=0A=20=09=09=20*/=0A=20=09=09if=20(MySerializableXact=20=3D=3D=20= writer)=0A=20=09=09{=0A+=09=09=09/*=0A+=09=09=09=20*=20Mark=20ourselves=20= doomed=20before=20raising=20the=20error.=20=20Otherwise=20a=0A+=09=09=09=20= *=20subtransaction=20abort=20(ROLLBACK=20TO=20SAVEPOINT)=20could=20= swallow=20this=0A+=09=09=09=20*=20error=20and=20let=20the=20transaction=20= commit=20anyway,=20defeating=20SSI.=0A+=09=09=09=20*/=0A+=09=09=09= MySerializableXact->flags=20|=3D=20SXACT_FLAG_DOOMED;=0A=20=09=09=09= LWLockRelease(SerializableXactHashLock);=0A=20=09=09=09ereport(ERROR,=0A=20= =09=09=09=09=09(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),=0A@@=20= -4598,10=20+4604,13=20@@=20OnConflict_CheckForSerializationFailure(const=20= SERIALIZABLEXACT=20*reader,=0A=20=09=09}=0A=20=09=09else=20if=20= (SxactIsPrepared(writer))=0A=20=09=09{=0A-=09=09=09= LWLockRelease(SerializableXactHashLock);=0A-=0A=20=09=09=09/*=20if=20= we're=20not=20the=20writer,=20we=20have=20to=20be=20the=20reader=20*/=0A=20= =09=09=09Assert(MySerializableXact=20=3D=3D=20reader);=0A+=0A+=09=09=09= /*=20See=20comment=20above:=20doom=20ourselves=20before=20raising=20the=20= error.=20*/=0A+=09=09=09MySerializableXact->flags=20|=3D=20= SXACT_FLAG_DOOMED;=0A+=09=09=09LWLockRelease(SerializableXactHashLock);=0A= +=0A=20=09=09=09ereport(ERROR,=0A=20=09=09=09=09=09= (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),=0A=20=09=09=09=09=09=20= errmsg("could=20not=20serialize=20access=20due=20to=20read/write=20= dependencies=20among=20transactions"),=0A--=20=0A2.50.1=20(Apple=20= Git-155)=0A=0A= --Apple-Mail=_4A6A8366-D42D-4F1F-932A-B24B0FB9722D--