From b6e6b651af17cbf36192ab1f3f658968e94e172c Mon Sep 17 00:00:00 2001
From: Matthias van de Meent <boekewurm+postgres@gmail.com>
Date: Fri, 8 Apr 2022 14:54:52 +0200
Subject: [PATCH v1 6/6] Specialize the nbtree rd_indam entry.

Because each rd_indam struct is seperately allocated for each index, we can
freely modify it at runtime without impacting other indexes of the same
access method. For btinsert (which effectively only calls _bt_insert) it is
useful to specialize that function, which also makes rd_indam->aminsert a
good signal whether or not the indexRelation has been fully optimized yet.
---
 src/backend/access/nbtree/nbtree.c      |  7 +++++++
 src/backend/access/nbtree/nbtree_spec.h | 20 +++++++++++++++-----
 src/backend/access/nbtree/nbtsearch.c   |  2 ++
 src/backend/access/nbtree/nbtsort.c     |  2 ++
 src/include/access/nbtree.h             |  7 +++++++
 5 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 09c43eb226..95da2c46bf 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -161,6 +161,8 @@ btbuildempty(Relation index)
 	metapage = (Page) palloc(BLCKSZ);
 	_bt_initmetapage(metapage, P_NONE, 0, _bt_allequalimage(index, false));
 
+	nbt_opt_specialize(index);
+
 	/*
 	 * Write the page and log it.  It might seem that an immediate sync would
 	 * be sufficient to guarantee that the file exists on disk, but recovery
@@ -323,6 +325,8 @@ btbeginscan(Relation rel, int nkeys, int norderbys)
 	IndexScanDesc scan;
 	BTScanOpaque so;
 
+	nbt_opt_specialize(rel);
+
 	/* no order by operators allowed */
 	Assert(norderbys == 0);
 
@@ -765,6 +769,7 @@ btbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 {
 	Relation	rel = info->index;
 	BTCycleId	cycleid;
+	nbt_opt_specialize(info->index);
 
 	/* allocate stats if first time through, else re-use existing struct */
 	if (stats == NULL)
@@ -798,6 +803,8 @@ btvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
 	if (info->analyze_only)
 		return stats;
 
+	nbt_opt_specialize(info->index);
+
 	/*
 	 * If btbulkdelete was called, we need not do anything (we just maintain
 	 * the information used within _bt_vacuum_needs_cleanup() by calling
diff --git a/src/backend/access/nbtree/nbtree_spec.h b/src/backend/access/nbtree/nbtree_spec.h
index 2e9190f267..001e56bfb8 100644
--- a/src/backend/access/nbtree/nbtree_spec.h
+++ b/src/backend/access/nbtree/nbtree_spec.h
@@ -2,9 +2,18 @@
  * Specialized functions for nbtree.c
  */
 
+/*
+ * _bt_specialize() -- Specialize this index relation for its index key.
+ */
 void
-NBTS_FUNCTION(_bt_specialize)(Relation rel) {
+NBTS_FUNCTION(_bt_specialize)(Relation rel)
+{
+	PopulateTupleDescCacheOffsets(rel->rd_att);
+#ifdef NBTS_SPECIALIZING_DEFAULT
+	nbts_call_norel(_bt_specialize, rel, rel);
+#else
 	rel->rd_indam->aminsert = NBTS_FUNCTION(btinsert);
+#endif
 }
 
 /*
@@ -23,10 +32,11 @@ NBTS_FUNCTION(btinsert)(Relation rel, Datum *values, bool *isnull,
 	bool		result;
 	IndexTuple	itup;
 
-#ifdef NBT_SPEC_DEFAULT
-	nbts_call(_bt_specialize, rel);
-	nbts_call(_bt_insert, rel, values, isnull, ht_ctid, heapRel, checkUnique,
-			  indexUnchanged, indexInfo);
+#ifdef NBTS_SPECIALIZING_DEFAULT
+	nbt_opt_specialize(rel);
+
+	return nbts_call(btinsert, rel, values, isnull, ht_ctid, heapRel,
+					 checkUnique, indexUnchanged, indexInfo);
 #else
 
 	/* generate an index tuple */
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index e81eee9c35..d5152bfcb7 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -181,6 +181,8 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
 
 	Assert(!BTScanPosIsValid(so->currPos));
 
+	nbt_opt_specialize(scan->indexRelation);
+
 	pgstat_count_index_scan(rel);
 
 	/*
diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
index 762921e66a..f2311caf16 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -305,6 +305,8 @@ btbuild(Relation heap, Relation index, IndexInfo *indexInfo)
 	BTBuildState buildstate;
 	double		reltuples;
 
+	nbt_opt_specialize(index);
+
 #ifdef BTREE_BUILD_STATS
 	if (log_btree_build_stats)
 		ResetUsage();
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index d59531f3b3..e101797419 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -1134,6 +1134,12 @@ typedef struct BTOptions
 
 #ifdef NBTS_ENABLED
 
+#define nbt_opt_specialize(rel) \
+do { \
+	if (unlikely((rel)->rd_indam->aminsert == btinsert)) \
+		_bt_specialize(rel); \
+} while (false)
+
 #define NBT_SPECIALIZE_CALL(function, rel, ...) \
 ( \
 	IndexRelationGetNumberOfKeyAttributes(rel) == 1 ? ( \
@@ -1154,6 +1160,7 @@ typedef struct BTOptions
 
 #else /* not defined NBTS_ENABLED */
 
+#define nbt_opt_specialize(rel)
 #define NBT_SPECIALIZE_CALL(function, rel, ...) function(__VA_ARGS__)
 
 #endif /* NBTS_ENABLED */
-- 
2.30.2

