From aeb9b1a20cc2fdf582aba37a7fce803ece6694a7 Mon Sep 17 00:00:00 2001
From: Sami Imseih <samimseih@gmail.com>
Date: Wed, 15 Jul 2026 13:30:38 -0500
Subject: [PATCH v2 1/1] pgstat: add pgstat_prep_pending_from_entry_ref() for
 pending setup

Add pgstat_prep_pending_from_entry_ref(), which prepares an existing
PgStat_EntryRef to receive pending stats.  This allows callers to
obtain a reference via pgstat_get_entry_ref() and set up pending data
in separate steps.

Previously, the only way to get an entry ref with pending data ready
was pgstat_prep_pending_entry(), which bundles lookup, creation, and
pending setup in a single call.  Callers that need finer control over
entry creation (e.g., to check capacity before deciding to create)
had no public way to attach pending data to an already-obtained ref.

pgstat_prep_pending_entry() is refactored to use the new function
internally.  All existing callers are unchanged.
---
 src/backend/utils/activity/pgstat.c | 55 ++++++++++++++++++-----------
 src/include/utils/pgstat_internal.h |  1 +
 2 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c
index 9234854b8b5..50cd07822b4 100644
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -1311,29 +1311,10 @@ pgstat_prep_pending_entry(PgStat_Kind kind, Oid dboid, uint64 objid, bool *creat
 {
 	PgStat_EntryRef *entry_ref;
 
-	/* need to be able to flush out */
-	Assert(pgstat_get_kind_info(kind)->flush_pending_cb != NULL);
-
-	if (unlikely(!pgStatPendingContext))
-	{
-		pgStatPendingContext =
-			AllocSetContextCreate(TopMemoryContext,
-								  "PgStat Pending",
-								  ALLOCSET_SMALL_SIZES);
-	}
-
 	entry_ref = pgstat_get_entry_ref(kind, dboid, objid,
 									 true, created_entry);
 
-	if (entry_ref->pending == NULL)
-	{
-		size_t		entrysize = pgstat_get_kind_info(kind)->pending_size;
-
-		Assert(entrysize != (size_t) -1);
-
-		entry_ref->pending = MemoryContextAllocZero(pgStatPendingContext, entrysize);
-		dlist_push_tail(&pgStatPending, &entry_ref->pending_node);
-	}
+	pgstat_prep_pending_from_entry_ref(entry_ref);
 
 	return entry_ref;
 }
@@ -1377,6 +1358,40 @@ pgstat_delete_pending_entry(PgStat_EntryRef *entry_ref)
 	dlist_delete(&entry_ref->pending_node);
 }
 
+/*
+ * Prepare the given entry to receive pending stats, if not already done.
+ */
+void
+pgstat_prep_pending_from_entry_ref(PgStat_EntryRef *entry_ref)
+{
+	PgStat_Kind kind;
+
+	Assert(entry_ref != NULL);
+
+	kind = entry_ref->shared_entry->key.kind;
+
+	/* need to be able to flush out */
+	Assert(pgstat_get_kind_info(kind)->flush_pending_cb != NULL);
+
+	if (entry_ref->pending == NULL)
+	{
+		size_t		entrysize = pgstat_get_kind_info(kind)->pending_size;
+
+		Assert(entrysize != (size_t) -1);
+
+		if (unlikely(!pgStatPendingContext))
+		{
+			pgStatPendingContext =
+				AllocSetContextCreate(TopMemoryContext,
+									  "PgStat Pending",
+									  ALLOCSET_SMALL_SIZES);
+		}
+
+		entry_ref->pending = MemoryContextAllocZero(pgStatPendingContext, entrysize);
+		dlist_push_tail(&pgStatPending, &entry_ref->pending_node);
+	}
+}
+
 /*
  * Flush out pending variable-numbered stats.
  */
diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index e62122b883b..b0a17691966 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -680,6 +680,7 @@ extern void pgstat_assert_is_up(void);
 #endif
 
 extern void pgstat_delete_pending_entry(PgStat_EntryRef *entry_ref);
+extern void pgstat_prep_pending_from_entry_ref(PgStat_EntryRef *entry_ref);
 extern PgStat_EntryRef *pgstat_prep_pending_entry(PgStat_Kind kind, Oid dboid,
 												  uint64 objid,
 												  bool *created_entry);
-- 
2.50.1 (Apple Git-155)

