From 9e2f8cb9a87f1d9be91f2f39ef25fbb254944968 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Mon, 4 Aug 2025 08:14:02 +0000
Subject: [PATCH v1 01/10] Adding per backend relation statistics tracking

This commit introduces per backend relation stats tracking and adds a
new PgStat_BackendRelPending struct to store the pending statistics. To begin with,
this commit adds a new counter (heap_scan) to record the number of sequential
scans initiated on tables.

This commit relies on the existing per backend statistics machinery that has been
added in 9aea73fc61d.
---
 src/backend/access/heap/heapam.c            |  3 ++
 src/backend/utils/activity/pgstat_backend.c | 59 +++++++++++++++++++++
 src/include/pgstat.h                        | 14 +++++
 src/include/utils/pgstat_internal.h         |  3 +-
 src/tools/pgindent/typedefs.list            |  1 +
 5 files changed, 79 insertions(+), 1 deletion(-)
  73.9% src/backend/utils/activity/
   7.4% src/include/utils/
  15.4% src/include/
   3.2% src/

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 0dcd6ee817e..d9d6fb6c6ea 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -467,7 +467,10 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
 	 * and for sample scans we update stats for tuple fetches).
 	 */
 	if (scan->rs_base.rs_flags & SO_TYPE_SEQSCAN)
+	{
 		pgstat_count_heap_scan(scan->rs_base.rs_rd);
+		pgstat_count_backend_rel_heap_scan();
+	}
 }
 
 /*
diff --git a/src/backend/utils/activity/pgstat_backend.c b/src/backend/utils/activity/pgstat_backend.c
index 8714a85e2d9..8797dac68c7 100644
--- a/src/backend/utils/activity/pgstat_backend.c
+++ b/src/backend/utils/activity/pgstat_backend.c
@@ -47,6 +47,11 @@ static bool backend_has_iostats = false;
  */
 static WalUsage prevBackendWalUsage;
 
+/*
+ * For backend relations's related statistics.
+ */
+static bool backend_has_relstats = false;
+
 /*
  * Utility routines to report I/O stats for backends, kept here to avoid
  * exposing PendingBackendStats to the outside world.
@@ -259,6 +264,39 @@ pgstat_flush_backend_entry_wal(PgStat_EntryRef *entry_ref)
 	prevBackendWalUsage = pgWalUsage;
 }
 
+/*
+ * Flush out locally pending backend relations's related statistics.  Locking is
+ * managed by the caller.
+ */
+static void
+pgstat_flush_backend_entry_rel(PgStat_EntryRef *entry_ref)
+{
+	PgStatShared_Backend *shbackendent;
+
+	/*
+	 * This function can be called even if nothing at all has happened for
+	 * relations's related statistics.  In this case, avoid unnecessarily
+	 * modifying the stats entry.
+	 */
+	if (!backend_has_relstats)
+		return;
+
+	shbackendent = (PgStatShared_Backend *) entry_ref->shared_stats;
+
+#define BACKENDREL_ACC(stat) \
+	(shbackendent->stats.stat += PendingBackendStats.pending_backendrel.stat)
+
+	BACKENDREL_ACC(heap_scan);
+#undef BACKENDREL_ACC
+
+	/*
+	 * Clear out the statistics buffer, so it can be re-used.
+	 */
+	MemSet(&PendingBackendStats.pending_backendrel, 0, sizeof(PgStat_BackendRelPending));
+
+	backend_has_relstats = false;
+}
+
 /*
  * Flush out locally pending backend statistics
  *
@@ -283,6 +321,10 @@ pgstat_flush_backend(bool nowait, bits32 flags)
 		pgstat_backend_wal_have_pending())
 		has_pending_data = true;
 
+	/* Some relations related data pending? */
+	if ((flags & PGSTAT_BACKEND_FLUSH_REL) && backend_has_relstats)
+		has_pending_data = true;
+
 	if (!has_pending_data)
 		return false;
 
@@ -298,6 +340,9 @@ pgstat_flush_backend(bool nowait, bits32 flags)
 	if (flags & PGSTAT_BACKEND_FLUSH_WAL)
 		pgstat_flush_backend_entry_wal(entry_ref);
 
+	if (flags & PGSTAT_BACKEND_FLUSH_REL)
+		pgstat_flush_backend_entry_rel(entry_ref);
+
 	pgstat_unlock_entry(entry_ref);
 
 	return false;
@@ -400,3 +445,17 @@ pgstat_backend_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts)
 {
 	((PgStatShared_Backend *) header)->stats.stat_reset_timestamp = ts;
 }
+
+#define PGSTAT_COUNT_BACKEND_FUNC(stat)					\
+void													\
+CppConcat(pgstat_count_backend_rel_,stat)(void)			\
+{														\
+	if (!pgstat_tracks_backend_bktype(MyBackendType))	\
+		return;											\
+	PendingBackendStats.pending_backendrel.stat++;		\
+	backend_has_relstats = true;						\
+	pgstat_report_fixed = true;							\
+}
+
+/* pgstat_count_backend_rel_heap_scan */
+PGSTAT_COUNT_BACKEND_FUNC(heap_scan)
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 202bd2d5ace..7b4dacd27f8 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -490,8 +490,14 @@ typedef struct PgStat_Backend
 	TimestampTz stat_reset_timestamp;
 	PgStat_BktypeIO io_stats;
 	PgStat_WalCounters wal_counters;
+	PgStat_Counter heap_scan;
 } PgStat_Backend;
 
+typedef struct PgStat_BackendRelPending
+{
+	PgStat_Counter heap_scan;
+} PgStat_BackendRelPending;
+
 /* ---------
  * PgStat_BackendPending	Non-flushed backend stats.
  * ---------
@@ -502,6 +508,11 @@ typedef struct PgStat_BackendPending
 	 * Backend statistics store the same amount of IO data as PGSTAT_KIND_IO.
 	 */
 	PgStat_PendingIO pending_io;
+
+	/*
+	 * Backend statistics related to relations.
+	 */
+	PgStat_BackendRelPending pending_backendrel;
 } PgStat_BackendPending;
 
 /*
@@ -563,6 +574,9 @@ extern PgStat_Backend *pgstat_fetch_stat_backend_by_pid(int pid,
 extern bool pgstat_tracks_backend_bktype(BackendType bktype);
 extern void pgstat_create_backend(ProcNumber procnum);
 
+/* used to track backend relations related stats */
+extern void pgstat_count_backend_rel_heap_scan(void);
+
 /*
  * Functions in pgstat_bgwriter.c
  */
diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index 6cf00008f63..286249c0f3a 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -616,7 +616,8 @@ extern void pgstat_archiver_snapshot_cb(void);
 /* flags for pgstat_flush_backend() */
 #define PGSTAT_BACKEND_FLUSH_IO		(1 << 0)	/* Flush I/O statistics */
 #define PGSTAT_BACKEND_FLUSH_WAL   (1 << 1) /* Flush WAL statistics */
-#define PGSTAT_BACKEND_FLUSH_ALL   (PGSTAT_BACKEND_FLUSH_IO | PGSTAT_BACKEND_FLUSH_WAL)
+#define PGSTAT_BACKEND_FLUSH_REL   (1 << 2) /* Flush relations related statistics */
+#define PGSTAT_BACKEND_FLUSH_ALL   (PGSTAT_BACKEND_FLUSH_IO | PGSTAT_BACKEND_FLUSH_WAL | PGSTAT_BACKEND_FLUSH_REL)
 
 extern bool pgstat_flush_backend(bool nowait, bits32 flags);
 extern bool pgstat_backend_flush_cb(bool nowait);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index e6f2e93b2d6..61e85da269c 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2226,6 +2226,7 @@ PgStatShared_Wal
 PgStat_ArchiverStats
 PgStat_Backend
 PgStat_BackendPending
+PgStat_BackendRelPending
 PgStat_BackendSubEntry
 PgStat_BgWriterStats
 PgStat_BktypeIO
-- 
2.34.1

