1 /*-------------------------------------------------------------------------
4 * Virtual file descriptor code.
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.64 2000/10/02 19:42:47 petere Exp $
14 * This code manages a cache of 'virtual' file descriptors (VFDs).
15 * The server opens many file descriptors for a variety of reasons,
16 * including base tables, scratch files (e.g., sort and hash spool
17 * files), and random calls to C library routines like system(3); it
18 * is quite easy to exceed system limits on the number of open files a
19 * single process can have. (This is around 256 on many modern
20 * operating systems, but can be as low as 32 on others.)
22 * VFDs are managed as an LRU pool, with actual OS file descriptors
23 * being opened and closed as needed. Obviously, if a routine is
24 * opened using these interfaces, all subsequent operations must also
25 * be through these interfaces (the File type is not a real file
28 * For this scheme to work, most (if not all) routines throughout the
29 * server should use these interfaces instead of calling the C library
30 * routines (e.g., open(2) and fopen(3)) themselves. Otherwise, we
31 * may find ourselves short of real file descriptors anyway.
33 * This file used to contain a bunch of stuff to support RAID levels 0
34 * (jbod), 1 (duplex) and 5 (xor parity). That stuff is all gone
35 * because the parallel query processing code that called it is all
36 * gone. If you really need it you could get it from the original
38 *-------------------------------------------------------------------------
43 #include <sys/types.h>
45 #include <sys/param.h>
51 #include "miscadmin.h"
52 #include "storage/fd.h"
55 * Problem: Postgres does a system(ld...) to do dynamic loading.
56 * This will open several extra files in addition to those used by
57 * Postgres. We need to guarantee that there are file descriptors free
60 * The current solution is to limit the number of file descriptors
61 * that this code will allocate at one time: it leaves RESERVE_FOR_LD free.
63 * (Even though most dynamic loaders now use dlopen(3) or the
64 * equivalent, the OS must still open several files to perform the
65 * dynamic loading. Keep this here.)
67 #ifndef RESERVE_FOR_LD
68 #define RESERVE_FOR_LD 10
72 * We need to ensure that we have at least some file descriptors
73 * available to postgreSQL after we've reserved the ones for LD,
74 * so we set that value here.
76 * I think 10 is an appropriate value so that's what it'll be
88 #define DO_DB(A) /* A */
91 #define VFD_CLOSED (-1)
93 #define FileIsValid(file) \
94 ((file) > 0 && (file) < (int) SizeVfdCache && VfdCache[file].fileName != NULL)
96 #define FileIsNotOpen(file) (VfdCache[file].fd == VFD_CLOSED)
98 #define FileUnknownPos (-1)
102 signed short fd; /* current FD, or VFD_CLOSED if none */
103 unsigned short fdstate; /* bitflags for VFD's state */
105 /* these are the assigned bits in fdstate: */
106 #define FD_DIRTY (1 << 0)/* written to, but not yet fsync'd */
107 #define FD_TEMPORARY (1 << 1)/* should be unlinked when closed */
109 File nextFree; /* link to next free VFD, if in freelist */
110 File lruMoreRecently;/* doubly linked recency-of-use list */
111 File lruLessRecently;
112 long seekPos; /* current logical file position */
113 char *fileName; /* name of file, or NULL for unused VFD */
114 /* NB: fileName is malloc'd, and must be free'd when closing the VFD */
115 int fileFlags; /* open(2) flags for opening the file */
116 int fileMode; /* mode to pass to open(2) */
120 * Virtual File Descriptor array pointer and size. This grows as
121 * needed. 'File' values are indexes into this array.
122 * Note that VfdCache[0] is not a usable VFD, just a list header.
124 static Vfd *VfdCache;
125 static Size SizeVfdCache = 0;
128 * Number of file descriptors known to be in use by VFD entries.
130 static int nfile = 0;
133 * List of stdio FILEs opened with AllocateFile.
135 * Since we don't want to encourage heavy use of AllocateFile, it seems
136 * OK to put a pretty small maximum limit on the number of simultaneously
139 #define MAX_ALLOCATED_FILES 32
141 static int numAllocatedFiles = 0;
142 static FILE *allocatedFiles[MAX_ALLOCATED_FILES];
145 * Number of temporary files opened during the current transaction;
146 * this is used in generation of tempfile names.
148 static long tempFileCounter = 0;
151 /*--------------------
155 * Delete - delete a file from the Lru ring
156 * LruDelete - remove a file from the Lru ring and close its FD
157 * Insert - put a file at the front of the Lru ring
158 * LruInsert - put a file at the front of the Lru ring and open it
159 * ReleaseLruFile - Release an fd by closing the last entry in the Lru ring
160 * AllocateVfd - grab a free (or new) file record (from VfdArray)
161 * FreeVfd - free a file record
163 * The Least Recently Used ring is a doubly linked list that begins and
164 * ends on element zero. Element zero is special -- it doesn't represent
165 * a file and its "fd" field always == VFD_CLOSED. Element zero is just an
166 * anchor that shows us the beginning/end of the ring.
167 * Only VFD elements that are currently really open (have an FD assigned) are
168 * in the Lru ring. Elements that are "virtually" open can be recognized
169 * by having a non-null fileName field.
173 * /--less----\ /---------\
175 * #0 --more---> LeastRecentlyUsed --more-\ \
177 * \\less--> MostRecentlyUsedFile <---/ |
178 * \more---/ \--less--/
180 *--------------------
182 static void Delete(File file);
183 static void LruDelete(File file);
184 static void Insert(File file);
185 static int LruInsert(File file);
186 static bool ReleaseLruFile(void);
187 static File AllocateVfd(void);
188 static void FreeVfd(File file);
190 static int FileAccess(File file);
191 static File fileNameOpenFile(FileName fileName, int fileFlags, int fileMode);
192 static char *filepath(char *filename);
193 static long pg_nofile(void);
196 * pg_fsync --- same as fsync except does nothing if -F switch was given
208 * BasicOpenFile --- same as open(2) except can free other FDs if needed
210 * This is exported for use by places that really want a plain kernel FD,
211 * but need to be proof against running out of FDs. Once an FD has been
212 * successfully returned, it is the caller's responsibility to ensure that
213 * it will not be leaked on elog()! Most users should *not* call this
214 * routine directly, but instead use the VFD abstraction level, which
215 * provides protection against descriptor leaks as well as management of
216 * files that need to be open for more than a short period of time.
218 * Ideally this should be the *only* direct call of open() in the backend.
219 * In practice, the postmaster calls open() directly, and there are some
220 * direct open() calls done early in backend startup. Those are OK since
221 * this module wouldn't have any open files to close at that point anyway.
224 BasicOpenFile(FileName fileName, int fileFlags, int fileMode)
229 fd = open(fileName, fileFlags, fileMode);
232 return fd; /* success! */
234 if (errno == EMFILE || errno == ENFILE)
236 int save_errno = errno;
238 DO_DB(elog(DEBUG, "BasicOpenFile: not enough descs, retry, er= %d",
241 if (ReleaseLruFile())
246 return -1; /* failure */
250 * pg_nofile: determine number of filedescriptors that fd.c is allowed to use
255 static long no_files = 0;
259 /* need do this calculation only once */
261 no_files = (long) NOFILE;
263 no_files = sysconf(_SC_OPEN_MAX);
266 elog(DEBUG, "pg_nofile: Unable to get _SC_OPEN_MAX using sysconf(); using %d", NOFILE);
267 no_files = (long) NOFILE;
271 if ((no_files - RESERVE_FOR_LD) < FD_MINFREE)
272 elog(FATAL, "pg_nofile: insufficient File Descriptors in postmaster to start backend (%ld).\n"
273 " O/S allows %ld, Postmaster reserves %d, We need %d (MIN) after that.",
274 no_files - RESERVE_FOR_LD, no_files, RESERVE_FOR_LD, FD_MINFREE);
276 no_files -= RESERVE_FOR_LD;
287 int mru = VfdCache[0].lruLessRecently;
288 Vfd *vfdP = &VfdCache[mru];
291 sprintf(buf, "LRU: MOST %d ", mru);
294 mru = vfdP->lruLessRecently;
295 vfdP = &VfdCache[mru];
296 sprintf(buf + strlen(buf), "%d ", mru);
298 sprintf(buf + strlen(buf), "LEAST");
311 DO_DB(elog(DEBUG, "Delete %d (%s)",
312 file, VfdCache[file].fileName));
315 vfdP = &VfdCache[file];
317 VfdCache[vfdP->lruLessRecently].lruMoreRecently = vfdP->lruMoreRecently;
318 VfdCache[vfdP->lruMoreRecently].lruLessRecently = vfdP->lruLessRecently;
331 DO_DB(elog(DEBUG, "LruDelete %d (%s)",
332 file, VfdCache[file].fileName));
334 vfdP = &VfdCache[file];
336 /* delete the vfd record from the LRU ring */
339 /* save the seek position */
340 vfdP->seekPos = (long) lseek(vfdP->fd, 0L, SEEK_CUR);
341 Assert(vfdP->seekPos != -1);
343 /* if we have written to the file, sync it before closing */
344 if (vfdP->fdstate & FD_DIRTY)
346 returnValue = pg_fsync(vfdP->fd);
347 Assert(returnValue != -1);
348 vfdP->fdstate &= ~FD_DIRTY;
352 returnValue = close(vfdP->fd);
353 Assert(returnValue != -1);
356 vfdP->fd = VFD_CLOSED;
366 DO_DB(elog(DEBUG, "Insert %d (%s)",
367 file, VfdCache[file].fileName));
370 vfdP = &VfdCache[file];
372 vfdP->lruMoreRecently = 0;
373 vfdP->lruLessRecently = VfdCache[0].lruLessRecently;
374 VfdCache[0].lruLessRecently = file;
375 VfdCache[vfdP->lruLessRecently].lruMoreRecently = file;
388 DO_DB(elog(DEBUG, "LruInsert %d (%s)",
389 file, VfdCache[file].fileName));
391 vfdP = &VfdCache[file];
393 if (FileIsNotOpen(file))
395 while (nfile + numAllocatedFiles >= pg_nofile())
397 if (! ReleaseLruFile())
402 * The open could still fail for lack of file descriptors, eg due
403 * to overall system file table being full. So, be prepared to
404 * release another FD if necessary...
406 vfdP->fd = BasicOpenFile(vfdP->fileName, vfdP->fileFlags,
410 DO_DB(elog(DEBUG, "RE_OPEN FAILED: %d", errno));
415 DO_DB(elog(DEBUG, "RE_OPEN SUCCESS"));
419 /* seek to the right position */
420 if (vfdP->seekPos != 0L)
422 returnValue = lseek(vfdP->fd, vfdP->seekPos, SEEK_SET);
423 Assert(returnValue != -1);
428 * put it at the head of the Lru ring
439 DO_DB(elog(DEBUG, "ReleaseLruFile. Opened %d", nfile));
444 * There are opened files and so there should be at least one used
447 Assert(VfdCache[0].lruMoreRecently != 0);
448 LruDelete(VfdCache[0].lruMoreRecently);
449 return true; /* freed a file */
451 return false; /* no files available to free */
460 DO_DB(elog(DEBUG, "AllocateVfd. Size %d", SizeVfdCache));
462 if (SizeVfdCache == 0)
464 /* initialize header entry first time through */
465 VfdCache = (Vfd *) malloc(sizeof(Vfd));
466 Assert(VfdCache != NULL);
467 MemSet((char *) &(VfdCache[0]), 0, sizeof(Vfd));
468 VfdCache->fd = VFD_CLOSED;
473 * register proc-exit call to ensure temp files are dropped at
476 on_proc_exit(AtEOXact_Files, 0);
479 if (VfdCache[0].nextFree == 0)
483 * The free list is empty so it is time to increase the size of
484 * the array. We choose to double it each time this happens.
485 * However, there's not much point in starting *real* small.
487 Size newCacheSize = SizeVfdCache * 2;
489 if (newCacheSize < 32)
492 VfdCache = (Vfd *) realloc(VfdCache, sizeof(Vfd) * newCacheSize);
493 Assert(VfdCache != NULL);
496 * Initialize the new entries and link them into the free list.
499 for (i = SizeVfdCache; i < newCacheSize; i++)
501 MemSet((char *) &(VfdCache[i]), 0, sizeof(Vfd));
502 VfdCache[i].nextFree = i + 1;
503 VfdCache[i].fd = VFD_CLOSED;
505 VfdCache[newCacheSize - 1].nextFree = 0;
506 VfdCache[0].nextFree = SizeVfdCache;
509 * Record the new size
512 SizeVfdCache = newCacheSize;
515 file = VfdCache[0].nextFree;
517 VfdCache[0].nextFree = VfdCache[file].nextFree;
525 Vfd *vfdP = &VfdCache[file];
527 DO_DB(elog(DEBUG, "FreeVfd: %d (%s)",
528 file, vfdP->fileName ? vfdP->fileName : ""));
530 if (vfdP->fileName != NULL)
532 free(vfdP->fileName);
533 vfdP->fileName = NULL;
536 vfdP->nextFree = VfdCache[0].nextFree;
537 VfdCache[0].nextFree = file;
541 * Convert given pathname to absolute.
543 * (Generally, this isn't actually necessary, considering that we
544 * should be cd'd into the database directory. Presently it is only
545 * necessary to do it in "bootstrap" mode. Maybe we should change
546 * bootstrap mode to do the cd, and save a few cycles/bytes here.)
549 filepath(char *filename)
554 /* Not an absolute path name? Then fill in with database path... */
555 if (*filename != SEP_CHAR)
557 len = strlen(DatabasePath) + strlen(filename) + 2;
558 buf = (char *) palloc(len);
559 sprintf(buf, "%s%c%s", DatabasePath, SEP_CHAR, filename);
563 buf = (char *) palloc(strlen(filename) + 1);
564 strcpy(buf, filename);
568 printf("filepath: path is %s\n", buf);
575 FileAccess(File file)
579 DO_DB(elog(DEBUG, "FileAccess %d (%s)",
580 file, VfdCache[file].fileName));
583 * Is the file open? If not, open it and put it at the head of the
584 * LRU ring (possibly closing the least recently used file to get an
588 if (FileIsNotOpen(file))
590 returnValue = LruInsert(file);
591 if (returnValue != 0)
594 else if (VfdCache[0].lruLessRecently != file)
598 * We now know that the file is open and that it is not the last
599 * one accessed, so we need to move it to the head of the Lru
611 * Called when we get a shared invalidation message on some relation.
615 FileInvalidate(File file)
617 Assert(FileIsValid(file));
618 if (!FileIsNotOpen(file))
625 fileNameOpenFile(FileName fileName,
632 if (fileName == NULL)
633 elog(ERROR, "fileNameOpenFile: NULL fname");
635 DO_DB(elog(DEBUG, "fileNameOpenFile: %s %x %o",
636 fileName, fileFlags, fileMode));
638 file = AllocateVfd();
639 vfdP = &VfdCache[file];
641 while (nfile + numAllocatedFiles >= pg_nofile())
643 if (! ReleaseLruFile())
647 vfdP->fd = BasicOpenFile(fileName, fileFlags, fileMode);
655 DO_DB(elog(DEBUG, "fileNameOpenFile: success %d",
660 vfdP->fileName = malloc(strlen(fileName) + 1);
661 strcpy(vfdP->fileName, fileName);
663 vfdP->fileFlags = fileFlags & ~(O_TRUNC | O_EXCL);
664 vfdP->fileMode = fileMode;
672 * open a file in the database directory ($PGDATA/base/...)
675 FileNameOpenFile(FileName fileName, int fileFlags, int fileMode)
680 fname = filepath(fileName);
681 fd = fileNameOpenFile(fname, fileFlags, fileMode);
687 * open a file in an arbitrary directory
690 PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
692 return fileNameOpenFile(fileName, fileFlags, fileMode);
696 * Open a temporary file that will disappear when we close it.
698 * This routine takes care of generating an appropriate tempfile name.
699 * There's no need to pass in fileFlags or fileMode either, since only
700 * one setting makes any sense for a temp file.
703 OpenTemporaryFile(void)
705 char tempfilename[64];
709 * Generate a tempfile name that's unique within the current
712 snprintf(tempfilename, sizeof(tempfilename),
713 "pg_sorttemp%d.%ld", MyProcPid, tempFileCounter++);
716 file = FileNameOpenFile(tempfilename,
717 O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, 0600);
719 elog(ERROR, "Failed to create temporary file %s", tempfilename);
721 /* Mark it for deletion at close or EOXact */
722 VfdCache[file].fdstate |= FD_TEMPORARY;
728 * close a file when done with it
735 Assert(FileIsValid(file));
737 DO_DB(elog(DEBUG, "FileClose: %d (%s)",
738 file, VfdCache[file].fileName));
740 if (!FileIsNotOpen(file))
743 /* remove the file from the lru ring */
746 /* if we did any writes, sync the file before closing */
747 if (VfdCache[file].fdstate & FD_DIRTY)
749 returnValue = pg_fsync(VfdCache[file].fd);
750 Assert(returnValue != -1);
751 VfdCache[file].fdstate &= ~FD_DIRTY;
755 returnValue = close(VfdCache[file].fd);
756 Assert(returnValue != -1);
759 VfdCache[file].fd = VFD_CLOSED;
763 * Delete the file if it was temporary
765 if (VfdCache[file].fdstate & FD_TEMPORARY)
766 unlink(VfdCache[file].fileName);
769 * Return the Vfd slot to the free list
775 * close a file and forcibly delete the underlying Unix file
778 FileUnlink(File file)
780 Assert(FileIsValid(file));
782 DO_DB(elog(DEBUG, "FileUnlink: %d (%s)",
783 file, VfdCache[file].fileName));
785 /* force FileClose to delete it */
786 VfdCache[file].fdstate |= FD_TEMPORARY;
792 FileRead(File file, char *buffer, int amount)
796 Assert(FileIsValid(file));
798 DO_DB(elog(DEBUG, "FileRead: %d (%s) %d %p",
799 file, VfdCache[file].fileName, amount, buffer));
802 returnCode = read(VfdCache[file].fd, buffer, amount);
804 VfdCache[file].seekPos += returnCode;
806 VfdCache[file].seekPos = FileUnknownPos;
812 FileWrite(File file, char *buffer, int amount)
816 Assert(FileIsValid(file));
818 DO_DB(elog(DEBUG, "FileWrite: %d (%s) %d %p",
819 file, VfdCache[file].fileName, amount, buffer));
822 returnCode = write(VfdCache[file].fd, buffer, amount);
825 VfdCache[file].seekPos += returnCode;
826 /* mark the file as needing fsync */
827 VfdCache[file].fdstate |= FD_DIRTY;
830 VfdCache[file].seekPos = FileUnknownPos;
836 FileSeek(File file, long offset, int whence)
838 Assert(FileIsValid(file));
840 DO_DB(elog(DEBUG, "FileSeek: %d (%s) %ld %d",
841 file, VfdCache[file].fileName, offset, whence));
843 if (FileIsNotOpen(file))
849 elog(ERROR, "FileSeek: invalid offset: %ld", offset);
850 VfdCache[file].seekPos = offset;
853 VfdCache[file].seekPos += offset;
857 VfdCache[file].seekPos = lseek(VfdCache[file].fd, offset, whence);
860 elog(ERROR, "FileSeek: invalid whence: %d", whence);
870 elog(ERROR, "FileSeek: invalid offset: %ld", offset);
871 if (VfdCache[file].seekPos != offset)
872 VfdCache[file].seekPos = lseek(VfdCache[file].fd, offset, whence);
875 if (offset != 0 || VfdCache[file].seekPos == FileUnknownPos)
876 VfdCache[file].seekPos = lseek(VfdCache[file].fd, offset, whence);
879 VfdCache[file].seekPos = lseek(VfdCache[file].fd, offset, whence);
882 elog(ERROR, "FileSeek: invalid whence: %d", whence);
886 return VfdCache[file].seekPos;
890 * XXX not actually used but here for completeness
896 Assert(FileIsValid(file));
897 DO_DB(elog(DEBUG, "FileTell %d (%s)",
898 file, VfdCache[file].fileName));
899 return VfdCache[file].seekPos;
905 FileTruncate(File file, long offset)
909 Assert(FileIsValid(file));
911 DO_DB(elog(DEBUG, "FileTruncate %d (%s)",
912 file, VfdCache[file].fileName));
916 returnCode = ftruncate(VfdCache[file].fd, (size_t) offset);
921 * FileSync --- if a file is marked as dirty, fsync it.
923 * The FD_DIRTY bit is slightly misnamed: it doesn't mean that we need to
924 * write the file, but that we *have* written it and need to execute an
925 * fsync() to ensure the changes are down on disk before we mark the current
926 * transaction committed.
928 * FD_DIRTY is set by FileWrite or by an explicit FileMarkDirty() call.
929 * It is cleared after successfully fsync'ing the file. FileClose() will
930 * fsync a dirty File that is about to be closed, since there will be no
931 * other place to remember the need to fsync after the VFD is gone.
933 * Note that the DIRTY bit is logically associated with the actual disk file,
934 * not with any particular kernel FD we might have open for it. We assume
935 * that fsync will force out any dirty buffers for that file, whether or not
936 * they were written through the FD being used for the fsync call --- they
937 * might even have been written by some other backend!
939 * Note also that LruDelete currently fsyncs a dirty file that it is about
940 * to close the kernel file descriptor for. The idea there is to avoid
941 * having to re-open the kernel descriptor later. But it's not real clear
942 * that this is a performance win; we could end up fsyncing the same file
943 * multiple times in a transaction, which would probably cost more time
944 * than is saved by avoiding an open() call. This should be studied.
946 * This routine used to think it could skip the fsync if the file is
947 * physically closed, but that is now WRONG; see comments for FileMarkDirty.
954 Assert(FileIsValid(file));
956 if (!(VfdCache[file].fdstate & FD_DIRTY))
958 /* Need not sync if file is not dirty. */
961 else if (!enableFsync)
963 /* Don't force the file open if pg_fsync isn't gonna sync it. */
965 VfdCache[file].fdstate &= ~FD_DIRTY;
971 * We don't use FileAccess() because we don't want to force the
972 * file to the front of the LRU ring; we aren't expecting to
973 * access it again soon.
975 if (FileIsNotOpen(file))
977 returnCode = LruInsert(file);
981 returnCode = pg_fsync(VfdCache[file].fd);
983 VfdCache[file].fdstate &= ~FD_DIRTY;
990 * FileMarkDirty --- mark a file as needing fsync at transaction commit.
992 * Since FileWrite marks the file dirty, this routine is not needed in
993 * normal use. It is called when the buffer manager detects that some other
994 * backend has written out a shared buffer that this backend dirtied (but
995 * didn't write) in the current xact. In that scenario, we need to fsync
996 * the file before we can commit. We cannot assume that the other backend
997 * has fsync'd the file yet; we need to do our own fsync to ensure that
998 * (a) the disk page is written and (b) this backend's commit is delayed
999 * until the write is complete.
1001 * Note we are assuming that an fsync issued by this backend will write
1002 * kernel disk buffers that were dirtied by another backend. Furthermore,
1003 * it doesn't matter whether we currently have the file physically open;
1004 * we must fsync even if we have to re-open the file to do it.
1007 FileMarkDirty(File file)
1009 Assert(FileIsValid(file));
1011 DO_DB(elog(DEBUG, "FileMarkDirty: %d (%s)",
1012 file, VfdCache[file].fileName));
1014 VfdCache[file].fdstate |= FD_DIRTY;
1019 * Routines that want to use stdio (ie, FILE*) should use AllocateFile
1020 * rather than plain fopen(). This lets fd.c deal with freeing FDs if
1021 * necessary to open the file. When done, call FreeFile rather than fclose.
1023 * Note that files that will be open for any significant length of time
1024 * should NOT be handled this way, since they cannot share kernel file
1025 * descriptors with other files; there is grave risk of running out of FDs
1026 * if anyone locks down too many FDs. Most callers of this routine are
1027 * simply reading a config file that they will read and close immediately.
1029 * fd.c will automatically close all files opened with AllocateFile at
1030 * transaction commit or abort; this prevents FD leakage if a routine
1031 * that calls AllocateFile is terminated prematurely by elog(ERROR).
1033 * Ideally this should be the *only* direct call of fopen() in the backend.
1037 AllocateFile(char *name, char *mode)
1041 DO_DB(elog(DEBUG, "AllocateFile: Allocated %d", numAllocatedFiles));
1043 if (numAllocatedFiles >= MAX_ALLOCATED_FILES)
1044 elog(ERROR, "AllocateFile: too many private FDs demanded");
1047 if ((file = fopen(name, mode)) != NULL)
1049 allocatedFiles[numAllocatedFiles++] = file;
1053 if (errno == EMFILE || errno == ENFILE)
1055 int save_errno = errno;
1057 DO_DB(elog(DEBUG, "AllocateFile: not enough descs, retry, er= %d",
1060 if (ReleaseLruFile())
1069 FreeFile(FILE *file)
1073 DO_DB(elog(DEBUG, "FreeFile: Allocated %d", numAllocatedFiles));
1075 /* Remove file from list of allocated files, if it's present */
1076 for (i = numAllocatedFiles; --i >= 0;)
1078 if (allocatedFiles[i] == file)
1080 allocatedFiles[i] = allocatedFiles[--numAllocatedFiles];
1085 elog(NOTICE, "FreeFile: file was not obtained from AllocateFile");
1093 * Force all VFDs into the physically-closed state, so that the fewest
1094 * possible number of kernel file descriptors are in use. There is no
1095 * change in the logical state of the VFDs.
1102 if (SizeVfdCache > 0)
1104 Assert(FileIsNotOpen(0)); /* Make sure ring not corrupted */
1105 for (i = 1; i < SizeVfdCache; i++)
1107 if (!FileIsNotOpen(i))
1116 * This routine is called during transaction commit or abort or backend
1117 * exit (it doesn't particularly care which). All still-open temporary-file
1118 * VFDs are closed, which also causes the underlying files to be deleted.
1119 * Furthermore, all "allocated" stdio files are closed.
1121 * This routine is not involved in fsync'ing non-temporary files at xact
1122 * commit; that is done by FileSync under control of the buffer manager.
1123 * During a commit, that is done *before* control gets here. If we still
1124 * have any needs-fsync bits set when we get here, we assume this is abort
1128 AtEOXact_Files(void)
1132 if (SizeVfdCache > 0)
1134 Assert(FileIsNotOpen(0)); /* Make sure ring not corrupted */
1135 for (i = 1; i < SizeVfdCache; i++)
1137 if ((VfdCache[i].fdstate & FD_TEMPORARY) &&
1138 VfdCache[i].fileName != NULL)
1141 VfdCache[i].fdstate &= ~FD_DIRTY;
1145 while (numAllocatedFiles > 0)
1146 FreeFile(allocatedFiles[0]);
1149 * Reset the tempfile name counter to 0; not really necessary, but
1150 * helps keep the names from growing unreasonably long.
1152 tempFileCounter = 0;