From c9bac6e4041afd91422a7df8ae92e120877930ef Mon Sep 17 00:00:00 2001 From: Shihao Date: Mon, 21 Sep 2026 19:19:02 -0400 Subject: [PATCH v5 2/2] Include the PID in the key of backend statistics entries With stats_fetch_consistency set to "snapshot", the statistics of a backend could be reported under the PID of a newer backend that reused its proc number. Make the PID part of the object ID of these entries, so that an entry is only found with the PID of the backend it belongs to. Reported-by: Bertrand Drouvot Author: Shihao Zhong Discussion: https://postgr.es/m/arD/w47Ug1GaObfq@bdtpg --- src/backend/utils/activity/pgstat.c | 3 ++- src/backend/utils/activity/pgstat_backend.c | 15 +++++++++------ src/backend/utils/adt/pgstatfuncs.c | 3 ++- src/include/pgstat.h | 11 ++++++++++- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c index 5177f880f70..0a7000844ec 100644 --- a/src/backend/utils/activity/pgstat.c +++ b/src/backend/utils/activity/pgstat.c @@ -666,7 +666,8 @@ pgstat_shutdown_hook(int code, Datum arg) dlist_init(&pgStatPending); /* drop the backend stats entry */ - if (!pgstat_drop_entry(PGSTAT_KIND_BACKEND, InvalidOid, MyProcNumber, false)) + if (!pgstat_drop_entry(PGSTAT_KIND_BACKEND, InvalidOid, + PGSTAT_BACKEND_OBJID(MyProcPid, MyProcNumber), false)) pgstat_request_entry_refs_gc(); pgstat_detach_shmem(); diff --git a/src/backend/utils/activity/pgstat_backend.c b/src/backend/utils/activity/pgstat_backend.c index 59bc7e699b5..b278cf03ef1 100644 --- a/src/backend/utils/activity/pgstat_backend.c +++ b/src/backend/utils/activity/pgstat_backend.c @@ -121,15 +121,16 @@ pgstat_count_backend_lock_fastpath_exceeded(uint8 locktag_type) } /* - * Returns statistics of a backend by proc number. + * Returns statistics of a backend by PID and proc number. */ PgStat_Backend * -pgstat_fetch_stat_backend(ProcNumber procNumber) +pgstat_fetch_stat_backend(int pid, ProcNumber procNumber) { PgStat_Backend *backend_entry; backend_entry = (PgStat_Backend *) pgstat_fetch_entry(PGSTAT_KIND_BACKEND, - InvalidOid, procNumber, + InvalidOid, + PGSTAT_BACKEND_OBJID(pid, procNumber), NULL); return backend_entry; @@ -188,7 +189,7 @@ pgstat_fetch_stat_backend_by_pid(int pid, BackendType *bktype, Oid *userid) * Retrieve the entry. Note that "beentry" may be freed depending on the * value of stats_fetch_consistency, so do not access it from this point. */ - backend_stats = pgstat_fetch_stat_backend(procNumber); + backend_stats = pgstat_fetch_stat_backend(pid, procNumber); if (!backend_stats) { if (bktype) @@ -366,7 +367,8 @@ pgstat_flush_backend(bool nowait, uint32 flags) return false; entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_BACKEND, InvalidOid, - MyProcNumber, nowait); + PGSTAT_BACKEND_OBJID(MyProcPid, MyProcNumber), + nowait); if (!entry_ref) return true; @@ -406,7 +408,8 @@ pgstat_create_backend(ProcNumber procnum) PgStatShared_Backend *shstatent; entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_BACKEND, InvalidOid, - procnum, false); + PGSTAT_BACKEND_OBJID(MyProcPid, procnum), + false); shstatent = (PgStatShared_Backend *) entry_ref->shared_stats; /* diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index f9fc3b65b2a..a84e263bf15 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -2204,7 +2204,8 @@ pg_stat_reset_backend_stats(PG_FUNCTION_ARGS) if (!pgstat_tracks_backend_bktype(beentry->st_backendType)) PG_RETURN_VOID(); - pgstat_reset(PGSTAT_KIND_BACKEND, InvalidOid, procNumber); + pgstat_reset(PGSTAT_KIND_BACKEND, InvalidOid, + PGSTAT_BACKEND_OBJID(backend_pid, procNumber)); PG_RETURN_VOID(); } diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 4c3dcc03df5..ba1c9b40768 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -665,11 +665,20 @@ extern void pgstat_count_backend_io_op(IOObject io_object, IOOp io_op, uint32 cnt, uint64 bytes); +/* + * Object ID of the stats entry of a backend. The PID is part of the key, so + * that an entry cached for an older backend that used the same proc number, + * for example in a stats snapshot, is never mistaken for the entry of the + * backend currently using this proc number. + */ +#define PGSTAT_BACKEND_OBJID(pid, procnum) \ + ((((uint64) (uint32) (pid)) << 32) | (uint32) (procnum)) + /* used by pgstat_lock.c for lock stats tracked in backends */ extern void pgstat_count_backend_lock_waits(uint8 locktag_type, PgStat_Counter usecs); extern void pgstat_count_backend_lock_fastpath_exceeded(uint8 locktag_type); -extern PgStat_Backend *pgstat_fetch_stat_backend(ProcNumber procNumber); +extern PgStat_Backend *pgstat_fetch_stat_backend(int pid, ProcNumber procNumber); extern PgStat_Backend *pgstat_fetch_stat_backend_by_pid(int pid, BackendType *bktype, Oid *userid); -- 2.37.1 (Apple Git-137.1)