On 14.06.2024 10:45, Anton A. Melnikov wrote:

The src/backend/access/heap/README.tuplock says about HEAP_XMAX_INVALID bit
that "Any tuple with this bit set does not have a valid value stored in XMAX."

Found that FreezeMultiXactId() tries to process such an invalid multi xmax
and may looks for an update xid in the pg_multixact for it.

Maybe not do this work in FreezeMultiXactId() and exit immediately if the
bit HEAP_XMAX_INVALID was already set?


Seems it is important to save the check that multi xmax is not behind 
relminmxid.
So saved it and correct README.tuplock accordingly.

Would be glad if someone take a look at the patch attached.


With the best regards,

--
Anton A. Melnikov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
From 7608078bddf35904427cb1c04497ab0c98e9d111 Mon Sep 17 00:00:00 2001
From: "Anton A. Melnikov" <a.melni...@postgrespro.ru>
Date: Fri, 14 Jun 2024 10:42:55 +0300
Subject: [PATCH] Don't process multi xmax in the FreezeMultiXactId() if the
 HEAP_XMAX_INVALID bit was already set.

---
 src/backend/access/heap/README.tuplock | 1 +
 src/backend/access/heap/heapam.c       | 8 ++++++++
 2 files changed, 9 insertions(+)

diff --git a/src/backend/access/heap/README.tuplock b/src/backend/access/heap/README.tuplock
index 6441e8baf0..e198942647 100644
--- a/src/backend/access/heap/README.tuplock
+++ b/src/backend/access/heap/README.tuplock
@@ -124,6 +124,7 @@ The following infomask bits are applicable:
 
 - HEAP_XMAX_INVALID
   Any tuple with this bit set does not have a valid value stored in XMAX.
+  Although if it's a multi xmax it must follow relminmxid.
 
 - HEAP_XMAX_IS_MULTI
   This bit is set if the tuple's Xmax is a MultiXactId (as opposed to a
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 82bb9cb33b..d1cba6970d 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -6227,6 +6227,14 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
 				(errcode(ERRCODE_DATA_CORRUPTED),
 				 errmsg_internal("found multixact %u from before relminmxid %u",
 								 multi, cutoffs->relminmxid)));
+	else if (MultiXactIdIsValid(multi) &&
+			(t_infomask & HEAP_XMAX_INVALID))
+	{
+		/* Xmax is already marked as invalid */
+		*flags |= FRM_INVALIDATE_XMAX;
+		pagefrz->freeze_required = true;
+		return InvalidTransactionId;
+	}
 	else if (MultiXactIdPrecedes(multi, cutoffs->OldestMxact))
 	{
 		TransactionId update_xact;
-- 
2.45.2

Reply via email to