pgstat_reuse_fix_a.txt

text/plain

Filename: pgstat_reuse_fix_a.txt
Type: text/plain
Part: 0
Message: Re: BUG #17947: Combination of replslots pgstat issues causes error/assertion failure
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