From c24c7ca65f9ad5f777d5fa642c2d4f63020225eb 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 v4 2/2] Fix race in SERIALIZABLE READ ONLY.

Commit bdaabb9b skipped 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.

Go ahead and set the flag immediately if the list turns out to be empty.
(We could also free the SERIALIZABLEXACT immediately, but this change
seems simpler.)

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 | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 41688d8078..93632f1522 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -1900,6 +1900,13 @@ GetSerializableTransactionSnapshotInt(Snapshot snapshot,
 				SetPossibleUnsafeConflict(sxact, othersxact);
 			}
 		}
+
+		/*
+		 * If we didn't find any possibly unsafe conflicts.  Set our own
+		 * SXACT_FLAG_RO_SAFE flag immediately, because no one else will.
+		 */
+		if (SHMQueueEmpty(&sxact->possibleUnsafeConflicts))
+			sxact->flags |= SXACT_FLAG_RO_SAFE;
 	}
 	else
 	{
-- 
2.30.2

