* 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
+ * 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).
* 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.
static uint64 temporary_files_size = 0;
- * List of stdio FILEs and <dirent.h> DIRs opened with AllocateFile
+ * List of OS handles opened with AllocateFile, AllocateDir and
- * Since we don't want to encourage heavy use of
AllocateFile or AllocateDir,
+ * Since we don't want to encourage heavy use of ,
* it seems OK to put a pretty small maximum limit on the number of
* simultaneously allocated descs.
- * Free an AllocateDesc of either type.
+ * Like AllocateFile, but returns an unbuffered fd like open(2)
+OpenTransientFile(FileName fileName, int fileFlags, int fileMode)
+ 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
+ if (numAllocatedDescs >= MAX_ALLOCATED_DESCS ||
+ numAllocatedDescs >= max_safe_fds - 1)
+ elog(ERROR, "exceeded MAX_ALLOCATED_DESCS while trying to open file \"%s\"",
+ fd = BasicOpenFile(fileName, fileFlags, fileMode);
+ AllocateDesc *desc = &allocatedDescs[numAllocatedDescs];
+ desc->kind = AllocateDescRawFD;
+ desc->create_subid = GetCurrentSubTransactionId();
+ return -1; /* failure */
+ * Free an AllocateDesc of any type.
* The argument *must* point into the allocatedDescs array.
result = closedir(desc->desc.dir);
+ case AllocateDescRawFD:
+ result = close(desc->desc.fd);
elog(ERROR, "AllocateDesc kind not recognized");
result = 0; /* keep compiler quiet */
+ * 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.
+ 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)
+ /* Only get here if someone passes us a file not in allocatedDescs */
+ elog(WARNING, "fd passed to CloseTransientFile was not obtained from OpenTransientFile");
* Routines that want to use <dirent.h> (ie, DIR*) should use AllocateDir
* 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 d
+ * also clean up "allocated" stdio files and ds.
have_xact_temporary_files = false;
- /* Clean up "allocated" stdio files and d
+ /* Clean up "allocated" stdio files and ds. */
while (numAllocatedDescs > 0)