aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/file/fd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage/file/fd.c')
-rw-r--r--src/backend/storage/file/fd.c91
1 files changed, 65 insertions, 26 deletions
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index 387092724d2..820e6dbfd97 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -125,12 +125,11 @@ static int max_safe_fds = 32; /* default if not changed */
/* these are the assigned bits in fdstate below: */
#define FD_TEMPORARY (1 << 0) /* T = delete when closed */
#define FD_XACT_TEMPORARY (1 << 1) /* T = delete at eoXact */
+#define FD_XACT_TRANSIENT (1 << 2) /* T = close (not delete) at aoXact,
+ * but keep VFD */
-/*
- * Flag to tell whether it's worth scanning VfdCache looking for temp files to
- * close
- */
-static bool have_xact_temporary_files = false;
+/* Flag to tell whether there are files to close/delete at end of transaction */
+static bool have_pending_fd_cleanup = false;
typedef struct vfd
{
@@ -591,6 +590,7 @@ LruDelete(File file)
Vfd *vfdP;
Assert(file != 0);
+ Assert(!FileIsNotOpen(file));
DO_DB(elog(LOG, "LruDelete %d (%s)",
file, VfdCache[file].fileName));
@@ -953,7 +953,7 @@ OpenTemporaryFile(bool interXact)
VfdCache[file].resowner = CurrentResourceOwner;
/* ensure cleanup happens at eoxact */
- have_xact_temporary_files = true;
+ have_pending_fd_cleanup = true;
}
return file;
@@ -1027,6 +1027,25 @@ OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError)
}
/*
+ * Set the transient flag on a file
+ *
+ * This flag tells CleanupTempFiles to close the kernel-level file descriptor
+ * (but not the VFD itself) at end of transaction.
+ */
+void
+FileSetTransient(File file)
+{
+ Vfd *vfdP;
+
+ Assert(FileIsValid(file));
+
+ vfdP = &VfdCache[file];
+ vfdP->fdstate |= FD_XACT_TRANSIENT;
+
+ have_pending_fd_cleanup = true;
+}
+
+/*
* close a file when done with it
*/
void
@@ -1778,8 +1797,9 @@ AtEOSubXact_Files(bool isCommit, SubTransactionId mySubid,
* particularly care which). All still-open per-transaction temporary file
* VFDs are closed, which also causes the underlying files to be deleted
* (although they should've been closed already by the ResourceOwner
- * cleanup). Furthermore, all "allocated" stdio files are closed. We also
- * forget any transaction-local temp tablespace list.
+ * cleanup). Transient files have their kernel file descriptors closed.
+ * Furthermore, all "allocated" stdio files are closed. We also forget any
+ * transaction-local temp tablespace list.
*/
void
AtEOXact_Files(void)
@@ -1802,7 +1822,10 @@ AtProcExit_Files(int code, Datum arg)
}
/*
- * Close temporary files and delete their underlying files.
+ * General cleanup routine for fd.c.
+ *
+ * Temporary files are closed, and their underlying files deleted.
+ * Transient files are closed.
*
* isProcExit: if true, this is being called as the backend process is
* exiting. If that's the case, we should remove all temporary files; if
@@ -1819,35 +1842,51 @@ CleanupTempFiles(bool isProcExit)
* Careful here: at proc_exit we need extra cleanup, not just
* xact_temporary files.
*/
- if (isProcExit || have_xact_temporary_files)
+ if (isProcExit || have_pending_fd_cleanup)
{
Assert(FileIsNotOpen(0)); /* Make sure ring not corrupted */
for (i = 1; i < SizeVfdCache; i++)
{
unsigned short fdstate = VfdCache[i].fdstate;
- if ((fdstate & FD_TEMPORARY) && VfdCache[i].fileName != NULL)
+ if (VfdCache[i].fileName != NULL)
{
- /*
- * If we're in the process of exiting a backend process, close
- * all temporary files. Otherwise, only close temporary files
- * local to the current transaction. They should be closed by
- * the ResourceOwner mechanism already, so this is just a
- * debugging cross-check.
- */
- if (isProcExit)
- FileClose(i);
- else if (fdstate & FD_XACT_TEMPORARY)
+ if (fdstate & FD_TEMPORARY)
+ {
+ /*
+ * If we're in the process of exiting a backend process, close
+ * all temporary files. Otherwise, only close temporary files
+ * local to the current transaction. They should be closed by
+ * the ResourceOwner mechanism already, so this is just a
+ * debugging cross-check.
+ */
+ if (isProcExit)
+ FileClose(i);
+ else if (fdstate & FD_XACT_TEMPORARY)
+ {
+ elog(WARNING,
+ "temporary file %s not closed at end-of-transaction",
+ VfdCache[i].fileName);
+ FileClose(i);
+ }
+ }
+ else if (fdstate & FD_XACT_TRANSIENT)
{
- elog(WARNING,
- "temporary file %s not closed at end-of-transaction",
- VfdCache[i].fileName);
- FileClose(i);
+ /*
+ * Close the FD, and remove the entry from the LRU ring,
+ * but also remove the flag from the VFD. This is to
+ * ensure that if the VFD is reused in the future for
+ * non-transient access, we don't close it inappropriately
+ * then.
+ */
+ if (!FileIsNotOpen(i))
+ LruDelete(i);
+ VfdCache[i].fdstate &= ~FD_XACT_TRANSIENT;
}
}
}
- have_xact_temporary_files = false;
+ have_pending_fd_cleanup = false;
}
/* Clean up "allocated" stdio files and dirs. */