From 44e27be7ce30049c83e7a15aee3f9bc5bf01ac03 Mon Sep 17 00:00:00 2001
From: David Christensen <david.christensen@crunchydata.com>
Date: Sun, 26 Nov 2023 16:24:09 -0500
Subject: [PATCH v4 01/22] refactor: Create PageUsableSpace to represent space
 post-smgr

Work to abstract out the direct usage of SizeOfPageHeaderData and BLCKSZ from
access methods; they should only need to operate from a sense of what space is
available to them and not be party to the details.

This is in preparation for allowing space to be reserved at the end of the page
for, e.g., authenticated encryption tags and/or evs which will prevent future
churn when we redefine this value in the future.

This is largely mechanical, though some spots are trickier in their reworking;
basically anything which used BLCKSZ - SizeOfPageHeaderData (in some form).

Care was taken to ensure that even with differences in MAXALIGN() that no
changes were introduced in the rework here, though if there is an area to look
at more closely, this is it.
---
 contrib/bloom/bloom.h                    | 10 +++++-----
 contrib/pageinspect/btreefuncs.c         |  2 +-
 contrib/pgstattuple/pgstatapprox.c       |  2 +-
 contrib/pgstattuple/pgstatindex.c        |  2 +-
 src/backend/access/common/bufmask.c      |  2 +-
 src/backend/access/gin/ginfast.c         |  2 +-
 src/backend/access/gist/gistbuild.c      |  4 ++--
 src/backend/access/heap/heapam.c         |  4 ++--
 src/backend/access/heap/heapam_handler.c |  2 +-
 src/backend/access/heap/vacuumlazy.c     |  2 +-
 src/backend/access/heap/visibilitymap.c  |  2 +-
 src/backend/optimizer/util/plancat.c     |  2 +-
 src/bin/pg_upgrade/file.c                |  2 +-
 src/include/access/brin_page.h           |  2 +-
 src/include/access/ginblock.h            |  4 ++--
 src/include/access/gist.h                |  2 +-
 src/include/access/gist_private.h        |  2 +-
 src/include/access/htup_details.h        |  8 ++++----
 src/include/access/itup.h                |  4 ++--
 src/include/access/nbtree.h              |  4 ++--
 src/include/storage/bufpage.h            |  8 ++++++++
 src/include/storage/fsm_internals.h      |  2 +-
 22 files changed, 41 insertions(+), 33 deletions(-)

diff --git a/contrib/bloom/bloom.h b/contrib/bloom/bloom.h
index fba3ba7771..6d645aa3a2 100644
--- a/contrib/bloom/bloom.h
+++ b/contrib/bloom/bloom.h
@@ -111,10 +111,10 @@ typedef struct BloomOptions
  * all space in metapage.
  */
 typedef BlockNumber FreeBlockNumberArray[
-										 MAXALIGN_DOWN(
-													   BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(BloomPageOpaqueData))
-													   - MAXALIGN(sizeof(uint16) * 2 + sizeof(uint32) + sizeof(BloomOptions))
-													   ) / sizeof(BlockNumber)
+	MAXALIGN_DOWN(
+		PageUsableSpaceMax - MAXALIGN(sizeof(BloomPageOpaqueData))
+		- MAXALIGN(sizeof(uint16) * 2 + sizeof(uint32) + sizeof(BloomOptions))
+		) / sizeof(BlockNumber)
 ];
 
 /* Metadata of bloom index */
@@ -150,7 +150,7 @@ typedef struct BloomState
 } BloomState;
 
 #define BloomPageGetFreeSpace(state, page) \
-	(BLCKSZ - MAXALIGN(SizeOfPageHeaderData) \
+	(PageUsableSpace \
 		- BloomPageGetMaxOffset(page) * (state)->sizeOfBloomTuple \
 		- MAXALIGN(sizeof(BloomPageOpaqueData)))
 
diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c
index 9cdc8e182b..1e20fecf2f 100644
--- a/contrib/pageinspect/btreefuncs.c
+++ b/contrib/pageinspect/btreefuncs.c
@@ -116,7 +116,7 @@ GetBTPageStatistics(BlockNumber blkno, Buffer buffer, BTPageStat *stat)
 
 	stat->blkno = blkno;
 
-	stat->max_avail = BLCKSZ - (BLCKSZ - phdr->pd_special + SizeOfPageHeaderData);
+	stat->max_avail = PageUsableSpace - (BLCKSZ - phdr->pd_special);
 
 	stat->dead_items = stat->live_items = 0;
 
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index c84c642355..b344dc6385 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -113,7 +113,7 @@ statapprox_heap(Relation rel, output_type *stat)
 		if (!PageIsNew(page))
 			stat->free_space += PageGetHeapFreeSpace(page);
 		else
-			stat->free_space += BLCKSZ - SizeOfPageHeaderData;
+			stat->free_space += PageUsableSpace;
 
 		/* We may count the page as scanned even if it's new/empty */
 		scanned++;
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 5c06ba6db4..2641df9d61 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -309,7 +309,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
 		{
 			int			max_avail;
 
-			max_avail = BLCKSZ - (BLCKSZ - ((PageHeader) page)->pd_special + SizeOfPageHeaderData);
+			max_avail = PageUsableSpace - (BLCKSZ - ((PageHeader) page)->pd_special);
 			indexStat.max_avail += max_avail;
 			indexStat.free_space += PageGetFreeSpace(page);
 
diff --git a/src/backend/access/common/bufmask.c b/src/backend/access/common/bufmask.c
index 10a1e4d7c6..92bb06bb50 100644
--- a/src/backend/access/common/bufmask.c
+++ b/src/backend/access/common/bufmask.c
@@ -120,7 +120,7 @@ mask_page_content(Page page)
 {
 	/* Mask Page Content */
 	memset(page + SizeOfPageHeaderData, MASK_MARKER,
-		   BLCKSZ - SizeOfPageHeaderData);
+		   PageUsableSpace);
 
 	/* Mask pd_lower and pd_upper */
 	memset(&((PageHeader) page)->pd_lower, MASK_MARKER,
diff --git a/src/backend/access/gin/ginfast.c b/src/backend/access/gin/ginfast.c
index eeca3ed318..197ea3a047 100644
--- a/src/backend/access/gin/ginfast.c
+++ b/src/backend/access/gin/ginfast.c
@@ -39,7 +39,7 @@
 int			gin_pending_list_limit = 0;
 
 #define GIN_PAGE_FREESIZE \
-	( BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(GinPageOpaqueData)) )
+	( PageUsableSpace - MAXALIGN(sizeof(GinPageOpaqueData)) )
 
 typedef struct KeyArray
 {
diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c
index ba06df30fa..1c984d9d91 100644
--- a/src/backend/access/gist/gistbuild.c
+++ b/src/backend/access/gist/gistbuild.c
@@ -636,7 +636,7 @@ gistInitBuffering(GISTBuildState *buildstate)
 	int			levelStep;
 
 	/* Calc space of index page which is available for index tuples */
-	pageFreeSpace = BLCKSZ - SizeOfPageHeaderData - sizeof(GISTPageOpaqueData)
+	pageFreeSpace = PageUsableSpace - sizeof(GISTPageOpaqueData)
 		- sizeof(ItemIdData)
 		- buildstate->freespace;
 
@@ -792,7 +792,7 @@ calculatePagesPerBuffer(GISTBuildState *buildstate, int levelStep)
 	Size		pageFreeSpace;
 
 	/* Calc space of index page which is available for index tuples */
-	pageFreeSpace = BLCKSZ - SizeOfPageHeaderData - sizeof(GISTPageOpaqueData)
+	pageFreeSpace = PageUsableSpace - sizeof(GISTPageOpaqueData)
 		- sizeof(ItemIdData)
 		- buildstate->freespace;
 
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 633c6e4303..9b034539f0 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2060,7 +2060,7 @@ heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 static int
 heap_multi_insert_pages(HeapTuple *heaptuples, int done, int ntuples, Size saveFreeSpace)
 {
-	size_t		page_avail = BLCKSZ - SizeOfPageHeaderData - saveFreeSpace;
+	size_t		page_avail = PageUsableSpace - saveFreeSpace;
 	int			npages = 1;
 
 	for (int i = done; i < ntuples; i++)
@@ -2070,7 +2070,7 @@ heap_multi_insert_pages(HeapTuple *heaptuples, int done, int ntuples, Size saveF
 		if (page_avail < tup_sz)
 		{
 			npages++;
-			page_avail = BLCKSZ - SizeOfPageHeaderData - saveFreeSpace;
+			page_avail = PageUsableSpace - saveFreeSpace;
 		}
 		page_avail -= tup_sz;
 	}
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index dd894afaf1..9e72fe6a28 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -2090,7 +2090,7 @@ heapam_relation_toast_am(Relation rel)
 #define HEAP_OVERHEAD_BYTES_PER_TUPLE \
 	(MAXALIGN(SizeofHeapTupleHeader) + sizeof(ItemIdData))
 #define HEAP_USABLE_BYTES_PER_PAGE \
-	(BLCKSZ - SizeOfPageHeaderData)
+	(PageUsableSpace)
 
 static void
 heapam_estimate_rel_size(Relation rel, int32 *attr_widths,
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index c147c77984..3d1cc75bbb 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -1301,7 +1301,7 @@ lazy_scan_new_or_empty(LVRelState *vacrel, Buffer buf, BlockNumber blkno,
 
 		if (GetRecordedFreeSpace(vacrel->rel, blkno) == 0)
 		{
-			freespace = BLCKSZ - SizeOfPageHeaderData;
+			freespace = PageUsableSpace;
 
 			RecordPageWithFreeSpace(vacrel->rel, blkno, freespace);
 		}
diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c
index 1ab6c865e3..5c48b7d63c 100644
--- a/src/backend/access/heap/visibilitymap.c
+++ b/src/backend/access/heap/visibilitymap.c
@@ -105,7 +105,7 @@
  * extra headers, so the whole page minus the standard page header is
  * used for the bitmap.
  */
-#define MAPSIZE (BLCKSZ - MAXALIGN(SizeOfPageHeaderData))
+#define MAPSIZE (PageUsableSpace)
 
 /* Number of heap blocks we can represent in one byte */
 #define HEAPBLOCKS_PER_BYTE (BITS_PER_BYTE / BITS_PER_HEAPBLOCK)
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 6bb53e4346..858682a1a2 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -1106,7 +1106,7 @@ estimate_rel_size(Relation rel, int32 *attr_widths,
 			tuple_width += MAXALIGN(SizeofHeapTupleHeader);
 			tuple_width += sizeof(ItemIdData);
 			/* note: integer division is intentional here */
-			density = (BLCKSZ - SizeOfPageHeaderData) / tuple_width;
+			density = (PageUsableSpace) / tuple_width;
 		}
 		*tuples = rint(density * (double) curpages);
 
diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c
index 73932504ca..284af5077b 100644
--- a/src/bin/pg_upgrade/file.c
+++ b/src/bin/pg_upgrade/file.c
@@ -227,7 +227,7 @@ rewriteVisibilityMap(const char *fromfile, const char *tofile,
 	struct stat statbuf;
 
 	/* Compute number of old-format bytes per new page */
-	rewriteVmBytesPerPage = (BLCKSZ - SizeOfPageHeaderData) / 2;
+	rewriteVmBytesPerPage = (PageUsableSpace) / 2;
 
 	if ((src_fd = open(fromfile, O_RDONLY | PG_BINARY, 0)) < 0)
 		pg_fatal("error while copying relation \"%s.%s\": could not open file \"%s\": %m",
diff --git a/src/include/access/brin_page.h b/src/include/access/brin_page.h
index 70b141c25e..28c4dd9f21 100644
--- a/src/include/access/brin_page.h
+++ b/src/include/access/brin_page.h
@@ -86,7 +86,7 @@ typedef struct RevmapContents
 } RevmapContents;
 
 #define REVMAP_CONTENT_SIZE \
-	(BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - \
+	(PageUsableSpace - \
 	 offsetof(RevmapContents, rm_tids) - \
 	 MAXALIGN(sizeof(BrinSpecialSpace)))
 /* max num of items in the array */
diff --git a/src/include/access/ginblock.h b/src/include/access/ginblock.h
index c55d11be64..05b2f34408 100644
--- a/src/include/access/ginblock.h
+++ b/src/include/access/ginblock.h
@@ -318,7 +318,7 @@ typedef signed char GinNullCategory;
 	 GinPageGetOpaque(page)->maxoff * sizeof(PostingItem))
 
 #define GinDataPageMaxDataSize	\
-	(BLCKSZ - MAXALIGN(SizeOfPageHeaderData) \
+	(PageUsableSpace \
 	 - MAXALIGN(sizeof(ItemPointerData)) \
 	 - MAXALIGN(sizeof(GinPageOpaqueData)))
 
@@ -326,7 +326,7 @@ typedef signed char GinNullCategory;
  * List pages
  */
 #define GinListPageSize  \
-	( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GinPageOpaqueData)) )
+	( PageUsableSpace - MAXALIGN(sizeof(GinPageOpaqueData)) )
 
 /*
  * A compressed posting list.
diff --git a/src/include/access/gist.h b/src/include/access/gist.h
index 22dd04c141..b22b9bad3d 100644
--- a/src/include/access/gist.h
+++ b/src/include/access/gist.h
@@ -98,7 +98,7 @@ typedef GISTPageOpaqueData *GISTPageOpaque;
  * key size using opclass parameters.
  */
 #define GISTMaxIndexTupleSize	\
-	MAXALIGN_DOWN((BLCKSZ - SizeOfPageHeaderData - sizeof(GISTPageOpaqueData)) / \
+	MAXALIGN_DOWN((PageUsableSpace - sizeof(GISTPageOpaqueData)) / \
 				  4 - sizeof(ItemIdData))
 
 #define GISTMaxIndexKeySize	\
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 7b8749c8db..b7402450ba 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -474,7 +474,7 @@ extern void gistadjustmembers(Oid opfamilyoid,
 /* gistutil.c */
 
 #define GiSTPageSize   \
-	( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GISTPageOpaqueData)) )
+	( PageUsableSpace - MAXALIGN(sizeof(GISTPageOpaqueData)) )
 
 #define GIST_MIN_FILLFACTOR			10
 #define GIST_DEFAULT_FILLFACTOR		90
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h
index bb5c746b98..57dd928bda 100644
--- a/src/include/access/htup_details.h
+++ b/src/include/access/htup_details.h
@@ -569,8 +569,8 @@ StaticAssertDecl(MaxOffsetNumber < SpecTokenOffsetNumber,
  * you can, say, fit 2 tuples of size ClusterMaxHeapTupleSize/2 on the same page.
  */
 #define CalcMaxHeapTupleSize(size)  (size - sizeof(ItemIdData))
-#define ClusterMaxHeapTupleSize CalcMaxHeapTupleSize(BLCKSZ - SizeOfPageHeaderData)
-#define MaxHeapTupleSizeLimit CalcMaxHeapTupleSize(BLCKSZ - SizeOfPageHeaderData)
+#define ClusterMaxHeapTupleSize CalcMaxHeapTupleSize(PageUsableSpace)
+#define MaxHeapTupleSizeLimit CalcMaxHeapTupleSize(PageUsableSpaceMax)
 #define MinHeapTupleSize  MAXALIGN(SizeofHeapTupleHeader)
 
 /*
@@ -599,8 +599,8 @@ StaticAssertDecl(MaxOffsetNumber < SpecTokenOffsetNumber,
  */
 #define CalcMaxHeapTuplesPerPage(size)	((int) ((size) / \
 			(MAXALIGN(SizeofHeapTupleHeader) + sizeof(ItemIdData))))
-#define ClusterMaxHeapTuplesPerPage CalcMaxHeapTuplesPerPage(BLCKSZ - SizeOfPageHeaderData)
-#define MaxHeapTuplesPerPageLimit CalcMaxHeapTuplesPerPage(BLCKSZ - SizeOfPageHeaderData)
+#define ClusterMaxHeapTuplesPerPage CalcMaxHeapTuplesPerPage(PageUsableSpace)
+#define MaxHeapTuplesPerPageLimit CalcMaxHeapTuplesPerPage(PageUsableSpaceMax)
 
 /*
  * MaxAttrSize is a somewhat arbitrary upper limit on the declared size of
diff --git a/src/include/access/itup.h b/src/include/access/itup.h
index 61fa8ff538..9c436c8b16 100644
--- a/src/include/access/itup.h
+++ b/src/include/access/itup.h
@@ -173,7 +173,7 @@ index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
  */
 #define CalcMaxIndexTuplesPerPage(size)	((int) ((size) / \
 			(MAXALIGN(sizeof(IndexTupleData) + 1) + sizeof(ItemIdData))))
-#define ClusterMaxIndexTuplesPerPage CalcMaxIndexTuplesPerPage(BLCKSZ - SizeOfPageHeaderData)
-#define MaxIndexTuplesPerPageLimit CalcMaxIndexTuplesPerPage(BLCKSZ - SizeOfPageHeaderData)
+#define ClusterMaxIndexTuplesPerPage CalcMaxIndexTuplesPerPage(PageUsableSpace)
+#define MaxIndexTuplesPerPageLimit CalcMaxIndexTuplesPerPage(PageUsableSpaceMax)
 
 #endif							/* ITUP_H */
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 568646a146..4607e45dff 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -194,9 +194,9 @@ typedef struct BTMetaPageData
 	(int) (((size) - sizeof(BTPageOpaqueData)) /	\
 		   sizeof(ItemPointerData))
 #define ClusterMaxTIDsPerBTreePage \
-	CalcMaxTIDsPerBTreePage(BLCKSZ - SizeOfPageHeaderData)
+	CalcMaxTIDsPerBTreePage(PageUsableSpace)
 #define MaxTIDsPerBTreePageLimit \
-	CalcMaxTIDsPerBTreePage(BLCKSZ - SizeOfPageHeaderData)
+	CalcMaxTIDsPerBTreePage(PageUsableSpaceMax)
 
 /*
  * The leaf-page fillfactor defaults to 90% but is user-adjustable.
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index d0df02d39c..dcdeaaf910 100644
--- a/src/include/storage/bufpage.h
+++ b/src/include/storage/bufpage.h
@@ -213,6 +213,14 @@ typedef PageHeaderData *PageHeader;
  */
 #define SizeOfPageHeaderData (offsetof(PageHeaderData, pd_linp))
 
+/*
+ * how much space is left after smgr's bookkeeping, etc
+ */
+#define PageUsableSpace (BLCKSZ - SizeOfPageHeaderData)
+StaticAssertDecl(PageUsableSpace == MAXALIGN(PageUsableSpace),
+				 "SizeOfPageHeaderData must be MAXALIGN'd");
+#define PageUsableSpaceMax (BLCKSZ - SizeOfPageHeaderData)
+
 /*
  * PageIsEmpty
  *		returns true iff no itemid has been allocated on the page
diff --git a/src/include/storage/fsm_internals.h b/src/include/storage/fsm_internals.h
index a922e691fe..148693d977 100644
--- a/src/include/storage/fsm_internals.h
+++ b/src/include/storage/fsm_internals.h
@@ -48,7 +48,7 @@ typedef FSMPageData *FSMPage;
  * Number of non-leaf and leaf nodes, and nodes in total, on an FSM page.
  * These definitions are internal to fsmpage.c.
  */
-#define NodesPerPage (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - \
+#define NodesPerPage (PageUsableSpace - \
 					  offsetof(FSMPageData, fp_nodes))
 
 #define NonLeafNodesPerPage (BLCKSZ / 2 - 1)
-- 
2.40.1

