From 18eea37d9f5d46d2e2c1295528de2154ed23456d Mon Sep 17 00:00:00 2001
From: Matthias van de Meent <boekewurm+postgres@gmail.com>
Date: Fri, 19 Dec 2025 22:27:04 +0100
Subject: [PATCH v13 2/8] pg_visibility: vectorize collect_visibility_data

---
 contrib/pg_visibility/pg_visibility.c | 40 +++++++++++++++++++++------
 1 file changed, 31 insertions(+), 9 deletions(-)

diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index 7046c1b5f8e..8c76b0bf7f6 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -510,6 +510,9 @@ collect_visibility_data(Oid relid, bool include_pd)
 	BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
 	BlockRangeReadStreamPrivate p;
 	ReadStream *stream = NULL;
+#define VM_BATCHSIZE	1024
+	BlockNumber *blknos;
+	uint8	   *status;
 
 	rel = relation_open(relid, AccessShareLock);
 
@@ -521,6 +524,9 @@ collect_visibility_data(Oid relid, bool include_pd)
 	info->next = 0;
 	info->count = nblocks;
 
+	blknos = palloc0_array(BlockNumber, VM_BATCHSIZE);
+	status = palloc0_array(uint8, VM_BATCHSIZE);
+
 	/* Create a stream if reading main fork. */
 	if (include_pd)
 	{
@@ -541,30 +547,44 @@ collect_visibility_data(Oid relid, bool include_pd)
 											0);
 	}
 
-	for (blkno = 0; blkno < nblocks; ++blkno)
+	for (blkno = 0; blkno < nblocks;)
 	{
-		int32		mapbits;
+		int batchsize = 0;
+
+		for (BlockNumber bno = blkno; batchsize < VM_BATCHSIZE && bno < nblocks;)
+			blknos[batchsize++] = bno++;
 
 		/* Make sure we are interruptible. */
 		CHECK_FOR_INTERRUPTS();
 
-		/* Get map info. */
-		mapbits = (int32) visibilitymap_get_status(rel, blkno, &vmbuffer);
-		if ((mapbits & VISIBILITYMAP_ALL_VISIBLE) != 0)
-			info->bits[blkno] |= (1 << 0);
-		if ((mapbits & VISIBILITYMAP_ALL_FROZEN) != 0)
-			info->bits[blkno] |= (1 << 1);
+		/* Get map info in bulk. */
+		visibilitymap_get_statusv(rel, blknos, status, batchsize, &vmbuffer);
+
+		/* move the status bits */
+		for (int i = 0; i < batchsize; i++)
+		{
+			uint32 mapbits = status[i];
+			BlockNumber bno = blknos[i];
+
+			if ((mapbits & VISIBILITYMAP_ALL_VISIBLE) != 0)
+				info->bits[bno] |= (1 << 0);
+			if ((mapbits & VISIBILITYMAP_ALL_FROZEN) != 0)
+				info->bits[bno] |= (1 << 1);
+		}
 
 		/*
 		 * Page-level data requires reading every block, so only get it if the
 		 * caller needs it.  Use a buffer access strategy, too, to prevent
 		 * cache-trashing.
 		 */
-		if (include_pd)
+		for (int i = 0; include_pd && i < batchsize; i++)
 		{
 			Buffer		buffer;
 			Page		page;
 
+			/* This subloop should be interruptable, it does IO */
+			CHECK_FOR_INTERRUPTS();
+
 			buffer = read_stream_next_buffer(stream, NULL);
 			LockBuffer(buffer, BUFFER_LOCK_SHARE);
 
@@ -574,6 +594,8 @@ collect_visibility_data(Oid relid, bool include_pd)
 
 			UnlockReleaseBuffer(buffer);
 		}
+
+		blkno += batchsize;
 	}
 
 	if (include_pd)
-- 
2.50.1 (Apple Git-155)

