From 1a85c94f93985d39a6090a35d155f6ee6c788c14 Mon Sep 17 00:00:00 2001
From: Naga Appani <nagnrik@gmail.com>
Date: Sat, 16 Aug 2025 17:51:52 +0000
Subject: [PATCH v4] Rename ReadMultiXactCounts() to GetMultiXactInfo() and
 make it public

Following review feedback from Michael Paquier, this patch exposes
GetMultiXactInfo(), a public accessor that returns snapshot of
MultiXact state (counts and horizons) in one call, replacing
ReadMultiXactCounts().

Provide a single snapshot of MultiXact state and return:
- multixacts
- members
- oldestMultiXactId
- oldestOffset

Return false when the oldest offset is not known; in that case set all
outputs to 0/invalid for consistency.  Declare the function in
multixact.h and switch MultiXactMemberFreezeThreshold() to the new API.

This accessor underpins pg_get_multixact_stats() and is available to
extensions that wish to monitor MultiXact usage.

Author: Naga Appani <nagnrik@gmail.com>
Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://www.postgresql.org/message-id/flat/CA%2BQeY%2BAAsYK6WvBW4qYzHz4bahHycDAY_q5ECmHkEV_eB9ckzg%40mail.gmail.com
---
 src/backend/access/transam/multixact.c | 45 ++++++++++++++++++--------
 src/include/access/multixact.h         |  1 +
 2 files changed, 32 insertions(+), 14 deletions(-)

diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 3cb09c3d598..eeeec81abc9 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -2859,31 +2859,46 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
 }
 
 /*
- * Determine how many multixacts, and how many multixact members, currently
- * exist.  Return false if unable to determine.
+ * GetMultiXactInfo
+ *
+ * Returns information about current MultiXact state in a single atomic read:
+ *		- multixacts: Number of MultiXacts (nextMultiXactId - oldestMultiXactId)
+ *		- members: Number of member entries (nextOffset - oldestOffset)
+ *		- oldestMultiXactId: Oldest MultiXact ID still in use
+ *		- oldestOffset: Oldest offset still in use
+ *
+ * Returns false if the oldest offset is not known, in which case all output
+ * parameters are set to 0/invalid values for consistency.
  */
-static bool
-ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members)
+bool
+GetMultiXactInfo(uint32 *multixacts, MultiXactOffset *members,
+				 MultiXactId *oldestMultiXactId, MultiXactOffset *oldestOffset)
 {
-	MultiXactOffset nextOffset;
-	MultiXactOffset oldestOffset;
-	MultiXactId oldestMultiXactId;
-	MultiXactId nextMultiXactId;
-	bool		oldestOffsetKnown;
+	MultiXactOffset	nextOffset;
+	MultiXactId		nextMultiXactId;
+	bool			oldestOffsetKnown;
 
+	/* Take one consistent snapshot of the state */
 	LWLockAcquire(MultiXactGenLock, LW_SHARED);
 	nextOffset = MultiXactState->nextOffset;
-	oldestMultiXactId = MultiXactState->oldestMultiXactId;
+	*oldestMultiXactId = MultiXactState->oldestMultiXactId;
 	nextMultiXactId = MultiXactState->nextMXact;
-	oldestOffset = MultiXactState->oldestOffset;
+	*oldestOffset = MultiXactState->oldestOffset;
 	oldestOffsetKnown = MultiXactState->oldestOffsetKnown;
 	LWLockRelease(MultiXactGenLock);
 
 	if (!oldestOffsetKnown)
+	{
+		/* Set all outputs to 0/invalid for consistency */
+		*members = 0;
+		*multixacts = 0;
+		*oldestMultiXactId = InvalidMultiXactId;
+		*oldestOffset = 0;
 		return false;
+	}
 
-	*members = nextOffset - oldestOffset;
-	*multixacts = nextMultiXactId - oldestMultiXactId;
+	*members = nextOffset - *oldestOffset;
+	*multixacts = nextMultiXactId - *oldestMultiXactId;
 	return true;
 }
 
@@ -2922,9 +2937,11 @@ MultiXactMemberFreezeThreshold(void)
 	uint32		victim_multixacts;
 	double		fraction;
 	int			result;
+	MultiXactId	oldestMultiXactId;
+	MultiXactOffset oldestOffset;
 
 	/* If we can't determine member space utilization, assume the worst. */
-	if (!ReadMultiXactCounts(&multixacts, &members))
+	if (!GetMultiXactInfo(&multixacts, &members, &oldestMultiXactId, &oldestOffset))
 		return 0;
 
 	/* If member space utilization is low, no special action is required. */
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index b876e98f46e..e0878461c2c 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -158,5 +158,6 @@ extern void multixact_desc(StringInfo buf, XLogReaderState *record);
 extern const char *multixact_identify(uint8 info);
 extern char *mxid_to_string(MultiXactId multi, int nmembers,
 							MultiXactMember *members);
+extern bool GetMultiXactInfo(uint32 *multixacts, MultiXactOffset *members, MultiXactId *oldestMultiXactId, MultiXactOffset *oldestOffset);
 
 #endif							/* MULTIXACT_H */
-- 
2.47.3

