pgstat_reuse_fix_a.txt
text/plain
Filename: pgstat_reuse_fix_a.txt
Type: text/plain
Part: 0
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