From 496966a89acca5eb8e406571637ad00d0135cb5c Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Fri, 30 Jul 2021 17:27:16 +1200
Subject: [PATCH v3 1/2] Fix race in SERIALIZABLE READ ONLY.

Commit bdaabb9b started skipping doomed transactions when building the
list of possible conflicts, when obtaining a snapshot for SERIALIZABLE
READ ONLY.  This had two unintended consequences:

1.  With unlucky timing, a transaction will never benefit from the
SXACT_FLAG_RO_SAFE optimization, because no one will ever set the flag.

2.  In the same circumstances but with DEFERRABLE, an assertion that
SXACT_FLAG_RO_SAFE has been set fails.

This is really exactly the same as the "opt out" case for
PredXact->WritableSxactCount == 0, it just happens a bit later in racy
conditions.  We should "opt out" in the same way in this case too.

Back-patch to all supported releases.  Discovered along with bug #17116,
but a separate commit to back-patch further.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Discussion: https://postgr.es/m/17116-d6ca217acc180e30%40postgresql.org
---
 src/backend/storage/lmgr/predicate.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 6b5a416873..99386d36a2 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -1839,6 +1839,19 @@ GetSerializableTransactionSnapshotInt(Snapshot snapshot,
 				SetPossibleUnsafeConflict(sxact, othersxact);
 			}
 		}
+
+		/*
+		 * If we didn't find any possibly unsafe conflicts because every
+		 * uncommitted writable transaction turned out to be doomed (which
+		 * should be rare), then we can "opt out" immediately.  This is a
+		 * variation of the opt out for PredXact->WritableSxactCount == 0.
+		 */
+		if (dlist_is_empty(&sxact->possibleUnsafeConflicts))
+		{
+			ReleasePredXact(sxact);
+			LWLockRelease(SerializableXactHashLock);
+			return snapshot;
+		}
 	}
 	else
 	{
-- 
2.39.1

