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.c84
1 files changed, 46 insertions, 38 deletions
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index 2a6c9466363..2d0d733a7c3 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.57 2000/05/31 00:28:27 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.58 2000/06/02 03:58:32 tgl Exp $
*
* NOTES:
*
@@ -203,6 +203,45 @@ pg_fsync(int fd)
}
/*
+ * BasicOpenFile --- same as open(2) except can free other FDs if needed
+ *
+ * This is exported for use by places that really want a plain kernel FD,
+ * but need to be proof against running out of FDs. Once an FD has been
+ * successfully returned, it is the caller's responsibility to ensure that
+ * it will not be leaked on elog()! Most users should *not* call this
+ * routine directly, but instead use the VFD abstraction level, which
+ * provides protection against descriptor leaks as well as management of
+ * files that need to be open for more than a short period of time.
+ *
+ * Ideally this should be the *only* direct call of open() in the backend.
+ * In practice, the postmaster calls open() directly, and there are some
+ * direct open() calls done early in backend startup. Those are OK since
+ * this module wouldn't have any open files to close at that point anyway.
+ */
+int
+BasicOpenFile(FileName fileName, int fileFlags, int fileMode)
+{
+ int fd;
+
+tryAgain:
+ fd = open(fileName, fileFlags, fileMode);
+
+ if (fd >= 0)
+ return fd; /* success! */
+
+ if ((errno == EMFILE || errno == ENFILE) && nfile > 0)
+ {
+ DO_DB(elog(DEBUG, "BasicOpenFile: not enough descs, retry, er= %d",
+ errno));
+ errno = 0;
+ ReleaseLruFile();
+ goto tryAgain;
+ }
+
+ return -1; /* failure */
+}
+
+/*
* pg_nofile: determine number of filedescriptors that fd.c is allowed to use
*/
static long
@@ -348,7 +387,6 @@ LruInsert(File file)
if (FileIsNotOpen(file))
{
-
while (nfile + numAllocatedFiles >= pg_nofile())
ReleaseLruFile();
@@ -357,15 +395,8 @@ LruInsert(File file)
* to overall system file table being full. So, be prepared to
* release another FD if necessary...
*/
-tryAgain:
- vfdP->fd = open(vfdP->fileName, vfdP->fileFlags, vfdP->fileMode);
- if (vfdP->fd < 0 && (errno == EMFILE || errno == ENFILE))
- {
- errno = 0;
- ReleaseLruFile();
- goto tryAgain;
- }
-
+ vfdP->fd = BasicOpenFile(vfdP->fileName, vfdP->fileFlags,
+ vfdP->fileMode);
if (vfdP->fd < 0)
{
DO_DB(elog(DEBUG, "RE_OPEN FAILED: %d",
@@ -411,22 +442,6 @@ ReleaseLruFile()
LruDelete(VfdCache[0].lruMoreRecently);
}
-/*
- * Force one kernel file descriptor to be released (temporarily).
- */
-bool
-ReleaseDataFile()
-{
- DO_DB(elog(DEBUG, "ReleaseDataFile. Opened %d", nfile));
-
- if (nfile <= 0)
- return (false);
- Assert(VfdCache[0].lruMoreRecently != 0);
- LruDelete(VfdCache[0].lruMoreRecently);
-
- return (true);
-}
-
static File
AllocateVfd()
{
@@ -617,16 +632,7 @@ fileNameOpenFile(FileName fileName,
while (nfile + numAllocatedFiles >= pg_nofile())
ReleaseLruFile();
-tryAgain:
- vfdP->fd = open(fileName, fileFlags, fileMode);
- if (vfdP->fd < 0 && (errno == EMFILE || errno == ENFILE))
- {
- DO_DB(elog(DEBUG, "fileNameOpenFile: not enough descs, retry, er= %d",
- errno));
- errno = 0;
- ReleaseLruFile();
- goto tryAgain;
- }
+ vfdP->fd = BasicOpenFile(fileName, fileFlags, fileMode);
if (vfdP->fd < 0)
{
@@ -990,6 +996,8 @@ FileMarkDirty(File file)
* fd.c will automatically close all files opened with AllocateFile at
* transaction commit or abort; this prevents FD leakage if a routine
* that calls AllocateFile is terminated prematurely by elog(ERROR).
+ *
+ * Ideally this should be the *only* direct call of fopen() in the backend.
*/
FILE *
@@ -1005,7 +1013,7 @@ AllocateFile(char *name, char *mode)
TryAgain:
if ((file = fopen(name, mode)) == NULL)
{
- if (errno == EMFILE || errno == ENFILE)
+ if ((errno == EMFILE || errno == ENFILE) && nfile > 0)
{
DO_DB(elog(DEBUG, "AllocateFile: not enough descs, retry, er= %d",
errno));