From a070c3d806a1d05bab24d040ad4a3bdb0a951b60 Mon Sep 17 00:00:00 2001
From: Peter Geoghegan <pg@bowt.ie>
Date: Thu, 29 Dec 2022 13:25:24 -0800
Subject: [PATCH] Prefer FRM_INVALIDATE_XMAX over FRM_NOOP when cheaper.

---
 src/backend/access/heap/heapam.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 34d83dc70..0bc7d27d7 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -6146,7 +6146,8 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
 	TransactionId newxmax;
 	MultiXactMember *members;
 	int			nmembers;
-	bool		need_replace;
+	bool		need_replace,
+				cheap_to_replace;
 	int			nnewmembers;
 	MultiXactMember *newmembers;
 	bool		has_lockers;
@@ -6262,6 +6263,7 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
 	 * OldestXmin/OldestMxact, so later values never need to be tracked here.)
 	 */
 	need_replace = false;
+	cheap_to_replace = true;
 	FreezePageRelfrozenXid = pagefrz->FreezePageRelfrozenXid;
 	for (int i = 0; i < nmembers; i++)
 	{
@@ -6275,6 +6277,8 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
 			need_replace = true;
 			break;
 		}
+		if (TransactionIdFollowsOrEquals(xid, cutoffs->OldestXmin))
+			cheap_to_replace = false;
 		if (TransactionIdPrecedes(xid, FreezePageRelfrozenXid))
 			FreezePageRelfrozenXid = xid;
 	}
@@ -6283,7 +6287,12 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
 	if (!need_replace)
 		need_replace = MultiXactIdPrecedes(multi, cutoffs->MultiXactCutoff);
 
-	if (!need_replace)
+	/*
+	 * FRM_NOOP isn't cheaper than a second pass that indicates that xmax gets
+	 * FRM_INVALIDATE_XMAX processing.  Avoid FRM_NOOP whenever we've already
+	 * determined that doing a second pass will be cheaper (and more useful).
+	 */
+	if (!need_replace && !cheap_to_replace)
 	{
 		/*
 		 * vacuumlazy.c might ratchet back NewRelminMxid, NewRelfrozenXid, or
@@ -6424,6 +6433,7 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
 		 * interesting, because those are longer-lived.)
 		 */
 		Assert(nnewmembers == 1);
+		Assert(need_replace);
 		*flags |= FRM_RETURN_IS_XID;
 		if (update_committed)
 			*flags |= FRM_MARK_COMMITTED;
@@ -6435,6 +6445,7 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
 		 * Create a new multixact with the surviving members of the previous
 		 * one, to set as new Xmax in the tuple
 		 */
+		Assert(need_replace);
 		newxmax = MultiXactIdCreateFromMembers(nnewmembers, newmembers);
 		*flags |= FRM_RETURN_IS_MULTI;
 	}
-- 
2.38.1

