diff options
Diffstat (limited to 'src/backend/storage/file/fd.c')
-rw-r--r-- | src/backend/storage/file/fd.c | 108 |
1 files changed, 82 insertions, 26 deletions
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index 11bab38280e..0db3d38c678 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 { @@ -953,7 +952,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 +1026,45 @@ 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 at the kernel level, but keep the VFD open + */ +static void +FileKernelClose(File file) +{ + Vfd *vfdP; + + Assert(FileIsValid(file)); + + vfdP = &VfdCache[file]; + + if (!FileIsNotOpen(file)) + { + if (close(vfdP->fd)) + elog(ERROR, "could not close file \"%s\": %m", vfdP->fileName); + vfdP->fd = VFD_CLOSED; + } +} + +/* * close a file when done with it */ void @@ -1778,8 +1816,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 +1841,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 +1861,49 @@ 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 kernel file descriptor, 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. + */ + FileKernelClose(i); + VfdCache[i].fdstate &= ~FD_XACT_TRANSIENT; } } } - have_xact_temporary_files = false; + have_pending_fd_cleanup = false; } /* Clean up "allocated" stdio files and dirs. */ |