From: Michael Paquier Date: Tue, 21 Jul 2026 23:15:00 +0000 (+0900) Subject: Add new pgstats routine to split pending data setup X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e65c331b8fbf8c9632b62c5a9dcb589cbd3046a8;p=thirdparty%2Fpostgresql.git Add new pgstats routine to split pending data setup This commit adds pgstat_prep_pending_from_entry_ref(), a new pgstats routine that is able to prepare an existing PgStat_EntryRef to receive pending stats. This split gives a way for callers to obtain first a reference via pgstat_get_entry_ref(), then set up pending data as two separate, distinctive, steps. Previously, the only way to get an entry reference 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 the entry creation had no way to attach pending data to an already-obtained entry reference. One case where this has shown to matter for a stats kind is where one wants to check some capacity (for example where a GUC bounds the maximum numer of entries allowed) before deciding if a new entry should be created. So this split can help in reducing calls to pgstat_get_entry_ref(), meaning less shmem hash table lookups. The only logical ordering change is that pgStatPendingContext is initialized after calling pgstat_get_entry_ref() in pgstat_prep_pending_entry(). This does not matter in practice. pgstat_prep_pending_entry() is refactored to use the new function internally. All the existing callers are unchanged. Existing out-of-core custom stats kinds should see no impact. Author: Sami Imseih Reviewed-by: Kyotaro Horiguchi Reviewed-by: Michael Paquier Discussion: https://postgr.es/m/CAA5RZ0sV+TsLejUMhAM=PJoOm8u-t8ru7B67KvyLCy=19sM87g@mail.gmail.com --- 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);