@@ -125,12 +125,11 @@ static intmax_safe_fds = 32;/* default if not changed */
125125/* these are the assigned bits in fdstate below: */
126126#define FD_TEMPORARY (1 << 0)/* T = delete when closed */
127127#define FD_XACT_TEMPORARY (1 << 1)/* T = delete at eoXact */
128+ #define FD_XACT_TRANSIENT (1 << 2)/* T = close (not delete) at aoXact,
129+ * but keep VFD */
128130
129- /*
130- * Flag to tell whether it's worth scanning VfdCache looking for temp files to
131- * close
132- */
133- static bool have_xact_temporary_files = false;
131+ /* Flag to tell whether there are files to close/delete at end of transaction */
132+ static bool have_pending_fd_cleanup = false;
134133
135134typedef struct vfd
136135{
@@ -953,7 +952,7 @@ OpenTemporaryFile(bool interXact)
953952VfdCache [file ].resowner = CurrentResourceOwner ;
954953
955954/* ensure cleanup happens at eoxact */
956- have_xact_temporary_files = true;
955+ have_pending_fd_cleanup = true;
957956}
958957
959958return file ;
@@ -1026,6 +1025,45 @@ OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError)
10261025return file ;
10271026}
10281027
1028+ /*
1029+ * Set the transient flag on a file
1030+ *
1031+ * This flag tells CleanupTempFiles to close the kernel-level file descriptor
1032+ * (but not the VFD itself) at end of transaction.
1033+ */
1034+ void
1035+ FileSetTransient (File file )
1036+ {
1037+ Vfd * vfdP ;
1038+
1039+ Assert (FileIsValid (file ));
1040+
1041+ vfdP = & VfdCache [file ];
1042+ vfdP -> fdstate |=FD_XACT_TRANSIENT ;
1043+
1044+ have_pending_fd_cleanup = true;
1045+ }
1046+
1047+ /*
1048+ * Close a file at the kernel level, but keep the VFD open
1049+ */
1050+ static void
1051+ FileKernelClose (File file )
1052+ {
1053+ Vfd * vfdP ;
1054+
1055+ Assert (FileIsValid (file ));
1056+
1057+ vfdP = & VfdCache [file ];
1058+
1059+ if (!FileIsNotOpen (file ))
1060+ {
1061+ if (close (vfdP -> fd ))
1062+ elog (ERROR ,"could not close file \"%s\": %m" ,vfdP -> fileName );
1063+ vfdP -> fd = VFD_CLOSED ;
1064+ }
1065+ }
1066+
10291067/*
10301068 * close a file when done with it
10311069 */
@@ -1778,8 +1816,9 @@ AtEOSubXact_Files(bool isCommit, SubTransactionId mySubid,
17781816 * particularly care which). All still-open per-transaction temporary file
17791817 * VFDs are closed, which also causes the underlying files to be deleted
17801818 * (although they should've been closed already by the ResourceOwner
1781- * cleanup). Furthermore, all "allocated" stdio files are closed. We also
1782- * forget any transaction-local temp tablespace list.
1819+ * cleanup). Transient files have their kernel file descriptors closed.
1820+ * Furthermore, all "allocated" stdio files are closed. We also forget any
1821+ * transaction-local temp tablespace list.
17831822 */
17841823void
17851824AtEOXact_Files (void )
@@ -1802,7 +1841,10 @@ AtProcExit_Files(int code, Datum arg)
18021841}
18031842
18041843/*
1805- * Close temporary files and delete their underlying files.
1844+ * General cleanup routine for fd.c.
1845+ *
1846+ * Temporary files are closed, and their underlying files deleted.
1847+ * Transient files are closed.
18061848 *
18071849 * isProcExit: if true, this is being called as the backend process is
18081850 * exiting. If that's the case, we should remove all temporary files; if
@@ -1819,35 +1861,49 @@ CleanupTempFiles(bool isProcExit)
18191861 * Careful here: at proc_exit we need extra cleanup, not just
18201862 * xact_temporary files.
18211863 */
1822- if (isProcExit || have_xact_temporary_files )
1864+ if (isProcExit || have_pending_fd_cleanup )
18231865{
18241866Assert (FileIsNotOpen (0 ));/* Make sure ring not corrupted */
18251867for (i = 1 ;i < SizeVfdCache ;i ++ )
18261868{
18271869unsigned short fdstate = VfdCache [i ].fdstate ;
18281870
1829- if (( fdstate & FD_TEMPORARY ) && VfdCache [i ].fileName != NULL )
1871+ if (VfdCache [i ].fileName != NULL )
18301872{
1831- /*
1832- * If we're in the process of exiting a backend process, close
1833- * all temporary files. Otherwise, only close temporary files
1834- * local to the current transaction. They should be closed by
1835- * the ResourceOwner mechanism already, so this is just a
1836- * debugging cross-check.
1837- */
1838- if (isProcExit )
1839- FileClose (i );
1840- else if (fdstate & FD_XACT_TEMPORARY )
1873+ if (fdstate & FD_TEMPORARY )
1874+ {
1875+ /*
1876+ * If we're in the process of exiting a backend process, close
1877+ * all temporary files. Otherwise, only close temporary files
1878+ * local to the current transaction. They should be closed by
1879+ * the ResourceOwner mechanism already, so this is just a
1880+ * debugging cross-check.
1881+ */
1882+ if (isProcExit )
1883+ FileClose (i );
1884+ else if (fdstate & FD_XACT_TEMPORARY )
1885+ {
1886+ elog (WARNING ,
1887+ "temporary file %s not closed at end-of-transaction" ,
1888+ VfdCache [i ].fileName );
1889+ FileClose (i );
1890+ }
1891+ }
1892+ else if (fdstate & FD_XACT_TRANSIENT )
18411893{
1842- elog (WARNING ,
1843- "temporary file %s not closed at end-of-transaction" ,
1844- VfdCache [i ].fileName );
1845- FileClose (i );
1894+ /*
1895+ * Close the kernel file descriptor, but also remove the
1896+ * flag from the VFD. This is to ensure that if the VFD is
1897+ * reused in the future for non-transient access, we don't
1898+ * close it inappropriately then.
1899+ */
1900+ FileKernelClose (i );
1901+ VfdCache [i ].fdstate &= ~FD_XACT_TRANSIENT ;
18461902}
18471903}
18481904}
18491905
1850- have_xact_temporary_files = false;
1906+ have_pending_fd_cleanup = false;
18511907}
18521908
18531909/* Clean up "allocated" stdio files and dirs. */