@@ -125,12 +125,11 @@ static int max_safe_fds = 32; /* default if not changed */
125
125
/* these are the assigned bits in fdstate below: */
126
126
#define FD_TEMPORARY (1 << 0) /* T = delete when closed */
127
127
#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 */
128
130
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;
134
133
135
134
typedef struct vfd
136
135
{
@@ -953,7 +952,7 @@ OpenTemporaryFile(bool interXact)
953
952
VfdCache [file ].resowner = CurrentResourceOwner ;
954
953
955
954
/* ensure cleanup happens at eoxact */
956
- have_xact_temporary_files = true;
955
+ have_pending_fd_cleanup = true;
957
956
}
958
957
959
958
return file ;
@@ -1026,6 +1025,45 @@ OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError)
1026
1025
return file ;
1027
1026
}
1028
1027
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
+
1029
1067
/*
1030
1068
* close a file when done with it
1031
1069
*/
@@ -1778,8 +1816,9 @@ AtEOSubXact_Files(bool isCommit, SubTransactionId mySubid,
1778
1816
* particularly care which). All still-open per-transaction temporary file
1779
1817
* VFDs are closed, which also causes the underlying files to be deleted
1780
1818
* (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.
1783
1822
*/
1784
1823
void
1785
1824
AtEOXact_Files (void )
@@ -1802,7 +1841,10 @@ AtProcExit_Files(int code, Datum arg)
1802
1841
}
1803
1842
1804
1843
/*
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.
1806
1848
*
1807
1849
* isProcExit: if true, this is being called as the backend process is
1808
1850
* exiting. If that's the case, we should remove all temporary files; if
@@ -1819,35 +1861,49 @@ CleanupTempFiles(bool isProcExit)
1819
1861
* Careful here: at proc_exit we need extra cleanup, not just
1820
1862
* xact_temporary files.
1821
1863
*/
1822
- if (isProcExit || have_xact_temporary_files )
1864
+ if (isProcExit || have_pending_fd_cleanup )
1823
1865
{
1824
1866
Assert (FileIsNotOpen (0 )); /* Make sure ring not corrupted */
1825
1867
for (i = 1 ; i < SizeVfdCache ; i ++ )
1826
1868
{
1827
1869
unsigned short fdstate = VfdCache [i ].fdstate ;
1828
1870
1829
- if (( fdstate & FD_TEMPORARY ) && VfdCache [i ].fileName != NULL )
1871
+ if (VfdCache [i ].fileName != NULL )
1830
1872
{
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 )
1841
1893
{
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 ;
1846
1902
}
1847
1903
}
1848
1904
}
1849
1905
1850
- have_xact_temporary_files = false;
1906
+ have_pending_fd_cleanup = false;
1851
1907
}
1852
1908
1853
1909
/* Clean up "allocated" stdio files and dirs. */
0 commit comments