From c256a451f9ab64c787fb8e069ca7561f2c4da145 Mon Sep 17 00:00:00 2001
From: Vignesh <vignesh21@gmail.com>
Date: Fri, 21 Mar 2025 18:24:48 +0530
Subject: [PATCH v1] Fix issue with file handle retention during CREATE
 DATABASE in pg_restore

During upgrades, when pg_restore performs CREATE DATABASE, the
bgwriter or checkpointer may flush buffers and hold a file handle
for the table. This causes issues if the table needs to be re-created
later (e.g., after a TRUNCATE command), especially on OSes like older
versions of Windows, where unlinked files aren't fully removed until
they are no longer open.

This commit fixes the issue by checking for STATUS_DELETE_PENDING and
calling WaitForProcSignalBarrier, ensuring that all smgr file descriptors
are closed across all backends before retrying the file operation.
---
 src/backend/storage/smgr/md.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index f3220f98dc4..9a795a661de 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -34,6 +34,7 @@
 #include "storage/bufmgr.h"
 #include "storage/fd.h"
 #include "storage/md.h"
+#include "storage/procsignal.h"
 #include "storage/relfilelocator.h"
 #include "storage/smgr.h"
 #include "storage/sync.h"
@@ -204,6 +205,9 @@ mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
 	MdfdVec    *mdfd;
 	RelPathStr	path;
 	File		fd;
+#if defined(WIN32) && !defined(__CYGWIN__)
+	bool		retryattempted = false;
+#endif
 
 	if (isRedo && reln->md_num_open_segs[forknum] > 0)
 		return;					/* created and opened already... */
@@ -225,6 +229,9 @@ mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
 
 	path = relpath(reln->smgr_rlocator, forknum);
 
+#if defined(WIN32) && !defined(__CYGWIN__)
+retry:
+#endif
 	fd = PathNameOpenFile(path.str, _mdfd_open_flags() | O_CREAT | O_EXCL);
 
 	if (fd < 0)
@@ -235,6 +242,15 @@ mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
 			fd = PathNameOpenFile(path.str, _mdfd_open_flags());
 		if (fd < 0)
 		{
+#if defined(WIN32) && !defined(__CYGWIN__)
+			if (!retryattempted && pg_RtlGetLastNtStatus() == STATUS_DELETE_PENDING)
+			{
+				retryattempted = true;
+				WaitForProcSignalBarrier(EmitProcSignalBarrier(PROCSIGNAL_BARRIER_SMGRRELEASE));
+				goto retry;
+			}
+#endif
+
 			/* be sure to report the error reported by create, not open */
 			errno = save_errno;
 			ereport(ERROR,
-- 
2.43.0

