diff --git a/src/backend/utils/activity/pgstat_shmem.c b/src/backend/utils/activity/pgstat_shmem.c index d1149adf70..77289dab3d 100644 --- a/src/backend/utils/activity/pgstat_shmem.c +++ b/src/backend/utils/activity/pgstat_shmem.c @@ -269,6 +269,7 @@ pgstat_init_entry(PgStat_Kind kind, * further if a longer lived reference is needed. */ pg_atomic_init_u32(&shhashent->refcount, 1); + pg_atomic_init_u32(&shhashent->reusecount, 0); shhashent->dropped = false; chunk = dsa_allocate0(pgStatLocal.dsa, pgstat_get_kind_info(kind)->shared_size); @@ -292,6 +293,7 @@ pgstat_reinit_entry(PgStat_Kind kind, PgStatShared_HashEntry *shhashent) /* mark as not dropped anymore */ pg_atomic_fetch_add_u32(&shhashent->refcount, 1); + pg_atomic_fetch_add_u32(&shhashent->reusecount, 1); shhashent->dropped = false; /* reinitialize content */ @@ -332,6 +334,7 @@ pgstat_acquire_entry_ref(PgStat_EntryRef *entry_ref, entry_ref->shared_stats = shheader; entry_ref->shared_entry = shhashent; + entry_ref->reusecount = pg_atomic_read_u32(&shhashent->reusecount); } /* @@ -380,6 +383,16 @@ pgstat_get_entry_ref_cached(PgStat_HashKey key, PgStat_EntryRef **entry_ref_p) Assert(entry_ref->shared_stats->magic == 0xdeadbeef); /* should have at least our reference */ Assert(pg_atomic_read_u32(&entry_ref->shared_entry->refcount) > 0); + + /* However, if someone has reused the shred stats, give it up. */ + if (entry_ref->reusecount != + pg_atomic_read_u32(&entry_ref->shared_entry->reusecount)) + { + entry_ref->shared_stats = NULL; + entry_ref->shared_entry = NULL; + entry_ref->pending = NULL; + found = false; + } } *entry_ref_p = cache_entry->entry_ref; diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h index 60fbf9394b..b68cc08b11 100644 --- a/src/include/utils/pgstat_internal.h +++ b/src/include/utils/pgstat_internal.h @@ -72,6 +72,12 @@ typedef struct PgStatShared_HashEntry */ bool dropped; + /* + * Increments at reinit for backends to know whether this entry is already + * reinited. + */ + pg_atomic_uint32 reusecount; + /* * Refcount managing lifetime of the entry itself (as opposed to the * dshash entry pointing to it). The stats lifetime has to be separate @@ -132,6 +138,12 @@ typedef struct PgStat_EntryRef */ PgStatShared_Common *shared_stats; + /* + * This count is copied in from shared entry at establising a local + * reference. Then compared to detect shared entry reuse. + */ + int reusecount; + /* * Pending statistics data that will need to be flushed to shared memory * stats eventually. Each stats kind utilizing pending data defines what