diff options
Diffstat (limited to 'src/backend/storage/file/fd.c')
-rw-r--r-- | src/backend/storage/file/fd.c | 125 |
1 files changed, 108 insertions, 17 deletions
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index ecb62ba01ae..07ee51cf5aa 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -30,11 +30,29 @@ * routines (e.g., open(2) and fopen(3)) themselves. Otherwise, we * may find ourselves short of real file descriptors anyway. * - * This file used to contain a bunch of stuff to support RAID levels 0 - * (jbod), 1 (duplex) and 5 (xor parity). That stuff is all gone - * because the parallel query processing code that called it is all - * gone. If you really need it you could get it from the original - * POSTGRES source. + * INTERFACE ROUTINES + * + * PathNameOpenFile and OpenTemporaryFile are used to open virtual files. + * A File opened with OpenTemporaryFile is automatically deleted when the + * File is closed, either explicitly or implicitly at end of transaction or + * process exit. PathNameOpenFile is intended for files that are held open + * for a long time, like relation files. It is the caller's responsibility + * to close them, there is no automatic mechanism in fd.c for that. + * + * AllocateFile, AllocateDir and OpenTransientFile are wrappers around + * fopen(3), opendir(3), and open(2), respectively. They behave like the + * corresponding native functions, except that the handle is registered with + * the current subtransaction, and will be automatically closed at abort. + * These are intended for short operations like reading a configuration file. + * and there is a fixed limit on the number files that can be open using these + * functions at any one time. + * + * Finally, BasicOpenFile is a just thin wrapper around open() that can + * release file descriptors in use by the virtual file descriptors if + * necessary. There is no automatic cleanup of file descriptors returned by + * BasicOpenFile, it is solely the caller's responsibility to close the file + * descriptor by calling close(2). + * *------------------------------------------------------------------------- */ @@ -94,11 +112,11 @@ int max_files_per_process = 1000; /* * Maximum number of file descriptors to open for either VFD entries or - * AllocateFile/AllocateDir operations. This is initialized to a conservative - * value, and remains that way indefinitely in bootstrap or standalone-backend - * cases. In normal postmaster operation, the postmaster calls - * set_max_safe_fds() late in initialization to update the value, and that - * value is then inherited by forked subprocesses. + * AllocateFile/AllocateDir/OpenTransientFile operations. This is initialized + * to a conservative value, and remains that way indefinitely in bootstrap or + * standalone-backend cases. In normal postmaster operation, the postmaster + * calls set_max_safe_fds() late in initialization to update the value, and + * that value is then inherited by forked subprocesses. * * Note: the value of max_files_per_process is taken into account while * setting this variable, and so need not be tested separately. @@ -171,10 +189,10 @@ static bool have_xact_temporary_files = false; static uint64 temporary_files_size = 0; /* - * List of stdio FILEs and <dirent.h> DIRs opened with AllocateFile - * and AllocateDir. + * List of OS handles opened with AllocateFile, AllocateDir and + * OpenTransientFile. * - * Since we don't want to encourage heavy use of AllocateFile or AllocateDir, + * Since we don't want to encourage heavy use of those functions, * it seems OK to put a pretty small maximum limit on the number of * simultaneously allocated descs. */ @@ -183,7 +201,8 @@ static uint64 temporary_files_size = 0; typedef enum { AllocateDescFile, - AllocateDescDir + AllocateDescDir, + AllocateDescRawFD } AllocateDescKind; typedef struct @@ -193,6 +212,7 @@ typedef struct { FILE *file; DIR *dir; + int fd; } desc; SubTransactionId create_subid; } AllocateDesc; @@ -1523,8 +1543,49 @@ TryAgain: return NULL; } + /* - * Free an AllocateDesc of either type. + * Like AllocateFile, but returns an unbuffered fd like open(2) + */ +int +OpenTransientFile(FileName fileName, int fileFlags, int fileMode) +{ + int fd; + + + DO_DB(elog(LOG, "OpenTransientFile: Allocated %d (%s)", + numAllocatedDescs, fileName)); + + /* + * The test against MAX_ALLOCATED_DESCS prevents us from overflowing + * allocatedFiles[]; the test against max_safe_fds prevents BasicOpenFile + * from hogging every one of the available FDs, which'd lead to infinite + * looping. + */ + if (numAllocatedDescs >= MAX_ALLOCATED_DESCS || + numAllocatedDescs >= max_safe_fds - 1) + elog(ERROR, "exceeded MAX_ALLOCATED_DESCS while trying to open file \"%s\"", + fileName); + + fd = BasicOpenFile(fileName, fileFlags, fileMode); + + if (fd >= 0) + { + AllocateDesc *desc = &allocatedDescs[numAllocatedDescs]; + + desc->kind = AllocateDescRawFD; + desc->desc.fd = fd; + desc->create_subid = GetCurrentSubTransactionId(); + numAllocatedDescs++; + + return fd; + } + + return -1; /* failure */ +} + +/* + * Free an AllocateDesc of any type. * * The argument *must* point into the allocatedDescs[] array. */ @@ -1542,6 +1603,9 @@ FreeDesc(AllocateDesc *desc) case AllocateDescDir: result = closedir(desc->desc.dir); break; + case AllocateDescRawFD: + result = close(desc->desc.fd); + break; default: elog(ERROR, "AllocateDesc kind not recognized"); result = 0; /* keep compiler quiet */ @@ -1583,6 +1647,33 @@ FreeFile(FILE *file) return fclose(file); } +/* + * Close a file returned by OpenTransientFile. + * + * Note we do not check close's return value --- it is up to the caller + * to handle close errors. + */ +int +CloseTransientFile(int fd) +{ + int i; + + DO_DB(elog(LOG, "CloseTransientFile: Allocated %d", numAllocatedDescs)); + + /* Remove fd from list of allocated files, if it's present */ + for (i = numAllocatedDescs; --i >= 0;) + { + AllocateDesc *desc = &allocatedDescs[i]; + + if (desc->kind == AllocateDescRawFD && desc->desc.fd == fd) + return FreeDesc(desc); + } + + /* Only get here if someone passes us a file not in allocatedDescs */ + elog(WARNING, "fd passed to CloseTransientFile was not obtained from OpenTransientFile"); + + return close(fd); +} /* * Routines that want to use <dirent.h> (ie, DIR*) should use AllocateDir @@ -1874,7 +1965,7 @@ AtProcExit_Files(int code, Datum arg) * exiting. If that's the case, we should remove all temporary files; if * that's not the case, we are being called for transaction commit/abort * and should only remove transaction-local temp files. In either case, - * also clean up "allocated" stdio files and dirs. + * also clean up "allocated" stdio files, dirs and fds. */ static void CleanupTempFiles(bool isProcExit) @@ -1916,7 +2007,7 @@ CleanupTempFiles(bool isProcExit) have_xact_temporary_files = false; } - /* Clean up "allocated" stdio files and dirs. */ + /* Clean up "allocated" stdio files, dirs and fds. */ while (numAllocatedDescs > 0) FreeDesc(&allocatedDescs[0]); } |