From cb3d29862851cc2525282bb46b90e263a5d4a2d5 Mon Sep 17 00:00:00 2001
From: David Christensen <david.christensen@crunchydata.com>
Date: Fri, 29 Sep 2023 15:03:00 -0400
Subject: [PATCH v3 6/8] Use fastdiv code in visibility map

---
 src/backend/access/heap/visibilitymap.c | 93 ++++++++++++++++++-------
 1 file changed, 68 insertions(+), 25 deletions(-)

diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c
index ab4d38fbe6..7c80df680c 100644
--- a/src/backend/access/heap/visibilitymap.c
+++ b/src/backend/access/heap/visibilitymap.c
@@ -105,18 +105,25 @@
  * extra headers, so the whole page minus the standard page header is
  * used for the bitmap.
  */
-#define MAPSIZE (cluster_block_size - MAXALIGN(SizeOfPageHeaderData))
+#define MAPSIZE(blocksize) (blocksize - MAXALIGN(SizeOfPageHeaderData))
 
 /* Number of heap blocks we can represent in one byte */
-#define HEAPBLOCKS_PER_BYTE (BITS_PER_BYTE / BITS_PER_HEAPBLOCK)
+#define HEAPBLOCKS_PER_BYTE(blocksize) (BITS_PER_BYTE / BITS_PER_HEAPBLOCK)
+
+/* Init routine for our fastmath */
+#define MAPBLOCK_INIT if (unlikely(!mapblock_size))		\
+	{													\
+		mapblock_size = MAPSIZE(cluster_block_size);	\
+		mapblock_inv = pg_fastinverse(mapblock_size);	\
+	}
 
 /* Number of heap blocks we can represent in one visibility map page. */
-#define HEAPBLOCKS_PER_PAGE (MAPSIZE << BITS_PER_HEAPBLOCK)
+#define HEAPBLOCKS_PER_PAGE(blocksize) (MAPSIZE(blocksize) << BITS_PER_HEAPBLOCK)
 
 /* Mapping from heap block number to the right bit in the visibility map */
-#define HEAPBLK_TO_MAPBLOCK(x) ((x) / HEAPBLOCKS_PER_PAGE)
-#define HEAPBLK_TO_MAPBYTE(x) (((x) % HEAPBLOCKS_PER_PAGE) / HEAPBLOCKS_PER_BYTE)
-#define HEAPBLK_TO_OFFSET(x) (((x) % HEAPBLOCKS_PER_BYTE) * BITS_PER_HEAPBLOCK)
+#define HEAPBLK_TO_MAPBLOCK(x) (pg_fastdiv((x),mapblock_size,mapblock_inv))
+#define HEAPBLK_TO_MAPBYTE(x) (pg_fastmod((x),mapblock_size,mapblock_inv) >> 2) /* always 4 blocks per byte */
+#define HEAPBLK_TO_OFFSET(x) (((x) & 0x3) << 1) /* always 2 bits per entry */
 
 /* Masks for counting subsets of bits in the visibility map. */
 #define VISIBLE_MASK64	UINT64CONST(0x5555555555555555) /* The lower bit of each
@@ -128,6 +135,9 @@
 static Buffer vm_readbuf(Relation rel, BlockNumber blkno, bool extend);
 static Buffer vm_extend(Relation rel, BlockNumber vm_nblocks);
 
+/* storage for the fast div/mod inverse */
+static uint64 mapblock_inv = 0;
+static uint32 mapblock_size = 0;
 
 /*
  *	visibilitymap_clear - clear specified bits for one page in visibility map
@@ -139,13 +149,20 @@ static Buffer vm_extend(Relation rel, BlockNumber vm_nblocks);
 bool
 visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer vmbuf, uint8 flags)
 {
-	BlockNumber mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk);
-	int			mapByte = HEAPBLK_TO_MAPBYTE(heapBlk);
-	int			mapOffset = HEAPBLK_TO_OFFSET(heapBlk);
-	uint8		mask = flags << mapOffset;
+	BlockNumber mapBlock;
+	int			mapByte;
+	int			mapOffset;
+	uint8		mask;
 	char	   *map;
 	bool		cleared = false;
 
+	MAPBLOCK_INIT;
+
+	mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk);
+	mapByte = HEAPBLK_TO_MAPBYTE(heapBlk);
+	mapOffset = HEAPBLK_TO_OFFSET(heapBlk);
+	mask = flags << mapOffset;
+
 	/* Must never clear all_visible bit while leaving all_frozen bit set */
 	Assert(flags & VISIBILITYMAP_VALID_BITS);
 	Assert(flags != VISIBILITYMAP_ALL_VISIBLE);
@@ -192,7 +209,11 @@ visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer vmbuf, uint8 flags
 void
 visibilitymap_pin(Relation rel, BlockNumber heapBlk, Buffer *vmbuf)
 {
-	BlockNumber mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk);
+	BlockNumber mapBlock;
+
+	MAPBLOCK_INIT;
+
+	mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk);
 
 	/* Reuse the old pinned buffer if possible */
 	if (BufferIsValid(*vmbuf))
@@ -216,7 +237,11 @@ visibilitymap_pin(Relation rel, BlockNumber heapBlk, Buffer *vmbuf)
 bool
 visibilitymap_pin_ok(BlockNumber heapBlk, Buffer vmbuf)
 {
-	BlockNumber mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk);
+	BlockNumber mapBlock;
+
+	MAPBLOCK_INIT;
+
+	mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk);
 
 	return BufferIsValid(vmbuf) && BufferGetBlockNumber(vmbuf) == mapBlock;
 }
@@ -247,12 +272,18 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf,
 				  XLogRecPtr recptr, Buffer vmBuf, TransactionId cutoff_xid,
 				  uint8 flags)
 {
-	BlockNumber mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk);
-	uint32		mapByte = HEAPBLK_TO_MAPBYTE(heapBlk);
-	uint8		mapOffset = HEAPBLK_TO_OFFSET(heapBlk);
+	BlockNumber mapBlock;
+	uint32		mapByte;
+	uint8		mapOffset;
 	Page		page;
 	uint8	   *map;
 
+	MAPBLOCK_INIT;
+
+	mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk);
+	mapByte = HEAPBLK_TO_MAPBYTE(heapBlk);
+	mapOffset = HEAPBLK_TO_OFFSET(heapBlk);
+
 #ifdef TRACE_VISIBILITYMAP
 	elog(DEBUG1, "vm_set %s %d", RelationGetRelationName(rel), heapBlk);
 #endif
@@ -337,12 +368,18 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf,
 uint8
 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *vmbuf)
 {
-	BlockNumber mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk);
-	uint32		mapByte = HEAPBLK_TO_MAPBYTE(heapBlk);
-	uint8		mapOffset = HEAPBLK_TO_OFFSET(heapBlk);
+	BlockNumber mapBlock;
+	uint32		mapByte;
+	uint8		mapOffset;
 	char	   *map;
 	uint8		result;
 
+	MAPBLOCK_INIT;
+
+	mapBlock = HEAPBLK_TO_MAPBLOCK(heapBlk);
+	mapByte = HEAPBLK_TO_MAPBYTE(heapBlk);
+	mapOffset = HEAPBLK_TO_OFFSET(heapBlk);
+
 #ifdef TRACE_VISIBILITYMAP
 	elog(DEBUG1, "vm_get_status %s %d", RelationGetRelationName(rel), heapBlk);
 #endif
@@ -414,16 +451,16 @@ visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_fro
 		 */
 		map = (uint64 *) PageGetContents(BufferGetPage(mapBuffer));
 
-		Assert(MAPSIZE % sizeof(uint64) == 0);
+		Assert(mapblock_size % sizeof(uint64) == 0);
 
 		if (all_frozen == NULL)
 		{
-			for (i = 0; i < MAPSIZE / sizeof(uint64); i++)
+			for (i = 0; i < mapblock_size / sizeof(uint64); i++)
 				nvisible += pg_popcount64(map[i] & VISIBLE_MASK64);
 		}
 		else
 		{
-			for (i = 0; i < MAPSIZE / sizeof(uint64); i++)
+			for (i = 0; i < mapblock_size / sizeof(uint64); i++)
 			{
 				nvisible += pg_popcount64(map[i] & VISIBLE_MASK64);
 				nfrozen += pg_popcount64(map[i] & FROZEN_MASK64);
@@ -455,9 +492,15 @@ visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks)
 	BlockNumber newnblocks;
 
 	/* last remaining block, byte, and bit */
-	BlockNumber truncBlock = HEAPBLK_TO_MAPBLOCK(nheapblocks);
-	uint32		truncByte = HEAPBLK_TO_MAPBYTE(nheapblocks);
-	uint8		truncOffset = HEAPBLK_TO_OFFSET(nheapblocks);
+	BlockNumber truncBlock;
+	uint32		truncByte;
+	uint8		truncOffset;
+
+	MAPBLOCK_INIT;
+
+	truncBlock = HEAPBLK_TO_MAPBLOCK(nheapblocks);
+	truncByte = HEAPBLK_TO_MAPBYTE(nheapblocks);
+	truncOffset = HEAPBLK_TO_OFFSET(nheapblocks);
 
 #ifdef TRACE_VISIBILITYMAP
 	elog(DEBUG1, "vm_truncate %s %d", RelationGetRelationName(rel), nheapblocks);
@@ -501,7 +544,7 @@ visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks)
 		START_CRIT_SECTION();
 
 		/* Clear out the unwanted bytes. */
-		MemSet(&map[truncByte + 1], 0, MAPSIZE - (truncByte + 1));
+		MemSet(&map[truncByte + 1], 0, mapblock_size - (truncByte + 1));
 
 		/*----
 		 * Mask out the unwanted bits of the last remaining byte.
-- 
2.40.1

