smgr-transient-files.patch
application/octet-stream
Filename: smgr-transient-files.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 | 53 | 0 |
| src/backend/storage/smgr/md.c | 9 | 0 |
| src/backend/storage/smgr/smgr.c | 14 | 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,140 ----
/* 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 */
/*
! * Global status flags
*/
+ /* are there FD_XACT_TEMPORARY files? */
static bool have_xact_temporary_files = false;
+ /* are there FD_XACT_TRANSIENT files? */
+ static bool have_xact_transient_files = false;
typedef struct vfd
{
***************
*** 1027,1032 **** OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError)
--- 1031,1075 ----
}
/*
+ * 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_xact_transient_files = 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
***************
*** 1819,1833 **** 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
--- 1862,1878 ----
* Careful here: at proc_exit we need extra cleanup, not just
* xact_temporary files.
*/
! if (isProcExit || have_xact_temporary_files || have_xact_transient_files)
{
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
***************
*** 1844,1853 **** CleanupTempFiles(bool isProcExit)
--- 1889,1902 ----
VfdCache[i].fileName);
FileClose(i);
}
+ }
+ else if (fdstate & FD_XACT_TRANSIENT)
+ FileKernelClose(i);
}
}
have_xact_temporary_files = false;
+ have_xact_transient_files = 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,170 **** smgropen(RelFileNode rnode, BackendId backend)
--- 165,171 ----
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 */
***************
*** 176,181 **** smgropen(RelFileNode rnode, BackendId backend)
--- 177,195 ----
}
/*
+ * 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);