From 029ec00036db1d218df83117ad576299287e888d Mon Sep 17 00:00:00 2001
From: David Geier <geidav.pg@gmail.com>
Date: Tue, 13 Oct 2026 13:36:22 +0200
Subject: [PATCH v2 2/2] TIDBitmap uses sort_template.h for pagetable sorting

Generate specialized sort functions for the pagetable instead of
going through generic qsort()/qsort_arg() comparator calls. The
inlined comparator avoids function call overhead per comparison.

The shared-iteration index arrays need the pagetable base address
to resolve indexes to entries, so that variant uses
ST_COMPARE_ARG_TYPE to pass it through.
---
 src/backend/nodes/tidbitmap.c | 58 ++++++++++++++++++++++-------------
 1 file changed, 37 insertions(+), 21 deletions(-)

diff --git a/src/backend/nodes/tidbitmap.c b/src/backend/nodes/tidbitmap.c
index f1f925cb13b..5108ba1eef1 100644
--- a/src/backend/nodes/tidbitmap.c
+++ b/src/backend/nodes/tidbitmap.c
@@ -225,9 +225,10 @@ static PagetableEntry *tbm_get_pageentry(TIDBitmap *tbm, BlockNumber pageno);
 static bool tbm_page_is_lossy(const TIDBitmap *tbm, BlockNumber pageno);
 static void tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno);
 static void tbm_lossify(TIDBitmap *tbm);
-static int	tbm_comparator(const void *left, const void *right);
-static int	tbm_shared_comparator(const void *left, const void *right,
-								  void *arg);
+static inline int tbm_comparator(PagetableEntry **lpage,
+								 PagetableEntry **rpage);
+static inline int tbm_shared_comparator(const int *lindex, const int *rindex,
+										const PagetableEntry *base);
 
 /* define hashtable mapping block numbers to PagetableEntry's */
 #define SH_USE_NONDEFAULT_ALLOCATOR
@@ -242,6 +243,25 @@ static int	tbm_shared_comparator(const void *left, const void *right,
 #define SH_DECLARE
 #include "lib/simplehash.h"
 
+#define ST_SORT	qsort_pagetable
+#define ST_ELEMENT_TYPE PagetableEntry *
+#define ST_COMPARE(a, b) tbm_comparator(a, b)
+#define ST_SCOPE static
+#define ST_DEFINE
+#include "lib/sort_template.h"
+
+/*
+ * The shared-iteration arrays contain indexes into the pagetable entry
+ * array rather than pointers, so their comparator needs the base address
+ * of the entry array passed through as an argument.
+ */
+#define ST_SORT qsort_pagetable_index
+#define ST_ELEMENT_TYPE int
+#define ST_COMPARE(a, b, arg) tbm_shared_comparator(a, b, arg)
+#define ST_COMPARE_ARG_TYPE PagetableEntry
+#define ST_SCOPE static
+#define ST_DEFINE
+#include "lib/sort_template.h"
 
 /*
  * tbm_create - create an initially-empty bitmap
@@ -727,11 +747,9 @@ tbm_begin_private_iterate(TIDBitmap *tbm)
 		Assert(npages == tbm->npages);
 		Assert(nchunks == tbm->nchunks);
 		if (npages > 1)
-			qsort(tbm->spages, npages, sizeof(PagetableEntry *),
-				  tbm_comparator);
+			qsort_pagetable(tbm->spages, npages);
 		if (nchunks > 1)
-			qsort(tbm->schunks, nchunks, sizeof(PagetableEntry *),
-				  tbm_comparator);
+			qsort_pagetable(tbm->schunks, nchunks);
 	}
 
 	tbm->iterating = TBM_ITERATING_PRIVATE;
@@ -840,11 +858,9 @@ tbm_prepare_shared_iterate(TIDBitmap *tbm)
 		if (ptbase != NULL)
 			pg_atomic_init_u32(&ptbase->refcount, 0);
 		if (npages > 1)
-			qsort_arg(ptpages->index, npages, sizeof(int),
-					  tbm_shared_comparator, ptbase->ptentry);
+			qsort_pagetable_index(ptpages->index, npages, ptbase->ptentry);
 		if (nchunks > 1)
-			qsort_arg(ptchunks->index, nchunks, sizeof(int),
-					  tbm_shared_comparator, ptbase->ptentry);
+			qsort_pagetable_index(ptchunks->index, nchunks, ptbase->ptentry);
 	}
 
 	/*
@@ -1421,13 +1437,14 @@ tbm_lossify(TIDBitmap *tbm)
 /*
  * qsort comparator to handle PagetableEntry pointers.
  */
-static int
-tbm_comparator(const void *left, const void *right)
+static inline int
+tbm_comparator( PagetableEntry **lpage,  PagetableEntry **rpage)
 {
-	BlockNumber l = (*((PagetableEntry *const *) left))->blockno;
-	BlockNumber r = (*((PagetableEntry *const *) right))->blockno;
-
-	return pg_cmp_u32(l, r);
+	if ((*lpage)->blockno < (*rpage)->blockno)
+		return -1;
+	else if ((*lpage)->blockno > (*rpage)->blockno)
+		return 1;
+	return 0;
 }
 
 /*
@@ -1436,11 +1453,10 @@ tbm_comparator(const void *left, const void *right)
  * blockno.
  */
 static int
-tbm_shared_comparator(const void *left, const void *right, void *arg)
+tbm_shared_comparator(const int *lindex, const int *rindex, const PagetableEntry *base)
 {
-	PagetableEntry *base = (PagetableEntry *) arg;
-	PagetableEntry *lpage = &base[*(const int *) left];
-	PagetableEntry *rpage = &base[*(const int *) right];
+	const PagetableEntry *lpage = &base[*lindex];
+	const PagetableEntry *rpage = &base[*rindex];
 
 	if (lpage->blockno < rpage->blockno)
 		return -1;
-- 
2.53.0

