smgr-transient-files-2.patch
application/octet-stream
Filename: smgr-transient-files-2.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| src/backend/storage/buffer/bufmgr.c | 8 | 0 |
| src/backend/storage/file/fd.c | 82 | 0 |
| src/backend/storage/smgr/md.c | 9 | 0 |
| src/backend/storage/smgr/smgr.c | 17 | 0 |
| src/include/storage/fd.h | 1 | 0 |
| src/include/storage/smgr.h | 2 | 0 |
*** a/src/backend/storage/buffer/bufmgr.c
--- b/src/backend/storage/buffer/bufmgr.c
***************
*** 1834,1840 **** BufferGetTag(Buffer buffer, RelFileNode *rnode, ForkNumber *forknum,
* written.)
*
* If the caller has an smgr reference for the buffer's relation, pass it
! * as the second parameter. If not, pass NULL.
*/
static void
FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
--- 1834,1843 ----
* written.)
*
* If the caller has an smgr reference for the buffer's relation, pass it
! * as the second parameter. If not, pass NULL. In the latter case, the
! * relation will be marked as "transient" so that the corresponding
! * kernel-level file descriptors are closed when the current transaction ends,
! * if any.
*/
static void
FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
***************
*** 1856,1864 **** FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
errcontext.previous = error_context_stack;
error_context_stack = &errcontext;
! /* Find smgr relation for buffer */
if (reln == NULL)
reln = smgropen(buf->tag.rnode, InvalidBackendId);
TRACE_POSTGRESQL_BUFFER_FLUSH_START(buf->tag.forkNum,
buf->tag.blockNum,
--- 1859,1870 ----
errcontext.previous = error_context_stack;
error_context_stack = &errcontext;
! /* Find smgr relation for buffer, and mark it as transient */
if (reln == NULL)
+ {
reln = smgropen(buf->tag.rnode, InvalidBackendId);
+ smgrsettransient(reln);
+ }
TRACE_POSTGRESQL_BUFFER_FLUSH_START(buf->tag.forkNum,
buf->tag.blockNum,
*** a/src/backend/storage/file/fd.c
--- b/src/backend/storage/file/fd.c
***************
*** 125,136 **** 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 */
! /*
! * Flag to tell whether it's worth scanning VfdCache looking for temp files to
! * close
! */
! static bool have_xact_temporary_files = false;
typedef struct vfd
{
--- 125,135 ----
/* 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 there are files to close/delete at end of transaction */
! static bool have_pending_fd_cleanup = false;
typedef struct vfd
{
***************
*** 953,959 **** OpenTemporaryFile(bool interXact)
VfdCache[file].resowner = CurrentResourceOwner;
/* ensure cleanup happens at eoxact */
! have_xact_temporary_files = true;
}
return file;
--- 952,958 ----
VfdCache[file].resowner = CurrentResourceOwner;
/* ensure cleanup happens at eoxact */
! have_pending_fd_cleanup = true;
}
return file;
***************
*** 1027,1032 **** OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError)
--- 1026,1070 ----
}
/*
+ * 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,1785 **** 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.
*/
void
AtEOXact_Files(void)
--- 1816,1824 ----
* 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). 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,1808 **** AtProcExit_Files(int code, Datum arg)
}
/*
! * Close temporary files and delete their underlying files.
*
* 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
--- 1841,1850 ----
}
/*
! * 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,1853 **** CleanupTempFiles(bool isProcExit)
* Careful here: at proc_exit we need extra cleanup, not just
* xact_temporary files.
*/
! if (isProcExit || have_xact_temporary_files)
{
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 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);
}
}
}
! have_xact_temporary_files = false;
}
/* Clean up "allocated" stdio files and dirs. */
--- 1861,1909 ----
* Careful here: at proc_exit we need extra cleanup, not just
* 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 (VfdCache[i].fileName != NULL)
{
! 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)
{
! /*
! * 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_pending_fd_cleanup = false;
}
/* Clean up "allocated" stdio files and dirs. */
*** a/src/backend/storage/smgr/md.c
--- b/src/backend/storage/smgr/md.c
***************
*** 288,293 **** mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
--- 288,296 ----
pfree(path);
+ if (reln->smgr_transient)
+ FileSetTransient(fd);
+
reln->md_fd[forkNum] = _fdvec_alloc();
reln->md_fd[forkNum]->mdfd_vfd = fd;
***************
*** 542,547 **** mdopen(SMgrRelation reln, ForkNumber forknum, ExtensionBehavior behavior)
--- 545,553 ----
pfree(path);
+ if (reln->smgr_transient)
+ FileSetTransient(fd);
+
reln->md_fd[forknum] = mdfd = _fdvec_alloc();
mdfd->mdfd_vfd = fd;
***************
*** 1556,1561 **** _mdfd_openseg(SMgrRelation reln, ForkNumber forknum, BlockNumber segno,
--- 1562,1570 ----
if (fd < 0)
return NULL;
+ if (reln->smgr_transient)
+ FileSetTransient(fd);
+
/* allocate an mdfdvec entry for it */
v = _fdvec_alloc();
*** a/src/backend/storage/smgr/smgr.c
--- b/src/backend/storage/smgr/smgr.c
***************
*** 165,181 **** smgropen(RelFileNode rnode, BackendId backend)
--- 165,198 ----
reln->smgr_targblock = InvalidBlockNumber;
reln->smgr_fsm_nblocks = InvalidBlockNumber;
reln->smgr_vm_nblocks = InvalidBlockNumber;
+ reln->smgr_transient = false;
reln->smgr_which = 0; /* we only have md.c at present */
/* mark it not open */
for (forknum = 0; forknum <= MAX_FORKNUM; forknum++)
reln->md_fd[forknum] = NULL;
}
+ else
+ /* if it was transient before, it no longer is */
+ reln->smgr_transient = false;
return reln;
}
/*
+ * smgrsettransient() -- mark an SMgrRelation object as transaction-bound
+ *
+ * The main effect of this is that all opened files are marked to be
+ * kernel-level closed (but not necessarily VFD-closed) when the current
+ * transaction ends.
+ */
+ void
+ smgrsettransient(SMgrRelation reln)
+ {
+ reln->smgr_transient = true;
+ }
+
+ /*
* smgrsetowner() -- Establish a long-lived reference to an SMgrRelation object
*
* There can be only one owner at a time; this is sufficient since currently
*** a/src/include/storage/fd.h
--- b/src/include/storage/fd.h
***************
*** 61,66 **** extern int max_files_per_process;
--- 61,67 ----
/* Operations on virtual Files --- equivalent to Unix kernel file ops */
extern File PathNameOpenFile(FileName fileName, int fileFlags, int fileMode);
extern File OpenTemporaryFile(bool interXact);
+ extern void FileSetTransient(File file);
extern void FileClose(File file);
extern int FilePrefetch(File file, off_t offset, int amount);
extern int FileRead(File file, char *buffer, int amount);
*** a/src/include/storage/smgr.h
--- b/src/include/storage/smgr.h
***************
*** 62,67 **** typedef struct SMgrRelationData
--- 62,68 ----
* submodules. Do not touch them from elsewhere.
*/
int smgr_which; /* storage manager selector */
+ bool smgr_transient; /* T if files are to be closed at EOXact */
/* for md.c; NULL for forks that are not open */
struct _MdfdVec *md_fd[MAX_FORKNUM + 1];
***************
*** 74,79 **** typedef SMgrRelationData *SMgrRelation;
--- 75,81 ----
extern void smgrinit(void);
extern SMgrRelation smgropen(RelFileNode rnode, BackendId backend);
+ extern void smgrsettransient(SMgrRelation reln);
extern bool smgrexists(SMgrRelation reln, ForkNumber forknum);
extern void smgrsetowner(SMgrRelation *owner, SMgrRelation reln);
extern void smgrclose(SMgrRelation reln);