From 2605d6260ae63adbb3713fe25ac14b59948de680 Mon Sep 17 00:00:00 2001
From: Jakub Wartak <jakub.wartak@enterprisedb.com>
Date: Mon, 1 Dec 2025 13:28:54 +0100
Subject: [PATCH v3 2/2] wait_event_arg: provide quick and dump demo of
 multixact passthrough to LWLockReportWaitStart()

---
 contrib/amcheck/verify_heapam.c             |  2 +-
 contrib/pgrowlocks/pgrowlocks.c             |  2 +-
 src/backend/access/heap/heapam.c            | 82 +++++++++++----------
 src/backend/access/heap/heapam_visibility.c | 22 +++---
 src/backend/access/transam/multixact.c      | 42 ++++++-----
 src/backend/storage/lmgr/lwlock.c           | 19 +++--
 src/backend/utils/adt/multixactfuncs.c      |  2 +-
 src/include/access/htup.h                   |  2 +-
 src/include/access/htup_details.h           |  2 +-
 src/include/access/multixact.h              | 10 ++-
 src/include/storage/lwlock.h                |  1 +
 src/test/modules/test_slru/test_multixact.c |  4 +-
 12 files changed, 107 insertions(+), 83 deletions(-)

diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c
index 4963e9245cb..27917e694f8 100644
--- a/contrib/amcheck/verify_heapam.c
+++ b/contrib/amcheck/verify_heapam.c
@@ -1397,7 +1397,7 @@ check_tuple_visibility(HeapCheckContext *ctx, bool *xmin_commit_status_ok,
 		 * We already checked above that this multixact is within limits for
 		 * this table.  Now check the update xid from this multixact.
 		 */
-		xmax = HeapTupleGetUpdateXid(tuphdr);
+		xmax = HeapTupleGetUpdateXid(tuphdr, 0); /* DEMO: we do not care */
 		switch (get_xid_status(xmax, ctx, &xmax_status))
 		{
 			case XID_INVALID:
diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c
index f88269332b6..d4b8b15530f 100644
--- a/contrib/pgrowlocks/pgrowlocks.c
+++ b/contrib/pgrowlocks/pgrowlocks.c
@@ -157,7 +157,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
 
 				allow_old = HEAP_LOCKED_UPGRADED(infomask);
 				nmembers = GetMultiXactIdMembers(xmax, &members, allow_old,
-												 false);
+												 false, rel->rd_locator.relNumber);
 				if (nmembers == -1)
 				{
 					values[Atnum_xids] = "{0}";
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 4d382a04338..06083ee2252 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -84,14 +84,14 @@ static void compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
 									  uint16 old_infomask2, TransactionId add_to_xmax,
 									  LockTupleMode mode, bool is_update,
 									  TransactionId *result_xmax, uint16 *result_infomask,
-									  uint16 *result_infomask2);
+									  uint16 *result_infomask2, RelFileNumber r);
 static TM_Result heap_lock_updated_tuple(Relation rel, HeapTuple tuple,
 										 const ItemPointerData *ctid, TransactionId xid,
 										 LockTupleMode mode);
 static void GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask,
-								   uint16 *new_infomask2);
+								   uint16 *new_infomask2, RelFileNumber r);
 static TransactionId MultiXactIdGetUpdateXid(TransactionId xmax,
-											 uint16 t_infomask);
+											 uint16 t_infomask, RelFileNumber r);
 static bool DoesMultiXactIdConflict(MultiXactId multi, uint16 infomask,
 									LockTupleMode lockmode, bool *current_is_member);
 static void MultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask,
@@ -3065,7 +3065,8 @@ l1:
 	compute_new_xmax_infomask(HeapTupleHeaderGetRawXmax(tp.t_data),
 							  tp.t_data->t_infomask, tp.t_data->t_infomask2,
 							  xid, LockTupleExclusive, true,
-							  &new_xmax, &new_infomask, &new_infomask2);
+							  &new_xmax, &new_infomask, &new_infomask2,
+							  relation->rd_locator.relNumber);
 
 	START_CRIT_SECTION();
 
@@ -3615,7 +3616,7 @@ l2:
 			 * subxact aborts.
 			 */
 			if (!HEAP_XMAX_IS_LOCKED_ONLY(oldtup.t_data->t_infomask))
-				update_xact = HeapTupleGetUpdateXid(oldtup.t_data);
+				update_xact = HeapTupleGetUpdateXid(oldtup.t_data, relation->rd_locator.relNumber);
 			else
 				update_xact = InvalidTransactionId;
 
@@ -3758,7 +3759,8 @@ l2:
 							  oldtup.t_data->t_infomask2,
 							  xid, *lockmode, true,
 							  &xmax_old_tuple, &infomask_old_tuple,
-							  &infomask2_old_tuple);
+							  &infomask2_old_tuple,
+							  relation->rd_locator.relNumber);
 
 	/*
 	 * And also prepare an Xmax value for the new copy of the tuple.  If there
@@ -3790,7 +3792,7 @@ l2:
 		if (oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI)
 		{
 			GetMultiXactIdHintBits(xmax_new_tuple, &infomask_new_tuple,
-								   &infomask2_new_tuple);
+								   &infomask2_new_tuple, relation->rd_locator.relNumber);
 		}
 		else
 		{
@@ -3875,7 +3877,8 @@ l2:
 								  oldtup.t_data->t_infomask2,
 								  xid, *lockmode, false,
 								  &xmax_lock_old_tuple, &infomask_lock_old_tuple,
-								  &infomask2_lock_old_tuple);
+								  &infomask2_lock_old_tuple,
+								  relation->rd_locator.relNumber);
 
 		Assert(HEAP_XMAX_IS_LOCKED_ONLY(infomask_lock_old_tuple));
 
@@ -4706,7 +4709,8 @@ l3:
 				 */
 				nmembers =
 					GetMultiXactIdMembers(xwait, &members, false,
-										  HEAP_XMAX_IS_LOCKED_ONLY(infomask));
+										  HEAP_XMAX_IS_LOCKED_ONLY(infomask),
+										  relation->rd_locator.relNumber);
 
 				for (i = 0; i < nmembers; i++)
 				{
@@ -5186,7 +5190,8 @@ failed:
 	 */
 	compute_new_xmax_infomask(xmax, old_infomask, tuple->t_data->t_infomask2,
 							  GetCurrentTransactionId(), mode, false,
-							  &xid, &new_infomask, &new_infomask2);
+							  &xid, &new_infomask, &new_infomask2,
+							  relation->rd_locator.relNumber);
 
 	START_CRIT_SECTION();
 
@@ -5353,7 +5358,7 @@ compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
 						  uint16 old_infomask2, TransactionId add_to_xmax,
 						  LockTupleMode mode, bool is_update,
 						  TransactionId *result_xmax, uint16 *result_infomask,
-						  uint16 *result_infomask2)
+						  uint16 *result_infomask2, RelFileNumber r)
 {
 	TransactionId new_xmax;
 	uint16		new_infomask,
@@ -5448,7 +5453,7 @@ l5:
 		{
 			if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask) ||
 				!TransactionIdDidCommit(MultiXactIdGetUpdateXid(xmax,
-																old_infomask)))
+																old_infomask, 11)))
 			{
 				/*
 				 * Reset these bits and restart; otherwise fall through to
@@ -5463,8 +5468,8 @@ l5:
 		new_status = get_mxact_status_for_lock(mode, is_update);
 
 		new_xmax = MultiXactIdExpand((MultiXactId) xmax, add_to_xmax,
-									 new_status);
-		GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
+									 new_status, r);
+		GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2, r);
 	}
 	else if (old_infomask & HEAP_XMAX_COMMITTED)
 	{
@@ -5487,8 +5492,8 @@ l5:
 		 * updater to be identical to the current one, so we need not check
 		 * for that case as we do in the block above.
 		 */
-		new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status);
-		GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
+		new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status, r);
+		GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2, r);
 	}
 	else if (TransactionIdIsInProgress(xmax))
 	{
@@ -5569,8 +5574,8 @@ l5:
 		/* otherwise, just fall back to creating a new multixact */
 		new_status = get_mxact_status_for_lock(mode, is_update);
 		new_xmax = MultiXactIdCreate(xmax, old_status,
-									 add_to_xmax, new_status);
-		GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
+									 add_to_xmax, new_status, r);
+		GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2, r);
 	}
 	else if (!HEAP_XMAX_IS_LOCKED_ONLY(old_infomask) &&
 			 TransactionIdDidCommit(xmax))
@@ -5594,8 +5599,8 @@ l5:
 		 * updater to be identical to the current one, so we need not check
 		 * for that case as we do in the block above.
 		 */
-		new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status);
-		GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
+		new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status, r);
+		GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2, r);
 	}
 	else
 	{
@@ -5856,7 +5861,8 @@ l4:
 				Assert(!HEAP_LOCKED_UPGRADED(mytup.t_data->t_infomask));
 
 				nmembers = GetMultiXactIdMembers(rawxmax, &members, false,
-												 HEAP_XMAX_IS_LOCKED_ONLY(old_infomask));
+												 HEAP_XMAX_IS_LOCKED_ONLY(old_infomask),
+												 rel->rd_locator.relNumber);
 				for (i = 0; i < nmembers; i++)
 				{
 					result = test_lockmode_for_conflict(members[i].status,
@@ -5971,7 +5977,8 @@ l4:
 		/* compute the new Xmax and infomask values for the tuple ... */
 		compute_new_xmax_infomask(xmax, old_infomask, mytup.t_data->t_infomask2,
 								  xid, mode, false,
-								  &new_xmax, &new_infomask, &new_infomask2);
+								  &new_xmax, &new_infomask, &new_infomask2,
+								  rel->rd_locator.relNumber);
 
 		if (PageIsAllVisible(BufferGetPage(buf)) &&
 			visibilitymap_clear(rel, block, vmbuffer,
@@ -6729,7 +6736,7 @@ heap_inplace_unlock(Relation relation,
 static TransactionId
 FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
 				  const struct VacuumCutoffs *cutoffs, uint16 *flags,
-				  HeapPageFreeze *pagefrz)
+				  HeapPageFreeze *pagefrz, RelFileNumber r)
 {
 	TransactionId newxmax;
 	MultiXactMember *members;
@@ -6784,7 +6791,7 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
 		}
 
 		/* replace multi with single XID for its updater? */
-		update_xact = MultiXactIdGetUpdateXid(multi, t_infomask);
+		update_xact = MultiXactIdGetUpdateXid(multi, t_infomask, 0);
 		if (TransactionIdPrecedes(update_xact, cutoffs->relfrozenxid))
 			ereport(ERROR,
 					(errcode(ERRCODE_DATA_CORRUPTED),
@@ -6822,7 +6829,7 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
 	 */
 	nmembers =
 		GetMultiXactIdMembers(multi, &members, false,
-							  HEAP_XMAX_IS_LOCKED_ONLY(t_infomask));
+							  HEAP_XMAX_IS_LOCKED_ONLY(t_infomask), r);
 	if (nmembers <= 0)
 	{
 		/* Nothing worth keeping */
@@ -7023,7 +7030,8 @@ 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
 		 */
-		newxmax = MultiXactIdCreateFromMembers(nnewmembers, newmembers);
+		/* XXX/DEMO no need to extend wiat info in freeze scenario? */
+		newxmax = MultiXactIdCreateFromMembers(nnewmembers, newmembers, 0);
 		*flags |= FRM_RETURN_IS_MULTI;
 	}
 
@@ -7154,7 +7162,7 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
 		 * FreezeLimit/MultiXactCutoff postcondition must never be violated.
 		 */
 		newxmax = FreezeMultiXactId(xid, tuple->t_infomask, cutoffs,
-									&flags, pagefrz);
+									&flags, pagefrz, 0);
 
 		if (flags & FRM_NOOP)
 		{
@@ -7220,7 +7228,7 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
 			 */
 			frz->t_infomask &= ~HEAP_XMAX_BITS;
 			frz->t_infomask2 &= ~HEAP_KEYS_UPDATED;
-			GetMultiXactIdHintBits(newxmax, &newbits, &newbits2);
+			GetMultiXactIdHintBits(newxmax, &newbits, &newbits2, 0); /* DEMO: shortcut */
 			frz->t_infomask |= newbits;
 			frz->t_infomask2 |= newbits2;
 			frz->xmax = newxmax;
@@ -7470,7 +7478,7 @@ heap_freeze_tuple(HeapTupleHeader tuple,
  */
 static void
 GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask,
-					   uint16 *new_infomask2)
+					   uint16 *new_infomask2, RelFileNumber r)
 {
 	int			nmembers;
 	MultiXactMember *members;
@@ -7484,7 +7492,7 @@ GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask,
 	 * We only use this in multis we just created, so they cannot be values
 	 * pre-pg_upgrade.
 	 */
-	nmembers = GetMultiXactIdMembers(multi, &members, false, false);
+	nmembers = GetMultiXactIdMembers(multi, &members, false, false, 0);
 
 	for (i = 0; i < nmembers; i++)
 	{
@@ -7550,7 +7558,7 @@ GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask,
  * necessary.
  */
 static TransactionId
-MultiXactIdGetUpdateXid(TransactionId xmax, uint16 t_infomask)
+MultiXactIdGetUpdateXid(TransactionId xmax, uint16 t_infomask, RelFileNumber r)
 {
 	TransactionId update_xact = InvalidTransactionId;
 	MultiXactMember *members;
@@ -7563,7 +7571,7 @@ MultiXactIdGetUpdateXid(TransactionId xmax, uint16 t_infomask)
 	 * Since we know the LOCK_ONLY bit is not set, this cannot be a multi from
 	 * pre-pg_upgrade.
 	 */
-	nmembers = GetMultiXactIdMembers(xmax, &members, false, false);
+	nmembers = GetMultiXactIdMembers(xmax, &members, false, false, r);
 
 	if (nmembers > 0)
 	{
@@ -7602,10 +7610,10 @@ MultiXactIdGetUpdateXid(TransactionId xmax, uint16 t_infomask)
  * checking the hint bits.
  */
 TransactionId
-HeapTupleGetUpdateXid(const HeapTupleHeaderData *tup)
+HeapTupleGetUpdateXid(const HeapTupleHeaderData *tup, uint32_t r)
 {
 	return MultiXactIdGetUpdateXid(HeapTupleHeaderGetRawXmax(tup),
-								   tup->t_infomask);
+								   tup->t_infomask, r);
 }
 
 /*
@@ -7630,7 +7638,7 @@ DoesMultiXactIdConflict(MultiXactId multi, uint16 infomask,
 		return false;
 
 	nmembers = GetMultiXactIdMembers(multi, &members, false,
-									 HEAP_XMAX_IS_LOCKED_ONLY(infomask));
+									 HEAP_XMAX_IS_LOCKED_ONLY(infomask), 4); /* DEMO: shortcut */
 	if (nmembers >= 0)
 	{
 		int			i;
@@ -7731,7 +7739,7 @@ Do_MultiXactIdWait(MultiXactId multi, MultiXactStatus status,
 	/* for pre-pg_upgrade tuples, no need to sleep at all */
 	nmembers = HEAP_LOCKED_UPGRADED(infomask) ? -1 :
 		GetMultiXactIdMembers(multi, &members, false,
-							  HEAP_XMAX_IS_LOCKED_ONLY(infomask));
+							  HEAP_XMAX_IS_LOCKED_ONLY(infomask), 5); /* DEMO */ 
 
 	if (nmembers >= 0)
 	{
@@ -7951,7 +7959,7 @@ heap_tuple_should_freeze(HeapTupleHeader tuple,
 
 		/* need to check whether any member of the mxact is old */
 		nmembers = GetMultiXactIdMembers(multi, &members, false,
-										 HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
+										 HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask), 3); /* DEMO: shortcut */
 
 		for (int i = 0; i < nmembers; i++)
 		{
diff --git a/src/backend/access/heap/heapam_visibility.c b/src/backend/access/heap/heapam_visibility.c
index 05f6946fe60..d1759b9fc24 100644
--- a/src/backend/access/heap/heapam_visibility.c
+++ b/src/backend/access/heap/heapam_visibility.c
@@ -230,7 +230,7 @@ HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
 			{
 				TransactionId xmax;
 
-				xmax = HeapTupleGetUpdateXid(tuple);
+				xmax = HeapTupleGetUpdateXid(tuple, htup->t_tableOid);
 
 				/* not LOCKED_ONLY, so it has to have an xmax */
 				Assert(TransactionIdIsValid(xmax));
@@ -285,7 +285,7 @@ HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
 		if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
 			return true;
 
-		xmax = HeapTupleGetUpdateXid(tuple);
+		xmax = HeapTupleGetUpdateXid(tuple, htup->t_tableOid);
 
 		/* not LOCKED_ONLY, so it has to have an xmax */
 		Assert(TransactionIdIsValid(xmax));
@@ -550,7 +550,7 @@ HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
 			{
 				TransactionId xmax;
 
-				xmax = HeapTupleGetUpdateXid(tuple);
+				xmax = HeapTupleGetUpdateXid(tuple, htup->t_tableOid);
 
 				/* not LOCKED_ONLY, so it has to have an xmax */
 				Assert(TransactionIdIsValid(xmax));
@@ -630,7 +630,7 @@ HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
 			return TM_Ok;
 		}
 
-		xmax = HeapTupleGetUpdateXid(tuple);
+		xmax = HeapTupleGetUpdateXid(tuple, htup->t_tableOid);
 		if (!TransactionIdIsValid(xmax))
 		{
 			if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
@@ -807,7 +807,7 @@ HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
 			{
 				TransactionId xmax;
 
-				xmax = HeapTupleGetUpdateXid(tuple);
+				xmax = HeapTupleGetUpdateXid(tuple, htup->t_tableOid);
 
 				/* not LOCKED_ONLY, so it has to have an xmax */
 				Assert(TransactionIdIsValid(xmax));
@@ -880,7 +880,7 @@ HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
 		if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
 			return true;
 
-		xmax = HeapTupleGetUpdateXid(tuple);
+		xmax = HeapTupleGetUpdateXid(tuple, htup->t_tableOid);
 
 		/* not LOCKED_ONLY, so it has to have an xmax */
 		Assert(TransactionIdIsValid(xmax));
@@ -1033,7 +1033,7 @@ HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
 			{
 				TransactionId xmax;
 
-				xmax = HeapTupleGetUpdateXid(tuple);
+				xmax = HeapTupleGetUpdateXid(tuple, htup->t_tableOid);
 
 				/* not LOCKED_ONLY, so it has to have an xmax */
 				Assert(TransactionIdIsValid(xmax));
@@ -1096,7 +1096,7 @@ HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot,
 		/* already checked above */
 		Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
 
-		xmax = HeapTupleGetUpdateXid(tuple);
+		xmax = HeapTupleGetUpdateXid(tuple, htup->t_tableOid);
 
 		/* not LOCKED_ONLY, so it has to have an xmax */
 		Assert(TransactionIdIsValid(xmax));
@@ -1354,7 +1354,7 @@ HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *de
 
 	if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
 	{
-		TransactionId xmax = HeapTupleGetUpdateXid(tuple);
+		TransactionId xmax = HeapTupleGetUpdateXid(tuple, htup->t_tableOid);
 
 		/* already checked above */
 		Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask));
@@ -1549,7 +1549,7 @@ HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
 		return false;
 
 	/* ... but if it's a multi, then perhaps the updating Xid aborted. */
-	xmax = HeapTupleGetUpdateXid(tuple);
+	xmax = HeapTupleGetUpdateXid(tuple, 12); /* DEMO */
 
 	/* not LOCKED_ONLY, so it has to have an xmax */
 	Assert(TransactionIdIsValid(xmax));
@@ -1698,7 +1698,7 @@ HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot,
 	 */
 	else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
 	{
-		xmax = HeapTupleGetUpdateXid(tuple);
+		xmax = HeapTupleGetUpdateXid(tuple, htup->t_tableOid);
 	}
 
 	/* check if it's one of our txids, toplevel is also in there */
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 9d5f130af7e..b149e4481e7 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -384,7 +384,9 @@ static MemoryContext MXactContext = NULL;
 /* internal MultiXactId management */
 static void MultiXactIdSetOldestVisible(void);
 static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
-							   int nmembers, MultiXactMember *members);
+							   int nmembers, MultiXactMember *members,
+							   RelFileNumber r);
+
 static MultiXactId GetNewMultiXactId(int nmembers, MultiXactOffset *offset);
 
 /* MultiXact cache management */
@@ -423,7 +425,8 @@ static void WriteMTruncateXlogRec(Oid oldestMultiDB,
  */
 MultiXactId
 MultiXactIdCreate(TransactionId xid1, MultiXactStatus status1,
-				  TransactionId xid2, MultiXactStatus status2)
+				  TransactionId xid2, MultiXactStatus status2,
+				  RelFileNumber r)
 {
 	MultiXactId newMulti;
 	MultiXactMember members[2];
@@ -447,7 +450,7 @@ MultiXactIdCreate(TransactionId xid1, MultiXactStatus status1,
 	members[1].xid = xid2;
 	members[1].status = status2;
 
-	newMulti = MultiXactIdCreateFromMembers(2, members);
+	newMulti = MultiXactIdCreateFromMembers(2, members, r);
 
 	debug_elog3(DEBUG2, "Create: %s",
 				mxid_to_string(newMulti, 2, members));
@@ -475,7 +478,8 @@ MultiXactIdCreate(TransactionId xid1, MultiXactStatus status1,
  * passed in.
  */
 MultiXactId
-MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status)
+MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status,
+				  RelFileNumber r)
 {
 	MultiXactId newMulti;
 	MultiXactMember *members;
@@ -498,7 +502,7 @@ MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status)
 	 * caller of this function does a check that the multixact is no longer
 	 * running.
 	 */
-	nmembers = GetMultiXactIdMembers(multi, &members, false, false);
+	nmembers = GetMultiXactIdMembers(multi, &members, false, false, r);
 
 	if (nmembers < 0)
 	{
@@ -513,7 +517,7 @@ MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status)
 		 */
 		member.xid = xid;
 		member.status = status;
-		newMulti = MultiXactIdCreateFromMembers(1, &member);
+		newMulti = MultiXactIdCreateFromMembers(1, &member, r);
 
 		debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u",
 					multi, newMulti);
@@ -565,7 +569,7 @@ MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status)
 
 	newMembers[j].xid = xid;
 	newMembers[j++].status = status;
-	newMulti = MultiXactIdCreateFromMembers(j, newMembers);
+	newMulti = MultiXactIdCreateFromMembers(j, newMembers, r);
 
 	pfree(members);
 	pfree(newMembers);
@@ -599,7 +603,7 @@ MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
 	 * "false" here means we assume our callers have checked that the given
 	 * multi cannot possibly come from a pg_upgraded database.
 	 */
-	nmembers = GetMultiXactIdMembers(multi, &members, false, isLockOnly);
+	nmembers = GetMultiXactIdMembers(multi, &members, false, isLockOnly, 0);
 
 	if (nmembers <= 0)
 	{
@@ -803,7 +807,7 @@ ReadMultiXactIdRange(MultiXactId *oldest, MultiXactId *next)
  * NB: the passed members[] array will be sorted in-place.
  */
 MultiXactId
-MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
+MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members, RelFileNumber r)
 {
 	MultiXactId multi;
 	MultiXactOffset offset;
@@ -883,7 +887,7 @@ MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
 	(void) XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_CREATE_ID);
 
 	/* Now enter the information into the OFFSETs and MEMBERs logs */
-	RecordNewMultiXact(multi, offset, nmembers, members);
+	RecordNewMultiXact(multi, offset, nmembers, members, r);
 
 	/* Done with critical section */
 	END_CRIT_SECTION();
@@ -905,7 +909,8 @@ MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
  */
 static void
 RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
-				   int nmembers, MultiXactMember *members)
+				   int nmembers, MultiXactMember *members,
+				   RelFileNumber r)
 {
 	int64		pageno;
 	int64		prev_pageno;
@@ -920,7 +925,7 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
 	entryno = MultiXactIdToOffsetEntry(multi);
 
 	lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
-	LWLockAcquire(lock, LW_EXCLUSIVE);
+	LWLockAcquireExt(lock, LW_EXCLUSIVE, r);
 
 	/*
 	 * Note: we pass the MultiXactId to SimpleLruReadPage as the "transaction"
@@ -977,7 +982,7 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
 				if (prevlock != NULL)
 					LWLockRelease(prevlock);
 
-				LWLockAcquire(lock, LW_EXCLUSIVE);
+				LWLockAcquireExt(lock, LW_EXCLUSIVE, r);
 				prevlock = lock;
 			}
 			slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
@@ -1288,7 +1293,8 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
  */
 int
 GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
-					  bool from_pgupgrade, bool isLockOnly)
+					  bool from_pgupgrade, bool isLockOnly,
+					  RelFileNumber r)
 {
 	int64		pageno;
 	int64		prev_pageno;
@@ -1415,7 +1421,7 @@ retry:
 
 	/* Acquire the bank lock for the page we need. */
 	lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
-	LWLockAcquire(lock, LW_EXCLUSIVE);
+	LWLockAcquireExt(lock, LW_EXCLUSIVE, r);
 
 	slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
 	offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
@@ -1461,7 +1467,7 @@ retry:
 			if (newlock != lock)
 			{
 				LWLockRelease(lock);
-				LWLockAcquire(newlock, LW_EXCLUSIVE);
+				LWLockAcquireExt(newlock, LW_EXCLUSIVE, r);
 				lock = newlock;
 			}
 			slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
@@ -1526,7 +1532,7 @@ retry:
 			{
 				if (lock)
 					LWLockRelease(lock);
-				LWLockAcquire(newlock, LW_EXCLUSIVE);
+				LWLockAcquireExt(newlock, LW_EXCLUSIVE, r);
 				lock = newlock;
 			}
 
@@ -3357,7 +3363,7 @@ multixact_redo(XLogReaderState *record)
 
 		/* Store the data back into the SLRU files */
 		RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
-						   xlrec->members);
+						   xlrec->members, 0);
 
 		/* Make sure nextMXact/nextOffset are beyond what this record has */
 		MultiXactAdvanceNextMXact(xlrec->mid + 1,
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index e703d6ae807..bd08af8a6c4 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -204,7 +204,7 @@ static int	LocalLWLockCounter;
 #define MAX_NAMED_TRANCHES 256
 
 static void InitializeLWLocks(void);
-static inline void LWLockReportWaitStart(LWLock *lock);
+static inline void LWLockReportWaitStart(LWLock *lock, uint32 additional_info);
 static inline void LWLockReportWaitEnd(void);
 static const char *GetLWTrancheName(uint16 trancheId);
 
@@ -716,9 +716,9 @@ LWLockInitialize(LWLock *lock, int tranche_id)
  * event based on tranche and lock id.
  */
 static inline void
-LWLockReportWaitStart(LWLock *lock)
+LWLockReportWaitStart(LWLock *lock, uint32 additional_info)
 {
-	pgstat_report_wait_start(PG_WAIT_LWLOCK | ((uint64_t) lock->tranche << 32));
+	pgstat_report_wait_start(PG_WAIT_LWLOCK | ((uint64_t) lock->tranche << 32) | additional_info);
 }
 
 /*
@@ -1173,6 +1173,13 @@ LWLockDequeueSelf(LWLock *lock)
  */
 bool
 LWLockAcquire(LWLock *lock, LWLockMode mode)
+{
+	return LWLockAcquireExt(lock, mode, 0);
+}
+
+/* XXX/DEMO just for demo purposes */
+bool
+LWLockAcquireExt(LWLock *lock, LWLockMode mode, uint32 additional_info)
 {
 	PGPROC	   *proc = MyProc;
 	bool		result = true;
@@ -1285,7 +1292,7 @@ LWLockAcquire(LWLock *lock, LWLockMode mode)
 		lwstats->block_count++;
 #endif
 
-		LWLockReportWaitStart(lock);
+		LWLockReportWaitStart(lock, additional_info);
 		if (TRACE_POSTGRESQL_LWLOCK_WAIT_START_ENABLED())
 			TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), mode);
 
@@ -1450,7 +1457,7 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode)
 			lwstats->block_count++;
 #endif
 
-			LWLockReportWaitStart(lock);
+			LWLockReportWaitStart(lock, 0);
 			if (TRACE_POSTGRESQL_LWLOCK_WAIT_START_ENABLED())
 				TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), mode);
 
@@ -1668,7 +1675,7 @@ LWLockWaitForVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 oldval,
 		lwstats->block_count++;
 #endif
 
-		LWLockReportWaitStart(lock);
+		LWLockReportWaitStart(lock, 0);
 		if (TRACE_POSTGRESQL_LWLOCK_WAIT_START_ENABLED())
 			TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), LW_EXCLUSIVE);
 
diff --git a/src/backend/utils/adt/multixactfuncs.c b/src/backend/utils/adt/multixactfuncs.c
index e74ea938348..045591c9cbb 100644
--- a/src/backend/utils/adt/multixactfuncs.c
+++ b/src/backend/utils/adt/multixactfuncs.c
@@ -53,7 +53,7 @@ pg_get_multixact_members(PG_FUNCTION_ARGS)
 		multi = palloc(sizeof(mxact));
 		/* no need to allow for old values here */
 		multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false,
-												false);
+												false, 0);
 		multi->iter = 0;
 
 		if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
diff --git a/src/include/access/htup.h b/src/include/access/htup.h
index f6b766697e2..82b1bc0c205 100644
--- a/src/include/access/htup.h
+++ b/src/include/access/htup.h
@@ -84,6 +84,6 @@ extern void HeapTupleHeaderAdjustCmax(const HeapTupleHeaderData *tup,
 									  CommandId *cmax, bool *iscombo);
 
 /* Prototype for HeapTupleHeader accessors in heapam.c */
-extern TransactionId HeapTupleGetUpdateXid(const HeapTupleHeaderData *tup);
+extern TransactionId HeapTupleGetUpdateXid(const HeapTupleHeaderData *tup, uint32_t r);
 
 #endif							/* HTUP_H */
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index f3593acc8c2..4c50a514141 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -404,7 +404,7 @@ HeapTupleHeaderGetUpdateXid(const HeapTupleHeaderData *tup)
 	if (!((tup)->t_infomask & HEAP_XMAX_INVALID) &&
 		((tup)->t_infomask & HEAP_XMAX_IS_MULTI) &&
 		!((tup)->t_infomask & HEAP_XMAX_LOCK_ONLY))
-		return HeapTupleGetUpdateXid(tup);
+		return HeapTupleGetUpdateXid(tup, 13);
 	else
 		return HeapTupleHeaderGetRawXmax(tup);
 }
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 82e4bb90dd5..643b17b6025 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -99,18 +99,20 @@ typedef struct xl_multixact_truncate
 
 extern MultiXactId MultiXactIdCreate(TransactionId xid1,
 									 MultiXactStatus status1, TransactionId xid2,
-									 MultiXactStatus status2);
+									 MultiXactStatus status2, RelFileNumber r);
 extern MultiXactId MultiXactIdExpand(MultiXactId multi, TransactionId xid,
-									 MultiXactStatus status);
+									 MultiXactStatus status, RelFileNumber r);
 extern MultiXactId MultiXactIdCreateFromMembers(int nmembers,
-												MultiXactMember *members);
+												MultiXactMember *members,
+												RelFileNumber r);
 
 extern MultiXactId ReadNextMultiXactId(void);
 extern void ReadMultiXactIdRange(MultiXactId *oldest, MultiXactId *next);
 extern bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly);
 extern void MultiXactIdSetOldestMember(void);
 extern int	GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
-								  bool from_pgupgrade, bool isLockOnly);
+								  bool from_pgupgrade, bool isLockOnly,
+								  RelFileNumber r);
 extern bool GetMultiXactInfo(uint32 *multixacts, MultiXactOffset *members,
 							 MultiXactId *oldestMultiXactId,
 							 MultiXactOffset *oldestOffset);
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index 54e72cd8860..594753fcf25 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -122,6 +122,7 @@ extern PGDLLIMPORT bool Trace_lwlocks;
 #endif
 
 extern bool LWLockAcquire(LWLock *lock, LWLockMode mode);
+extern bool LWLockAcquireExt(LWLock *lock, LWLockMode mode, uint32 additional_info);
 extern bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode);
 extern bool LWLockAcquireOrWait(LWLock *lock, LWLockMode mode);
 extern void LWLockRelease(LWLock *lock);
diff --git a/src/test/modules/test_slru/test_multixact.c b/src/test/modules/test_slru/test_multixact.c
index 6c9b0420717..099465c5f59 100644
--- a/src/test/modules/test_slru/test_multixact.c
+++ b/src/test/modules/test_slru/test_multixact.c
@@ -32,7 +32,7 @@ test_create_multixact(PG_FUNCTION_ARGS)
 
 	MultiXactIdSetOldestMember();
 	id = MultiXactIdCreate(GetCurrentTransactionId(), MultiXactStatusUpdate,
-						   GetCurrentTransactionId(), MultiXactStatusForShare);
+						   GetCurrentTransactionId(), MultiXactStatusForShare, 0);
 	PG_RETURN_TRANSACTIONID(id);
 }
 
@@ -50,7 +50,7 @@ test_read_multixact(PG_FUNCTION_ARGS)
 	/* discard caches */
 	AtEOXact_MultiXact();
 
-	if (GetMultiXactIdMembers(id, &members, false, false) == -1)
+	if (GetMultiXactIdMembers(id, &members, false, false, 0) == -1)
 		elog(ERROR, "MultiXactId not found");
 
 	PG_RETURN_VOID();
-- 
2.43.0

