From 92da58e2f4e05960ca005c69c1d11ec1f9edd965 Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@2ndquadrant.com>
Date: Sun, 31 Mar 2024 14:55:29 +0200
Subject: [PATCH v20240401 1/7] WIP: block alignment

Make sure the blocks in the incremental files are properly aligned
to 8KB boundaries, so that CoW works correctly.
---
 src/backend/backup/basebackup.c             | 16 ++++++++++++++++
 src/backend/backup/basebackup_incremental.c | 10 ++++++++--
 src/bin/pg_combinebackup/reconstruct.c      |  6 ++++++
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/src/backend/backup/basebackup.c b/src/backend/backup/basebackup.c
index 5fea86ad0fd..96e981a98f0 100644
--- a/src/backend/backup/basebackup.c
+++ b/src/backend/backup/basebackup.c
@@ -1635,6 +1635,19 @@ sendFile(bbsink *sink, const char *readfilename, const char *tarfilename,
 					 incremental_blocks,
 					 sizeof(BlockNumber) * num_incremental_blocks);
 
+		/* align header to a multiple of BLCKSZ */
+		if (header_bytes_done % BLCKSZ != 0)
+		{
+			char	padding[BLCKSZ];
+			size_t	paddinglen = (BLCKSZ - (header_bytes_done % BLCKSZ));
+
+			bytes_done += paddinglen;
+			memset(padding, 0, paddinglen);
+
+			push_to_sink(sink, &checksum_ctx, &header_bytes_done,
+						 padding, paddinglen);
+		}
+
 		/* Flush out any data still in the buffer so it's again empty. */
 		if (header_bytes_done > 0)
 		{
@@ -1748,6 +1761,9 @@ sendFile(bbsink *sink, const char *readfilename, const char *tarfilename,
 		blkno += cnt / BLCKSZ;
 		bytes_done += cnt;
 
+		if ((incremental_blocks != NULL) && (bytes_done % BLCKSZ != 0))
+			elog(FATAL, "incorrect file size '%s' bytes_done %lu", tarfilename, bytes_done);
+
 		/* Archive the data we just read. */
 		bbsink_archive_contents(sink, cnt);
 
diff --git a/src/backend/backup/basebackup_incremental.c b/src/backend/backup/basebackup_incremental.c
index 990b2872eaf..d425a3f555e 100644
--- a/src/backend/backup/basebackup_incremental.c
+++ b/src/backend/backup/basebackup_incremental.c
@@ -917,8 +917,14 @@ GetIncrementalFileSize(unsigned num_blocks_required)
 	 * Three four byte quantities (magic number, truncation block length,
 	 * block count) followed by block numbers followed by block contents.
 	 */
-	result = 3 * sizeof(uint32);
-	result += (BLCKSZ + sizeof(BlockNumber)) * num_blocks_required;
+	result = 3 * sizeof(uint32) + (sizeof(BlockNumber) * num_blocks_required);
+
+	if (result % BLCKSZ != 0)
+	{
+		result += BLCKSZ - (result % BLCKSZ);
+	}
+
+	result += BLCKSZ * num_blocks_required;
 
 	return result;
 }
diff --git a/src/bin/pg_combinebackup/reconstruct.c b/src/bin/pg_combinebackup/reconstruct.c
index 41f06bb26b5..e6cb9a206e2 100644
--- a/src/bin/pg_combinebackup/reconstruct.c
+++ b/src/bin/pg_combinebackup/reconstruct.c
@@ -472,6 +472,12 @@ make_incremental_rfile(char *filename)
 		sizeof(rf->truncation_block_length) +
 		sizeof(BlockNumber) * rf->num_blocks;
 
+	/* align header to multiple of BLCKSZ */
+	if (rf->header_length % BLCKSZ != 0)
+	{
+		rf->header_length += (BLCKSZ - (rf->header_length % BLCKSZ));
+	}
+
 	return rf;
 }
 
-- 
2.44.0

