From d023080f4a015c85ad328ca8963de2ef15acef9d Mon Sep 17 00:00:00 2001
From: David Christensen <david.christensen@crunchydata.com>
Date: Fri, 5 Jan 2024 15:45:47 -0500
Subject: [PATCH v3 17/28] feature: ControlFile/GUC support for
 reserved_page_size

---
 src/backend/access/transam/xlog.c       | 25 ++++++++++++++++++++++++-
 src/backend/utils/misc/guc.c            |  1 +
 src/backend/utils/misc/guc_tables.c     | 13 +++++++++++++
 src/bin/pg_controldata/pg_controldata.c |  2 ++
 src/include/catalog/pg_control.h        |  1 +
 5 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 5be782db92..63b3ee79d4 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -67,6 +67,7 @@
 #include "catalog/catversion.h"
 #include "catalog/pg_control.h"
 #include "catalog/pg_database.h"
+#include "common/blocksize.h"
 #include "common/controldata_utils.h"
 #include "common/file_utils.h"
 #include "executor/instrument.h"
@@ -4078,6 +4079,7 @@ WriteControlFile(void)
 	ControlFile->relseg_size = RELSEG_SIZE;
 	ControlFile->xlog_blcksz = XLOG_BLCKSZ;
 	ControlFile->xlog_seg_size = wal_segment_size;
+	ControlFile->reserved_page_size = ReservedPageSize;
 
 	ControlFile->nameDataLen = NAMEDATALEN;
 	ControlFile->indexMaxKeys = INDEX_MAX_KEYS;
@@ -4147,8 +4149,9 @@ ReadControlFile(void)
 	pg_crc32c	crc;
 	int			fd;
 	static char wal_segsz_str[20];
+	static char reserved_page_size_str[20];
 	int			r;
-
+	int reserved_page_size;
 	/*
 	 * Read data...
 	 */
@@ -4214,6 +4217,26 @@ ReadControlFile(void)
 		ereport(FATAL,
 				(errmsg("incorrect checksum in control file")));
 
+	/*
+	 * Block size computations affect a number of things that are later
+	 * checked, so ensure that we calculate as soon as CRC has been validated
+	 * before checking other things that may depend on it.
+	 */
+
+	reserved_page_size = ControlFile->reserved_page_size;
+
+	if (!IsValidReservedPageSize(reserved_page_size))
+		ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						errmsg_plural("Reserved Page Size must be a multiple of 8 between 0 and 256, but the control file specifies %d byte",
+									  "Reserved Page Size must be a multiple of 8 between 0 and 256, but the control file specifies %d bytes",
+									  reserved_page_size,
+									  reserved_page_size)));
+
+	BlockSizeInit(ControlFile->blcksz, reserved_page_size);
+	snprintf(reserved_page_size_str, sizeof(reserved_page_size_str), "%d", reserved_page_size);
+	SetConfigOption("reserved_page_size", reserved_page_size_str, PGC_INTERNAL,
+					PGC_S_DYNAMIC_DEFAULT);
+
 	/*
 	 * Do compatibility checking immediately.  If the database isn't
 	 * compatible with the backend executable, we want to abort before we can
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 8f65ef3d89..0f07885ee5 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -33,6 +33,7 @@
 #include "catalog/objectaccess.h"
 #include "catalog/pg_authid.h"
 #include "catalog/pg_parameter_acl.h"
+#include "common/blocksize.h"
 #include "guc_internal.h"
 #include "libpq/pqformat.h"
 #include "parser/scansup.h"
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index e53ebc6dc2..6590dd9329 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -2766,6 +2766,19 @@ struct config_int ConfigureNamesInt[] =
 		NULL, assign_max_wal_size, NULL
 	},
 
+	{
+		{"reserved_page_size", PGC_INTERNAL, PRESET_OPTIONS,
+			gettext_noop("Shows the size of reserved space for extended pages."),
+			NULL,
+			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+			},
+		(int*)&ReservedPageSize,
+		0,
+		0,
+		MaxReservedPageSize,
+		NULL, NULL, NULL
+		},
+
 	{
 		{"checkpoint_timeout", PGC_SIGHUP, WAL_CHECKPOINTS,
 			gettext_noop("Sets the maximum time between automatic WAL checkpoints."),
diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c
index 93e0837947..9c6b6adae7 100644
--- a/src/bin/pg_controldata/pg_controldata.c
+++ b/src/bin/pg_controldata/pg_controldata.c
@@ -304,6 +304,8 @@ main(int argc, char *argv[])
 	/* we don't print floatFormat since can't say much useful about it */
 	printf(_("Database block size:                  %u\n"),
 		   ControlFile->blcksz);
+	printf(_("Reserved page size:                   %u\n"),
+		   ControlFile->reserved_page_size);
 	printf(_("Blocks per segment of large relation: %u\n"),
 		   ControlFile->relseg_size);
 	printf(_("WAL block size:                       %u\n"),
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index a00606ffcd..b4711bc4f6 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -227,6 +227,7 @@ typedef struct ControlFileData
 	 */
 	char		mock_authentication_nonce[MOCK_AUTH_NONCE_LEN];
 
+	uint32		reserved_page_size;	/* how much space per disk block is reserved */
 	/* CRC of all above ... MUST BE LAST! */
 	pg_crc32c	crc;
 } ControlFileData;
-- 
2.40.1

