From 49f840b4278450150848453a8c47383ec9ef9c21 Mon Sep 17 00:00:00 2001
From: Harrison Booth <harrisontbooth@gmail.com>
Date: Mon, 12 Oct 2026 21:14:18 -0500
Subject: [PATCH] Mark the Windows large-file regression fixture sparse

CF6204's remaining test module writes two eight-byte markers across a
four-gigabyte gap. An ordinary NTFS temporary file allocates the full
gap; it is not made sparse simply by writing past end of file.

Explicitly request sparse-file support for the test fixture before
writing. Retain the ordinary-file test on filesystems that report sparse
operations unsupported, and report other setup errors. Update the
README to distinguish logical size from filesystem-dependent allocation.

Native ARM64 and emulated x64 measurements show the ordinary fixture
allocates 4294971392 bytes and the sparse fixture 131072 bytes on the
tested NTFS volume, while preserving logical size and marker readback.

This supplements the CF6204 test proposal and does not remove the
segment-size guard or change PostgreSQL's production file I/O.
---
 src/test/modules/test_large_files/README      | 12 ++++---
 .../test_large_files/test_large_files.c       | 33 +++++++++++++++++++
 2 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/src/test/modules/test_large_files/README b/src/test/modules/test_large_files/README
index 467ec629fd6..03466d8c681 100644
--- a/src/test/modules/test_large_files/README
+++ b/src/test/modules/test_large_files/README
@@ -52,8 +52,10 @@ sizeof(pgoff_t) >= 8).
 Platform Support
 ----------------
 
-- Linux/Unix: Automatically creates sparse files (fast, no disk space used)
-- Windows NTFS: Creates sparse file efficiently
+- Linux/Unix: The unwritten gap is normally sparse; allocation depends on the filesystem.
+- Windows NTFS: Explicitly marks the test file sparse before writing.
+- Windows filesystems without sparse support: Retains the ordinary-file test,
+  which can allocate approximately 4GB. Other sparse-setup failures are errors.
 - 32-bit offset platforms: Test is skipped automatically
 
 Running the Test
@@ -70,5 +72,7 @@ or with meson:
 
   meson test test_large_files
 
-The test completes in seconds on most platforms. On Windows, the test
-may take longer as the OS allocates the sparse file structure.
+The logical file size exceeds 4GB even when allocation is sparse. On an
+NTFS test host, two eight-byte markers allocated 128KB with sparse setup,
+compared with approximately 4GB for an ordinary file. These allocation
+figures depend on the filesystem and are not requirements of the test.
diff --git a/src/test/modules/test_large_files/test_large_files.c b/src/test/modules/test_large_files/test_large_files.c
index 70e675d473a..c086bc70b1c 100644
--- a/src/test/modules/test_large_files/test_large_files.c
+++ b/src/test/modules/test_large_files/test_large_files.c
@@ -19,8 +19,37 @@
 #include "utils/builtins.h"
 #include "utils/wait_event.h"
 
+#ifdef WIN32
+#include <winioctl.h>
+#endif
+
 PG_MODULE_MAGIC;
 
+#ifdef WIN32
+/* Avoid allocating the entire four-gigabyte gap on filesystems that support it. */
+static void
+make_test_file_sparse(File file)
+{
+	HANDLE		handle = (HANDLE) _get_osfhandle(FileGetRawDesc(file));
+	DWORD		returned;
+	DWORD		error;
+
+	if (DeviceIoControl(handle, FSCTL_SET_SPARSE, NULL, 0, NULL, 0,
+						&returned, NULL))
+		return;
+
+	error = GetLastError();
+	/* Keep the original test available on filesystems without sparse files. */
+	if (error == ERROR_INVALID_FUNCTION || error == ERROR_NOT_SUPPORTED)
+		return;
+
+	FileClose(file);
+	ereport(ERROR,
+			(errmsg("could not mark large-file test file sparse: Windows error %lu",
+					error)));
+}
+#endif
+
 PG_FUNCTION_INFO_V1(test_large_files_offset_size);
 Datum
 test_large_files_offset_size(PG_FUNCTION_ARGS)
@@ -47,6 +76,10 @@ test_large_files_test_4gb_boundary(PG_FUNCTION_ARGS)
 				(errcode_for_file_access(),
 				 errmsg("could not create temporary file")));
 
+#ifdef WIN32
+	make_test_file_sparse(file);
+#endif
+
 	nbytes = FileWrite(file, write_buf_0, 8, 0, WAIT_EVENT_DATA_FILE_WRITE);
 	if (nbytes != 8)
 	{
-- 
2.53.0.windows.2

