From 1a0617043d729e86570e3684012aa8015e84686d Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Wed, 2 Mar 2022 18:02:03 -0800
Subject: [PATCH v65 02/11] pgstat: Introduce pgstat_relation_should_count().

---
 src/include/pgstat.h                 | 27 +++++++++----
 src/include/utils/rel.h              |  1 +
 src/backend/access/common/relation.c |  4 +-
 src/backend/catalog/index.c          |  2 +-
 src/backend/postmaster/pgstat.c      | 59 +++++++++++++++++-----------
 5 files changed, 58 insertions(+), 35 deletions(-)

diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index be2f7e2bcc7..f808955125b 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -1102,43 +1102,54 @@ extern void pgstat_initialize(void);
 extern PgStat_TableStatus *find_tabstat_entry(Oid rel_id);
 extern PgStat_BackendFunctionEntry *find_funcstat_entry(Oid func_id);
 
-extern void pgstat_initstats(Relation rel);
+extern void pgstat_relation_init(Relation rel);
+extern void pgstat_relation_assoc(Relation rel);
+
+/*
+ * AFIXME: pgstat_enabled should instead be tri-valued (disabled,
+ * needs-initialization, initialized). Then we don't need to check two
+ * separate variables.
+ */
+#define pgstat_relation_should_count(rel)                           \
+	(likely((rel)->pgstat_info != NULL) ? true :                    \
+	 ((rel)->pgstat_enabled ? pgstat_relation_assoc(rel), true : false))
+
 
 /* nontransactional event counts are simple enough to inline */
 
 #define pgstat_count_heap_scan(rel)									\
 	do {															\
-		if ((rel)->pgstat_info != NULL)								\
+		if (pgstat_relation_should_count(rel))						\
 			(rel)->pgstat_info->t_counts.t_numscans++;				\
 	} while (0)
 #define pgstat_count_heap_getnext(rel)								\
 	do {															\
-		if ((rel)->pgstat_info != NULL)								\
+		if (pgstat_relation_should_count(rel))						\
 			(rel)->pgstat_info->t_counts.t_tuples_returned++;		\
 	} while (0)
 #define pgstat_count_heap_fetch(rel)								\
 	do {															\
-		if ((rel)->pgstat_info != NULL)								\
+		if (pgstat_relation_should_count(rel))						\
 			(rel)->pgstat_info->t_counts.t_tuples_fetched++;		\
 	} while (0)
 #define pgstat_count_index_scan(rel)								\
 	do {															\
-		if ((rel)->pgstat_info != NULL)								\
+		if (pgstat_relation_should_count(rel))						\
 			(rel)->pgstat_info->t_counts.t_numscans++;				\
 	} while (0)
 #define pgstat_count_index_tuples(rel, n)							\
 	do {															\
-		if ((rel)->pgstat_info != NULL)								\
+		if (pgstat_relation_should_count(rel))						\
 			(rel)->pgstat_info->t_counts.t_tuples_returned += (n);	\
 	} while (0)
 #define pgstat_count_buffer_read(rel)								\
 	do {															\
-		if ((rel)->pgstat_info != NULL)								\
+		if (pgstat_relation_should_count(rel))						\
 			(rel)->pgstat_info->t_counts.t_blocks_fetched++;		\
 	} while (0)
 #define pgstat_count_buffer_hit(rel)								\
 	do {															\
-		if ((rel)->pgstat_info != NULL)								\
+		if (pgstat_relation_should_count(rel))						\
 			(rel)->pgstat_info->t_counts.t_blocks_hit++;			\
 	} while (0)
 #define pgstat_count_buffer_read_time(n)							\
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 3b4ab65ae20..485d38ecee3 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -247,6 +247,7 @@ typedef struct RelationData
 	Oid			rd_toastoid;	/* Real TOAST table's OID, or InvalidOid */
 
 	/* use "struct" here to avoid needing to include pgstat.h: */
+	bool		pgstat_enabled;
 	struct PgStat_TableStatus *pgstat_info; /* statistics collection area */
 } RelationData;
 
diff --git a/src/backend/access/common/relation.c b/src/backend/access/common/relation.c
index 1c02bf03a34..003663ab811 100644
--- a/src/backend/access/common/relation.c
+++ b/src/backend/access/common/relation.c
@@ -73,7 +73,7 @@ relation_open(Oid relationId, LOCKMODE lockmode)
 	if (RelationUsesLocalBuffers(r))
 		MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
 
-	pgstat_initstats(r);
+	pgstat_relation_init(r);
 
 	return r;
 }
@@ -123,7 +123,7 @@ try_relation_open(Oid relationId, LOCKMODE lockmode)
 	if (RelationUsesLocalBuffers(r))
 		MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
 
-	pgstat_initstats(r);
+	pgstat_relation_init(r);
 
 	return r;
 }
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 5e3fc2b35dc..a9e69b8122b 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1743,7 +1743,7 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
 		tabentry = pgstat_fetch_stat_tabentry(oldIndexId);
 		if (tabentry)
 		{
-			if (newClassRel->pgstat_info)
+			if (pgstat_relation_should_count(newClassRel))
 			{
 				newClassRel->pgstat_info->t_counts.t_numscans = tabentry->numscans;
 				newClassRel->pgstat_info->t_counts.t_tuples_returned = tabentry->tuples_returned;
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 53ddd930e6e..de45a10334b 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -188,7 +188,7 @@ static bool pgStatRunningInCollector = false;
  * for the life of the backend.  Also, we zero out the t_id fields of the
  * contained PgStat_TableStatus structs whenever they are not actively in use.
  * This allows relcache pgstat_info pointers to be treated as long-lived data,
- * avoiding repeated searches in pgstat_initstats() when a relation is
+ * avoiding repeated searches in pgstat_relation_assoc() when a relation is
  * repeatedly opened during a transaction.
  */
 #define TABSTAT_QUANTUM		100 /* we alloc this many at a time */
@@ -1683,7 +1683,7 @@ pgstat_report_analyze(Relation rel,
 	 *
 	 * Waste no time on partitioned tables, though.
 	 */
-	if (rel->pgstat_info != NULL &&
+	if (pgstat_relation_should_count(rel) &&
 		rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
 	{
 		PgStat_TableXactStatus *trans;
@@ -2121,7 +2121,7 @@ pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
 
 
 /* ----------
- * pgstat_initstats() -
+ * pgstat_relation_init() -
  *
  *	Initialize a relcache entry to count access statistics.
  *	Called whenever a relation is opened.
@@ -2133,7 +2133,7 @@ pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize)
  * ----------
  */
 void
-pgstat_initstats(Relation rel)
+pgstat_relation_init(Relation rel)
 {
 	Oid			rel_id = rel->rd_id;
 	char		relkind = rel->rd_rel->relkind;
@@ -2143,6 +2143,7 @@ pgstat_initstats(Relation rel)
 	 */
 	if (!RELKIND_HAS_STORAGE(relkind) && relkind != RELKIND_PARTITIONED_TABLE)
 	{
+		rel->pgstat_enabled = false;
 		rel->pgstat_info = NULL;
 		return;
 	}
@@ -2150,6 +2151,7 @@ pgstat_initstats(Relation rel)
 	if (pgStatSock == PGINVALID_SOCKET || !pgstat_track_counts)
 	{
 		/* We're not counting at all */
+		rel->pgstat_enabled = false;
 		rel->pgstat_info = NULL;
 		return;
 	}
@@ -2158,11 +2160,22 @@ pgstat_initstats(Relation rel)
 	 * If we already set up this relation in the current transaction, nothing
 	 * to do.
 	 */
-	if (rel->pgstat_info != NULL &&
+	if (rel->pgstat_info &&
 		rel->pgstat_info->t_id == rel_id)
 		return;
 
-	/* Else find or make the PgStat_TableStatus entry, and update link */
+	rel->pgstat_enabled = true;
+}
+
+void
+pgstat_relation_assoc(Relation rel)
+{
+	Oid			rel_id = rel->rd_id;
+
+	Assert(rel->pgstat_enabled);
+	Assert(rel->pgstat_info == NULL);
+
+	/* find or make the PgStat_TableStatus entry, and update link */
 	rel->pgstat_info = get_tabstat_entry(rel_id, rel->rd_rel->relisshared);
 }
 
@@ -2331,13 +2344,12 @@ add_tabstat_xact_level(PgStat_TableStatus *pgstat_info, int nest_level)
 void
 pgstat_count_heap_insert(Relation rel, PgStat_Counter n)
 {
-	PgStat_TableStatus *pgstat_info = rel->pgstat_info;
-
-	if (pgstat_info != NULL)
+	if (pgstat_relation_should_count(rel))
 	{
-		/* We have to log the effect at the proper transactional level */
+		PgStat_TableStatus *pgstat_info = rel->pgstat_info;
 		int			nest_level = GetCurrentTransactionNestLevel();
 
+		/* We have to log the effect at the proper transactional level */
 		if (pgstat_info->trans == NULL ||
 			pgstat_info->trans->nest_level != nest_level)
 			add_tabstat_xact_level(pgstat_info, nest_level);
@@ -2352,13 +2364,12 @@ pgstat_count_heap_insert(Relation rel, PgStat_Counter n)
 void
 pgstat_count_heap_update(Relation rel, bool hot)
 {
-	PgStat_TableStatus *pgstat_info = rel->pgstat_info;
-
-	if (pgstat_info != NULL)
+	if (pgstat_relation_should_count(rel))
 	{
-		/* We have to log the effect at the proper transactional level */
+		PgStat_TableStatus *pgstat_info = rel->pgstat_info;
 		int			nest_level = GetCurrentTransactionNestLevel();
 
+		/* We have to log the effect at the proper transactional level */
 		if (pgstat_info->trans == NULL ||
 			pgstat_info->trans->nest_level != nest_level)
 			add_tabstat_xact_level(pgstat_info, nest_level);
@@ -2377,13 +2388,12 @@ pgstat_count_heap_update(Relation rel, bool hot)
 void
 pgstat_count_heap_delete(Relation rel)
 {
-	PgStat_TableStatus *pgstat_info = rel->pgstat_info;
-
-	if (pgstat_info != NULL)
+	if (pgstat_relation_should_count(rel))
 	{
-		/* We have to log the effect at the proper transactional level */
+		PgStat_TableStatus *pgstat_info = rel->pgstat_info;
 		int			nest_level = GetCurrentTransactionNestLevel();
 
+		/* We have to log the effect at the proper transactional level */
 		if (pgstat_info->trans == NULL ||
 			pgstat_info->trans->nest_level != nest_level)
 			add_tabstat_xact_level(pgstat_info, nest_level);
@@ -2435,13 +2445,12 @@ pgstat_truncdrop_restore_counters(PgStat_TableXactStatus *trans)
 void
 pgstat_count_truncate(Relation rel)
 {
-	PgStat_TableStatus *pgstat_info = rel->pgstat_info;
-
-	if (pgstat_info != NULL)
+	if (pgstat_relation_should_count(rel))
 	{
-		/* We have to log the effect at the proper transactional level */
+		PgStat_TableStatus *pgstat_info = rel->pgstat_info;
 		int			nest_level = GetCurrentTransactionNestLevel();
 
+		/* We have to log the effect at the proper transactional level */
 		if (pgstat_info->trans == NULL ||
 			pgstat_info->trans->nest_level != nest_level)
 			add_tabstat_xact_level(pgstat_info, nest_level);
@@ -2464,10 +2473,12 @@ pgstat_count_truncate(Relation rel)
 void
 pgstat_update_heap_dead_tuples(Relation rel, int delta)
 {
-	PgStat_TableStatus *pgstat_info = rel->pgstat_info;
+	if (pgstat_relation_should_count(rel))
+	{
+		PgStat_TableStatus *pgstat_info = rel->pgstat_info;
 
-	if (pgstat_info != NULL)
 		pgstat_info->t_counts.t_delta_dead_tuples -= delta;
+	}
 }
 
 /*
-- 
2.35.1.354.g715d08a9e5

