Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Enumerations | Functions | Variables

fd.c File Reference

#include "postgres.h"
#include <sys/file.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include "miscadmin.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/pg_tablespace.h"
#include "common/relpath.h"
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "utils/guc.h"
#include "utils/resowner_private.h"
Include dependency graph for fd.c:

Go to the source code of this file.

Data Structures

struct  vfd
struct  AllocateDesc

Defines

#define NUM_RESERVED_FDS   10
#define FD_MINFREE   10
#define DO_DB(A)
#define VFD_CLOSED   (-1)
#define FileIsValid(file)   ((file) > 0 && (file) < (int) SizeVfdCache && VfdCache[file].fileName != NULL)
#define FileIsNotOpen(file)   (VfdCache[file].fd == VFD_CLOSED)
#define FileUnknownPos   ((off_t) -1)
#define FD_TEMPORARY   (1 << 0)
#define FD_XACT_TEMPORARY   (1 << 1)
#define MAX_ALLOCATED_DESCS   32

Typedefs

typedef struct vfd Vfd

Enumerations

enum  AllocateDescKind { AllocateDescFile, AllocateDescPipe, AllocateDescDir, AllocateDescRawFD }

Functions

static void Delete (File file)
static void LruDelete (File file)
static void Insert (File file)
static int LruInsert (File file)
static bool ReleaseLruFile (void)
static File AllocateVfd (void)
static void FreeVfd (File file)
static int FileAccess (File file)
static File OpenTemporaryFileInTablespace (Oid tblspcOid, bool rejectError)
static void AtProcExit_Files (int code, Datum arg)
static void CleanupTempFiles (bool isProcExit)
static void RemovePgTempFilesInDir (const char *tmpdirname)
static void RemovePgTempRelationFiles (const char *tsdirname)
static void RemovePgTempRelationFilesInDbspace (const char *dbspacedirname)
static bool looks_like_temp_rel_name (const char *name)
int pg_fsync (int fd)
int pg_fsync_no_writethrough (int fd)
int pg_fsync_writethrough (int fd)
int pg_fdatasync (int fd)
int pg_flush_data (int fd, off_t offset, off_t amount)
void InitFileAccess (void)
static void count_usable_fds (int max_to_probe, int *usable_fds, int *already_open)
void set_max_safe_fds (void)
int BasicOpenFile (FileName fileName, int fileFlags, int fileMode)
File PathNameOpenFile (FileName fileName, int fileFlags, int fileMode)
File OpenTemporaryFile (bool interXact)
void FileClose (File file)
int FilePrefetch (File file, off_t offset, int amount)
int FileRead (File file, char *buffer, int amount)
int FileWrite (File file, char *buffer, int amount)
int FileSync (File file)
off_t FileSeek (File file, off_t offset, int whence)
int FileTruncate (File file, off_t offset)
char * FilePathName (File file)
FILE * AllocateFile (const char *name, const char *mode)
int OpenTransientFile (FileName fileName, int fileFlags, int fileMode)
FILE * OpenPipeStream (const char *command, const char *mode)
static int FreeDesc (AllocateDesc *desc)
int FreeFile (FILE *file)
int CloseTransientFile (int fd)
DIRAllocateDir (const char *dirname)
struct direntReadDir (DIR *dir, const char *dirname)
int FreeDir (DIR *dir)
int ClosePipeStream (FILE *file)
void closeAllVfds (void)
void SetTempTablespaces (Oid *tableSpaces, int numSpaces)
bool TempTablespacesAreSet (void)
Oid GetNextTempTableSpace (void)
void AtEOSubXact_Files (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
void AtEOXact_Files (void)
void RemovePgTempFiles (void)

Variables

int max_files_per_process = 1000
int max_safe_fds = 32
static VfdVfdCache
static Size SizeVfdCache = 0
static int nfile = 0
static bool have_xact_temporary_files = false
static uint64 temporary_files_size = 0
static int numAllocatedDescs = 0
static AllocateDesc allocatedDescs [MAX_ALLOCATED_DESCS]
static long tempFileCounter = 0
static OidtempTableSpaces = NULL
static int numTempTableSpaces = -1
static int nextTempTableSpace = 0

Define Documentation

#define DO_DB (   A  ) 
#define FD_MINFREE   10

Definition at line 103 of file fd.c.

Referenced by set_max_safe_fds().

#define FD_TEMPORARY   (1 << 0)

Definition at line 146 of file fd.c.

Referenced by CleanupTempFiles(), FileClose(), FileTruncate(), and FileWrite().

#define FD_XACT_TEMPORARY   (1 << 1)

Definition at line 147 of file fd.c.

Referenced by CleanupTempFiles().

#define FileIsNotOpen (   file  )     (VfdCache[file].fd == VFD_CLOSED)

Definition at line 141 of file fd.c.

Referenced by CleanupTempFiles(), closeAllVfds(), FileAccess(), FileClose(), FileSeek(), and LruInsert().

#define FileIsValid (   file  )     ((file) > 0 && (file) < (int) SizeVfdCache && VfdCache[file].fileName != NULL)
#define FileUnknownPos   ((off_t) -1)

Definition at line 143 of file fd.c.

Referenced by FileSeek().

#define MAX_ALLOCATED_DESCS   32

Definition at line 200 of file fd.c.

Referenced by AllocateDir(), AllocateFile(), OpenPipeStream(), and OpenTransientFile().

#define NUM_RESERVED_FDS   10

Definition at line 97 of file fd.c.

Referenced by set_max_safe_fds().

#define VFD_CLOSED   (-1)

Definition at line 136 of file fd.c.


Typedef Documentation

typedef struct vfd Vfd

Enumeration Type Documentation

Enumerator:
AllocateDescFile 
AllocateDescPipe 
AllocateDescDir 
AllocateDescRawFD 

Definition at line 202 of file fd.c.

{
    AllocateDescFile,
    AllocateDescPipe,
    AllocateDescDir,
    AllocateDescRawFD
} AllocateDescKind;


Function Documentation

DIR* AllocateDir ( const char *  dirname  ) 

Definition at line 1747 of file fd.c.

References AllocateDesc::create_subid, AllocateDesc::desc, AllocateDesc::dir, DO_DB, elog, ereport, errcode(), errmsg(), ERROR, GetCurrentSubTransactionId(), AllocateDesc::kind, LOG, MAX_ALLOCATED_DESCS, max_safe_fds, NULL, numAllocatedDescs, opendir(), and ReleaseLruFile().

Referenced by calculate_database_size(), calculate_tablespace_size(), CleanupBackupHistory(), copydir(), db_dir_size(), DeleteAllExportedSnapshotFiles(), destroy_tablespace_directories(), directory_is_empty(), get_available_versions_for_extension(), get_ext_ver_list(), getInstallationPaths(), movedb(), ParseTzFile(), perform_base_backup(), pg_available_extension_versions(), pg_available_extensions(), pg_logdir_ls(), pg_ls_dir(), pg_tablespace_databases(), pg_tzenumerate_next(), pg_tzenumerate_start(), pgarch_readyXlog(), pgstat_reset_remove_files(), PrescanPreparedTransactions(), RecoverPreparedTransactions(), RelationCacheInitFileRemove(), RelationCacheInitFileRemoveInDir(), RemoveOldXlogFiles(), RemovePgTempFiles(), RemovePgTempFilesInDir(), RemovePgTempRelationFiles(), RemovePgTempRelationFilesInDbspace(), ResetUnloggedRelations(), ResetUnloggedRelationsInDbspaceDir(), ResetUnloggedRelationsInTablespaceDir(), scan_directory_ci(), SendBaseBackup(), sendDir(), SlruScanDirectory(), and StandbyRecoverPreparedTransactions().

{
    DIR        *dir;

    DO_DB(elog(LOG, "AllocateDir: Allocated %d (%s)",
               numAllocatedDescs, dirname));

    /*
     * The test against MAX_ALLOCATED_DESCS prevents us from overflowing
     * allocatedDescs[]; the test against max_safe_fds prevents AllocateDir
     * 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 directory \"%s\"",
             dirname);

TryAgain:
    if ((dir = opendir(dirname)) != NULL)
    {
        AllocateDesc *desc = &allocatedDescs[numAllocatedDescs];

        desc->kind = AllocateDescDir;
        desc->desc.dir = dir;
        desc->create_subid = GetCurrentSubTransactionId();
        numAllocatedDescs++;
        return desc->desc.dir;
    }

    if (errno == EMFILE || errno == ENFILE)
    {
        int         save_errno = errno;

        ereport(LOG,
                (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
                 errmsg("out of file descriptors: %m; release and retry")));
        errno = 0;
        if (ReleaseLruFile())
            goto TryAgain;
        errno = save_errno;
    }

    return NULL;
}

FILE* AllocateFile ( const char *  name,
const char *  mode 
)

Definition at line 1502 of file fd.c.

References AllocateDesc::create_subid, AllocateDesc::desc, DO_DB, elog, ereport, errcode(), errmsg(), ERROR, AllocateDesc::file, GetCurrentSubTransactionId(), AllocateDesc::kind, LOG, MAX_ALLOCATED_DESCS, max_safe_fds, NULL, numAllocatedDescs, and ReleaseLruFile().

Referenced by BeginCopyFrom(), BeginCopyTo(), checkDataDir(), do_pg_start_backup(), do_pg_stop_backup(), existsTimeLineHistory(), ExportSnapshot(), ImportSnapshot(), load_hba(), load_ident(), load_relcache_init_file(), parse_extension_control_file(), ParseTzFile(), perform_base_backup(), pg_backup_start_time(), pgss_shmem_shutdown(), pgss_shmem_startup(), pgstat_read_db_statsfile(), pgstat_read_db_statsfile_timestamp(), pgstat_read_statsfiles(), pgstat_write_db_statsfile(), pgstat_write_statsfiles(), read_backup_label(), read_binary_file(), readRecoveryCommandFile(), readTimeLineHistory(), sendFile(), tokenize_inc_file(), tsearch_readline_begin(), ValidatePgVersion(), write_relcache_init_file(), XLogArchiveForceDone(), and XLogArchiveNotify().

{
    FILE       *file;

    DO_DB(elog(LOG, "AllocateFile: Allocated %d (%s)",
               numAllocatedDescs, name));

    /*
     * The test against MAX_ALLOCATED_DESCS prevents us from overflowing
     * allocatedFiles[]; the test against max_safe_fds prevents AllocateFile
     * 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\"",
             name);

TryAgain:
    if ((file = fopen(name, mode)) != NULL)
    {
        AllocateDesc *desc = &allocatedDescs[numAllocatedDescs];

        desc->kind = AllocateDescFile;
        desc->desc.file = file;
        desc->create_subid = GetCurrentSubTransactionId();
        numAllocatedDescs++;
        return desc->desc.file;
    }

    if (errno == EMFILE || errno == ENFILE)
    {
        int         save_errno = errno;

        ereport(LOG,
                (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
                 errmsg("out of file descriptors: %m; release and retry")));
        errno = 0;
        if (ReleaseLruFile())
            goto TryAgain;
        errno = save_errno;
    }

    return NULL;
}

static File AllocateVfd ( void   )  [static]

Definition at line 752 of file fd.c.

References Assert, DO_DB, elog, ereport, errcode(), errmsg(), ERROR, vfd::fd, i, LOG, MemSet, vfd::nextFree, NULL, realloc, and SizeVfdCache.

Referenced by PathNameOpenFile().

{
    Index       i;
    File        file;

    DO_DB(elog(LOG, "AllocateVfd. Size %lu", SizeVfdCache));

    Assert(SizeVfdCache > 0);   /* InitFileAccess not called? */

    if (VfdCache[0].nextFree == 0)
    {
        /*
         * The free list is empty so it is time to increase the size of the
         * array.  We choose to double it each time this happens. However,
         * there's not much point in starting *real* small.
         */
        Size        newCacheSize = SizeVfdCache * 2;
        Vfd        *newVfdCache;

        if (newCacheSize < 32)
            newCacheSize = 32;

        /*
         * Be careful not to clobber VfdCache ptr if realloc fails.
         */
        newVfdCache = (Vfd *) realloc(VfdCache, sizeof(Vfd) * newCacheSize);
        if (newVfdCache == NULL)
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("out of memory")));
        VfdCache = newVfdCache;

        /*
         * Initialize the new entries and link them into the free list.
         */
        for (i = SizeVfdCache; i < newCacheSize; i++)
        {
            MemSet((char *) &(VfdCache[i]), 0, sizeof(Vfd));
            VfdCache[i].nextFree = i + 1;
            VfdCache[i].fd = VFD_CLOSED;
        }
        VfdCache[newCacheSize - 1].nextFree = 0;
        VfdCache[0].nextFree = SizeVfdCache;

        /*
         * Record the new size
         */
        SizeVfdCache = newCacheSize;
    }

    file = VfdCache[0].nextFree;

    VfdCache[0].nextFree = VfdCache[file].nextFree;

    return file;
}

void AtEOSubXact_Files ( bool  isCommit,
SubTransactionId  mySubid,
SubTransactionId  parentSubid 
)

Definition at line 1996 of file fd.c.

References AllocateDesc::create_subid, FreeDesc(), i, and numAllocatedDescs.

Referenced by AbortSubTransaction(), and CommitSubTransaction().

{
    Index       i;

    for (i = 0; i < numAllocatedDescs; i++)
    {
        if (allocatedDescs[i].create_subid == mySubid)
        {
            if (isCommit)
                allocatedDescs[i].create_subid = parentSubid;
            else
            {
                /* have to recheck the item after FreeDesc (ugly) */
                FreeDesc(&allocatedDescs[i--]);
            }
        }
    }
}

void AtEOXact_Files ( void   ) 
static void AtProcExit_Files ( int  code,
Datum  arg 
) [static]

Definition at line 2041 of file fd.c.

References CleanupTempFiles().

Referenced by InitFileAccess().

{
    CleanupTempFiles(true);
}

int BasicOpenFile ( FileName  fileName,
int  fileFlags,
int  fileMode 
)

Definition at line 561 of file fd.c.

References ereport, errcode(), errmsg(), LOG, and ReleaseLruFile().

Referenced by GetNewRelFileNode(), LruInsert(), OpenTransientFile(), PathNameOpenFile(), ReadControlFile(), UpdateControlFile(), WriteControlFile(), XLogFileInit(), XLogFileOpen(), XLogFileRead(), and XLogRead().

{
    int         fd;

tryAgain:
    fd = open(fileName, fileFlags, fileMode);

    if (fd >= 0)
        return fd;              /* success! */

    if (errno == EMFILE || errno == ENFILE)
    {
        int         save_errno = errno;

        ereport(LOG,
                (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
                 errmsg("out of file descriptors: %m; release and retry")));
        errno = 0;
        if (ReleaseLruFile())
            goto tryAgain;
        errno = save_errno;
    }

    return -1;                  /* failure */
}

static void CleanupTempFiles ( bool  isProcExit  )  [static]

Definition at line 2056 of file fd.c.

References Assert, elog, FD_TEMPORARY, FD_XACT_TEMPORARY, vfd::fdstate, FileClose(), FileIsNotOpen, FreeDesc(), have_xact_temporary_files, i, NULL, numAllocatedDescs, SizeVfdCache, and WARNING.

Referenced by AtEOXact_Files(), and AtProcExit_Files().

{
    Index       i;

    /*
     * 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
                 * local to the current transaction. They should be closed by
                 * the ResourceOwner mechanism already, so this is just a
                 * debugging cross-check.
                 */
                if (isProcExit)
                    FileClose(i);
                else if (fdstate & FD_XACT_TEMPORARY)
                {
                    elog(WARNING,
                         "temporary file %s not closed at end-of-transaction",
                         VfdCache[i].fileName);
                    FileClose(i);
                }
            }
        }

        have_xact_temporary_files = false;
    }

    /* Clean up "allocated" stdio files, dirs and fds. */
    while (numAllocatedDescs > 0)
        FreeDesc(&allocatedDescs[0]);
}

void closeAllVfds ( void   ) 

Definition at line 1909 of file fd.c.

References Assert, FileIsNotOpen, i, LruDelete(), and SizeVfdCache.

Referenced by standard_ProcessUtility().

{
    Index       i;

    if (SizeVfdCache > 0)
    {
        Assert(FileIsNotOpen(0));       /* Make sure ring not corrupted */
        for (i = 1; i < SizeVfdCache; i++)
        {
            if (!FileIsNotOpen(i))
                LruDelete(i);
        }
    }
}

int ClosePipeStream ( FILE *  file  ) 

Definition at line 1880 of file fd.c.

References AllocateDescPipe, AllocateDesc::desc, DO_DB, elog, AllocateDesc::file, FreeDesc(), i, AllocateDesc::kind, LOG, numAllocatedDescs, and WARNING.

Referenced by ClosePipeToProgram().

{
    int         i;

    DO_DB(elog(LOG, "ClosePipeStream: Allocated %d", numAllocatedDescs));

    /* Remove file from list of allocated files, if it's present */
    for (i = numAllocatedDescs; --i >= 0;)
    {
        AllocateDesc *desc = &allocatedDescs[i];

        if (desc->kind == AllocateDescPipe && desc->desc.file == file)
            return FreeDesc(desc);
    }

    /* Only get here if someone passes us a file not in allocatedDescs */
    elog(WARNING, "file passed to ClosePipeStream was not obtained from OpenPipeStream");

    return pclose(file);
}

int CloseTransientFile ( int  fd  ) 

Definition at line 1717 of file fd.c.

References AllocateDescRawFD, close, AllocateDesc::desc, DO_DB, elog, AllocateDesc::fd, FreeDesc(), i, AllocateDesc::kind, LOG, numAllocatedDescs, and WARNING.

Referenced by CheckPointTwoPhase(), copy_file(), EndPrepare(), fsync_fname(), lo_export(), lo_import_internal(), load_relmap_file(), mdunlinkfork(), ReadTwoPhaseFile(), RecreateTwoPhaseFile(), SendTimeLineHistory(), SimpleLruFlush(), SlruInternalWritePage(), SlruPhysicalReadPage(), SlruPhysicalWritePage(), write_relmap_file(), writeTimeLineHistory(), writeTimeLineHistoryFile(), and XLogFileCopy().

{
    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);
}

static void count_usable_fds ( int  max_to_probe,
int *  usable_fds,
int *  already_open 
) [static]

Definition at line 422 of file fd.c.

References close, elog, ereport, errmsg(), palloc(), pfree(), repalloc(), and WARNING.

Referenced by set_max_safe_fds().

{
    int        *fd;
    int         size;
    int         used = 0;
    int         highestfd = 0;
    int         j;

#ifdef HAVE_GETRLIMIT
    struct rlimit rlim;
    int         getrlimit_status;
#endif

    size = 1024;
    fd = (int *) palloc(size * sizeof(int));

#ifdef HAVE_GETRLIMIT
#ifdef RLIMIT_NOFILE            /* most platforms use RLIMIT_NOFILE */
    getrlimit_status = getrlimit(RLIMIT_NOFILE, &rlim);
#else                           /* but BSD doesn't ... */
    getrlimit_status = getrlimit(RLIMIT_OFILE, &rlim);
#endif   /* RLIMIT_NOFILE */
    if (getrlimit_status != 0)
        ereport(WARNING, (errmsg("getrlimit failed: %m")));
#endif   /* HAVE_GETRLIMIT */

    /* dup until failure or probe limit reached */
    for (;;)
    {
        int         thisfd;

#ifdef HAVE_GETRLIMIT

        /*
         * don't go beyond RLIMIT_NOFILE; causes irritating kernel logs on
         * some platforms
         */
        if (getrlimit_status == 0 && highestfd >= rlim.rlim_cur - 1)
            break;
#endif

        thisfd = dup(0);
        if (thisfd < 0)
        {
            /* Expect EMFILE or ENFILE, else it's fishy */
            if (errno != EMFILE && errno != ENFILE)
                elog(WARNING, "dup(0) failed after %d successes: %m", used);
            break;
        }

        if (used >= size)
        {
            size *= 2;
            fd = (int *) repalloc(fd, size * sizeof(int));
        }
        fd[used++] = thisfd;

        if (highestfd < thisfd)
            highestfd = thisfd;

        if (used >= max_to_probe)
            break;
    }

    /* release the files we opened */
    for (j = 0; j < used; j++)
        close(fd[j]);

    pfree(fd);

    /*
     * Return results.  usable_fds is just the number of successful dups. We
     * assume that the system limit is highestfd+1 (remember 0 is a legal FD
     * number) and so already_open is highestfd+1 - usable_fds.
     */
    *usable_fds = used;
    *already_open = highestfd + 1 - used;
}

static void Delete ( File  file  )  [static]

Definition at line 609 of file fd.c.

References Assert, DO_DB, elog, LOG, vfd::lruLessRecently, and vfd::lruMoreRecently.

Referenced by FileAccess(), FileClose(), and LruDelete().

{
    Vfd        *vfdP;

    Assert(file != 0);

    DO_DB(elog(LOG, "Delete %d (%s)",
               file, VfdCache[file].fileName));
    DO_DB(_dump_lru());

    vfdP = &VfdCache[file];

    VfdCache[vfdP->lruLessRecently].lruMoreRecently = vfdP->lruMoreRecently;
    VfdCache[vfdP->lruMoreRecently].lruLessRecently = vfdP->lruLessRecently;

    DO_DB(_dump_lru());
}

static int FileAccess ( File  file  )  [static]

Definition at line 830 of file fd.c.

References Delete(), DO_DB, elog, FileIsNotOpen, Insert(), LOG, and LruInsert().

Referenced by FilePrefetch(), FileRead(), FileSeek(), FileSync(), FileTruncate(), and FileWrite().

{
    int         returnValue;

    DO_DB(elog(LOG, "FileAccess %d (%s)",
               file, VfdCache[file].fileName));

    /*
     * Is the file open?  If not, open it and put it at the head of the LRU
     * ring (possibly closing the least recently used file to get an FD).
     */

    if (FileIsNotOpen(file))
    {
        returnValue = LruInsert(file);
        if (returnValue != 0)
            return returnValue;
    }
    else if (VfdCache[0].lruLessRecently != file)
    {
        /*
         * We now know that the file is open and that it is not the last one
         * accessed, so we need to move it to the head of the Lru ring.
         */

        Delete(file);
        Insert(file);
    }

    return 0;
}

void FileClose ( File  file  ) 

Definition at line 1073 of file fd.c.

References Assert, close, Delete(), DO_DB, elog, ereport, errmsg(), ERROR, vfd::fd, FD_TEMPORARY, vfd::fdstate, FileIsNotOpen, FileIsValid, vfd::fileName, vfd::fileSize, FreeVfd(), LOG, log_temp_files, nfile, pgstat_report_tempfile(), ResourceOwnerForgetFile(), vfd::resowner, temporary_files_size, and unlink().

Referenced by BufFileClose(), CleanupTempFiles(), mdclose(), and ResourceOwnerReleaseInternal().

{
    Vfd        *vfdP;

    Assert(FileIsValid(file));

    DO_DB(elog(LOG, "FileClose: %d (%s)",
               file, VfdCache[file].fileName));

    vfdP = &VfdCache[file];

    if (!FileIsNotOpen(file))
    {
        /* remove the file from the lru ring */
        Delete(file);

        /* close the file */
        if (close(vfdP->fd))
            elog(ERROR, "could not close file \"%s\": %m", vfdP->fileName);

        --nfile;
        vfdP->fd = VFD_CLOSED;
    }

    /*
     * Delete the file if it was temporary, and make a log entry if wanted
     */
    if (vfdP->fdstate & FD_TEMPORARY)
    {
        struct stat filestats;
        int         stat_errno;

        /*
         * If we get an error, as could happen within the ereport/elog calls,
         * we'll come right back here during transaction abort.  Reset the
         * flag to ensure that we can't get into an infinite loop.  This code
         * is arranged to ensure that the worst-case consequence is failing to
         * emit log message(s), not failing to attempt the unlink.
         */
        vfdP->fdstate &= ~FD_TEMPORARY;

        /* Subtract its size from current usage (do first in case of error) */
        temporary_files_size -= vfdP->fileSize;
        vfdP->fileSize = 0;

        /* first try the stat() */
        if (stat(vfdP->fileName, &filestats))
            stat_errno = errno;
        else
            stat_errno = 0;

        /* in any case do the unlink */
        if (unlink(vfdP->fileName))
            elog(LOG, "could not unlink file \"%s\": %m", vfdP->fileName);

        /* and last report the stat results */
        if (stat_errno == 0)
        {
            pgstat_report_tempfile(filestats.st_size);

            if (log_temp_files >= 0)
            {
                if ((filestats.st_size / 1024) >= log_temp_files)
                    ereport(LOG,
                            (errmsg("temporary file: path \"%s\", size %lu",
                                    vfdP->fileName,
                                    (unsigned long) filestats.st_size)));
            }
        }
        else
        {
            errno = stat_errno;
            elog(LOG, "could not stat file \"%s\": %m", vfdP->fileName);
        }
    }

    /* Unregister it from the resource owner */
    if (vfdP->resowner)
        ResourceOwnerForgetFile(vfdP->resowner, file);

    /*
     * Return the Vfd slot to the free list
     */
    FreeVfd(file);
}

char* FilePathName ( File  file  ) 

Definition at line 1476 of file fd.c.

References Assert, FileIsValid, and vfd::fileName.

Referenced by _mdnblocks(), mdextend(), mdimmedsync(), mdread(), mdsync(), mdtruncate(), mdwrite(), and register_dirty_segment().

{
    Assert(FileIsValid(file));

    return VfdCache[file].fileName;
}

int FilePrefetch ( File  file,
off_t  offset,
int  amount 
)

Definition at line 1170 of file fd.c.

References Assert, DO_DB, elog, fd(), FileAccess(), FileIsValid, and LOG.

Referenced by mdprefetch().

{
#if defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
    int         returnCode;

    Assert(FileIsValid(file));

    DO_DB(elog(LOG, "FilePrefetch: %d (%s) " INT64_FORMAT " %d",
               file, VfdCache[file].fileName,
               (int64) offset, amount));

    returnCode = FileAccess(file);
    if (returnCode < 0)
        return returnCode;

    returnCode = posix_fadvise(VfdCache[file].fd, offset, amount,
                               POSIX_FADV_WILLNEED);

    return returnCode;
#else
    Assert(FileIsValid(file));
    return 0;
#endif
}

int FileRead ( File  file,
char *  buffer,
int  amount 
)

Definition at line 1196 of file fd.c.

References _dosmaperr(), Assert, DO_DB, EINTR, elog, error(), fd(), FileAccess(), FileIsValid, LOG, pg_usleep(), read, and vfd::seekPos.

Referenced by BufFileLoadBuffer(), and mdread().

{
    int         returnCode;

    Assert(FileIsValid(file));

    DO_DB(elog(LOG, "FileRead: %d (%s) " INT64_FORMAT " %d %p",
               file, VfdCache[file].fileName,
               (int64) VfdCache[file].seekPos,
               amount, buffer));

    returnCode = FileAccess(file);
    if (returnCode < 0)
        return returnCode;

retry:
    returnCode = read(VfdCache[file].fd, buffer, amount);

    if (returnCode >= 0)
        VfdCache[file].seekPos += returnCode;
    else
    {
        /*
         * Windows may run out of kernel buffers and return "Insufficient
         * system resources" error.  Wait a bit and retry to solve it.
         *
         * It is rumored that EINTR is also possible on some Unix filesystems,
         * in which case immediate retry is indicated.
         */
#ifdef WIN32
        DWORD       error = GetLastError();

        switch (error)
        {
            case ERROR_NO_SYSTEM_RESOURCES:
                pg_usleep(1000L);
                errno = EINTR;
                break;
            default:
                _dosmaperr(error);
                break;
        }
#endif
        /* OK to retry if interrupted */
        if (errno == EINTR)
            goto retry;

        /* Trouble, so assume we don't know the file position anymore */
        VfdCache[file].seekPos = FileUnknownPos;
    }

    return returnCode;
}

off_t FileSeek ( File  file,
off_t  offset,
int  whence 
)

Definition at line 1363 of file fd.c.

References Assert, DO_DB, elog, ERROR, fd(), FileAccess(), FileIsNotOpen, FileIsValid, FileUnknownPos, LOG, and vfd::seekPos.

Referenced by _mdnblocks(), BufFileDumpBuffer(), BufFileLoadBuffer(), mdextend(), mdread(), and mdwrite().

{
    int         returnCode;

    Assert(FileIsValid(file));

    DO_DB(elog(LOG, "FileSeek: %d (%s) " INT64_FORMAT " " INT64_FORMAT " %d",
               file, VfdCache[file].fileName,
               (int64) VfdCache[file].seekPos,
               (int64) offset, whence));

    if (FileIsNotOpen(file))
    {
        switch (whence)
        {
            case SEEK_SET:
                if (offset < 0)
                    elog(ERROR, "invalid seek offset: " INT64_FORMAT,
                         (int64) offset);
                VfdCache[file].seekPos = offset;
                break;
            case SEEK_CUR:
                VfdCache[file].seekPos += offset;
                break;
            case SEEK_END:
                returnCode = FileAccess(file);
                if (returnCode < 0)
                    return returnCode;
                VfdCache[file].seekPos = lseek(VfdCache[file].fd,
                                               offset, whence);
                break;
            default:
                elog(ERROR, "invalid whence: %d", whence);
                break;
        }
    }
    else
    {
        switch (whence)
        {
            case SEEK_SET:
                if (offset < 0)
                    elog(ERROR, "invalid seek offset: " INT64_FORMAT,
                         (int64) offset);
                if (VfdCache[file].seekPos != offset)
                    VfdCache[file].seekPos = lseek(VfdCache[file].fd,
                                                   offset, whence);
                break;
            case SEEK_CUR:
                if (offset != 0 || VfdCache[file].seekPos == FileUnknownPos)
                    VfdCache[file].seekPos = lseek(VfdCache[file].fd,
                                                   offset, whence);
                break;
            case SEEK_END:
                VfdCache[file].seekPos = lseek(VfdCache[file].fd,
                                               offset, whence);
                break;
            default:
                elog(ERROR, "invalid whence: %d", whence);
                break;
        }
    }
    return VfdCache[file].seekPos;
}

int FileSync ( File  file  ) 

Definition at line 1346 of file fd.c.

References Assert, DO_DB, elog, fd(), FileAccess(), FileIsValid, LOG, and pg_fsync().

Referenced by mdimmedsync(), mdsync(), and register_dirty_segment().

{
    int         returnCode;

    Assert(FileIsValid(file));

    DO_DB(elog(LOG, "FileSync: %d (%s)",
               file, VfdCache[file].fileName));

    returnCode = FileAccess(file);
    if (returnCode < 0)
        return returnCode;

    return pg_fsync(VfdCache[file].fd);
}

int FileTruncate ( File  file,
off_t  offset 
)

Definition at line 1443 of file fd.c.

References Assert, DO_DB, elog, fd(), FD_TEMPORARY, FileAccess(), FileIsValid, vfd::fileSize, ftruncate, LOG, and temporary_files_size.

Referenced by mdtruncate().

{
    int         returnCode;

    Assert(FileIsValid(file));

    DO_DB(elog(LOG, "FileTruncate %d (%s)",
               file, VfdCache[file].fileName));

    returnCode = FileAccess(file);
    if (returnCode < 0)
        return returnCode;

    returnCode = ftruncate(VfdCache[file].fd, offset);

    if (returnCode == 0 && VfdCache[file].fileSize > offset)
    {
        /* adjust our state for truncation of a temp file */
        Assert(VfdCache[file].fdstate & FD_TEMPORARY);
        temporary_files_size -= VfdCache[file].fileSize - offset;
        VfdCache[file].fileSize = offset;
    }

    return returnCode;
}

int FileWrite ( File  file,
char *  buffer,
int  amount 
)

Definition at line 1251 of file fd.c.

References _dosmaperr(), Assert, DO_DB, EINTR, elog, ereport, errcode(), errmsg(), error(), ERROR, fd(), FD_TEMPORARY, FileAccess(), FileIsValid, vfd::fileSize, LOG, pg_usleep(), vfd::seekPos, temp_file_limit, temporary_files_size, and write.

Referenced by BufFileDumpBuffer(), mdextend(), and mdwrite().

{
    int         returnCode;

    Assert(FileIsValid(file));

    DO_DB(elog(LOG, "FileWrite: %d (%s) " INT64_FORMAT " %d %p",
               file, VfdCache[file].fileName,
               (int64) VfdCache[file].seekPos,
               amount, buffer));

    returnCode = FileAccess(file);
    if (returnCode < 0)
        return returnCode;

    /*
     * If enforcing temp_file_limit and it's a temp file, check to see if the
     * write would overrun temp_file_limit, and throw error if so.  Note: it's
     * really a modularity violation to throw error here; we should set errno
     * and return -1.  However, there's no way to report a suitable error
     * message if we do that.  All current callers would just throw error
     * immediately anyway, so this is safe at present.
     */
    if (temp_file_limit >= 0 && (VfdCache[file].fdstate & FD_TEMPORARY))
    {
        off_t       newPos = VfdCache[file].seekPos + amount;

        if (newPos > VfdCache[file].fileSize)
        {
            uint64      newTotal = temporary_files_size;

            newTotal += newPos - VfdCache[file].fileSize;
            if (newTotal > (uint64) temp_file_limit * (uint64) 1024)
                ereport(ERROR,
                        (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
                 errmsg("temporary file size exceeds temp_file_limit (%dkB)",
                        temp_file_limit)));
        }
    }

retry:
    errno = 0;
    returnCode = write(VfdCache[file].fd, buffer, amount);

    /* if write didn't set errno, assume problem is no disk space */
    if (returnCode != amount && errno == 0)
        errno = ENOSPC;

    if (returnCode >= 0)
    {
        VfdCache[file].seekPos += returnCode;

        /* maintain fileSize and temporary_files_size if it's a temp file */
        if (VfdCache[file].fdstate & FD_TEMPORARY)
        {
            off_t       newPos = VfdCache[file].seekPos;

            if (newPos > VfdCache[file].fileSize)
            {
                temporary_files_size += newPos - VfdCache[file].fileSize;
                VfdCache[file].fileSize = newPos;
            }
        }
    }
    else
    {
        /*
         * See comments in FileRead()
         */
#ifdef WIN32
        DWORD       error = GetLastError();

        switch (error)
        {
            case ERROR_NO_SYSTEM_RESOURCES:
                pg_usleep(1000L);
                errno = EINTR;
                break;
            default:
                _dosmaperr(error);
                break;
        }
#endif
        /* OK to retry if interrupted */
        if (errno == EINTR)
            goto retry;

        /* Trouble, so assume we don't know the file position anymore */
        VfdCache[file].seekPos = FileUnknownPos;
    }

    return returnCode;
}

static int FreeDesc ( AllocateDesc desc  )  [static]

Definition at line 1650 of file fd.c.

References AllocateDescDir, AllocateDescFile, AllocateDescPipe, AllocateDescRawFD, close, closedir(), AllocateDesc::desc, AllocateDesc::dir, elog, ERROR, AllocateDesc::fd, AllocateDesc::file, AllocateDesc::kind, and numAllocatedDescs.

Referenced by AtEOSubXact_Files(), CleanupTempFiles(), ClosePipeStream(), CloseTransientFile(), FreeDir(), and FreeFile().

{
    int         result;

    /* Close the underlying object */
    switch (desc->kind)
    {
        case AllocateDescFile:
            result = fclose(desc->desc.file);
            break;
        case AllocateDescPipe:
            result = pclose(desc->desc.file);
            break;
        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 */
            break;
    }

    /* Compact storage in the allocatedDescs array */
    numAllocatedDescs--;
    *desc = allocatedDescs[numAllocatedDescs];

    return result;
}

int FreeDir ( DIR dir  ) 

Definition at line 1854 of file fd.c.

References AllocateDescDir, closedir(), AllocateDesc::desc, AllocateDesc::dir, DO_DB, elog, FreeDesc(), i, AllocateDesc::kind, LOG, numAllocatedDescs, and WARNING.

Referenced by calculate_database_size(), calculate_tablespace_size(), CleanupBackupHistory(), copydir(), db_dir_size(), DeleteAllExportedSnapshotFiles(), destroy_tablespace_directories(), directory_is_empty(), get_available_versions_for_extension(), get_ext_ver_list(), getInstallationPaths(), movedb(), ParseTzFile(), perform_base_backup(), pg_available_extension_versions(), pg_available_extensions(), pg_logdir_ls(), pg_ls_dir(), pg_tablespace_databases(), pg_tzenumerate_end(), pg_tzenumerate_next(), pgarch_readyXlog(), pgstat_reset_remove_files(), PrescanPreparedTransactions(), RecoverPreparedTransactions(), RelationCacheInitFileRemove(), RelationCacheInitFileRemoveInDir(), RemoveOldXlogFiles(), RemovePgTempFiles(), RemovePgTempFilesInDir(), RemovePgTempRelationFiles(), RemovePgTempRelationFilesInDbspace(), ResetUnloggedRelations(), ResetUnloggedRelationsInDbspaceDir(), ResetUnloggedRelationsInTablespaceDir(), scan_directory_ci(), SendBaseBackup(), sendDir(), SlruScanDirectory(), and StandbyRecoverPreparedTransactions().

{
    int         i;

    DO_DB(elog(LOG, "FreeDir: Allocated %d", numAllocatedDescs));

    /* Remove dir from list of allocated dirs, if it's present */
    for (i = numAllocatedDescs; --i >= 0;)
    {
        AllocateDesc *desc = &allocatedDescs[i];

        if (desc->kind == AllocateDescDir && desc->desc.dir == dir)
            return FreeDesc(desc);
    }

    /* Only get here if someone passes us a dir not in allocatedDescs */
    elog(WARNING, "dir passed to FreeDir was not obtained from AllocateDir");

    return closedir(dir);
}

int FreeFile ( FILE *  file  ) 
static void FreeVfd ( File  file  )  [static]

Definition at line 810 of file fd.c.

References DO_DB, elog, vfd::fdstate, vfd::fileName, free, LOG, vfd::nextFree, and NULL.

Referenced by FileClose(), and PathNameOpenFile().

{
    Vfd        *vfdP = &VfdCache[file];

    DO_DB(elog(LOG, "FreeVfd: %d (%s)",
               file, vfdP->fileName ? vfdP->fileName : ""));

    if (vfdP->fileName != NULL)
    {
        free(vfdP->fileName);
        vfdP->fileName = NULL;
    }
    vfdP->fdstate = 0x0;

    vfdP->nextFree = VfdCache[0].nextFree;
    VfdCache[0].nextFree = file;
}

Oid GetNextTempTableSpace ( void   ) 

Definition at line 1975 of file fd.c.

References nextTempTableSpace, numTempTableSpaces, and tempTableSpaces.

Referenced by GetDefaultTablespace(), and OpenTemporaryFile().

{
    if (numTempTableSpaces > 0)
    {
        /* Advance nextTempTableSpace counter with wraparound */
        if (++nextTempTableSpace >= numTempTableSpaces)
            nextTempTableSpace = 0;
        return tempTableSpaces[nextTempTableSpace];
    }
    return InvalidOid;
}

void InitFileAccess ( void   ) 

Definition at line 389 of file fd.c.

References Assert, AtProcExit_Files(), ereport, errcode(), errmsg(), FATAL, vfd::fd, malloc, MemSet, NULL, on_proc_exit(), and SizeVfdCache.

Referenced by BaseInit().

{
    Assert(SizeVfdCache == 0);  /* call me only once */

    /* initialize cache header entry */
    VfdCache = (Vfd *) malloc(sizeof(Vfd));
    if (VfdCache == NULL)
        ereport(FATAL,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("out of memory")));

    MemSet((char *) &(VfdCache[0]), 0, sizeof(Vfd));
    VfdCache->fd = VFD_CLOSED;

    SizeVfdCache = 1;

    /* register proc-exit hook to ensure temp files are dropped at exit */
    on_proc_exit(AtProcExit_Files, 0);
}

static void Insert ( File  file  )  [static]

Definition at line 655 of file fd.c.

References Assert, DO_DB, elog, LOG, vfd::lruLessRecently, and vfd::lruMoreRecently.

Referenced by AdvanceXLInsertBuffer(), CreateCheckPoint(), FileAccess(), GetRedoRecPtr(), GetXLogInsertRecPtr(), LruInsert(), PathNameOpenFile(), UpdateFullPageWrites(), XLogFlush(), and XLogInsert().

{
    Vfd        *vfdP;

    Assert(file != 0);

    DO_DB(elog(LOG, "Insert %d (%s)",
               file, VfdCache[file].fileName));
    DO_DB(_dump_lru());

    vfdP = &VfdCache[file];

    vfdP->lruMoreRecently = 0;
    vfdP->lruLessRecently = VfdCache[0].lruLessRecently;
    VfdCache[0].lruLessRecently = file;
    VfdCache[vfdP->lruLessRecently].lruMoreRecently = file;

    DO_DB(_dump_lru());
}

static bool looks_like_temp_rel_name ( const char *  name  )  [static]

Definition at line 2276 of file fd.c.

References forkname_chars(), and NULL.

Referenced by RemovePgTempRelationFilesInDbspace().

{
    int         pos;
    int         savepos;

    /* Must start with "t". */
    if (name[0] != 't')
        return false;

    /* Followed by a non-empty string of digits and then an underscore. */
    for (pos = 1; isdigit((unsigned char) name[pos]); ++pos)
        ;
    if (pos == 1 || name[pos] != '_')
        return false;

    /* Followed by another nonempty string of digits. */
    for (savepos = ++pos; isdigit((unsigned char) name[pos]); ++pos)
        ;
    if (savepos == pos)
        return false;

    /* We might have _forkname or .segment or both. */
    if (name[pos] == '_')
    {
        int         forkchar = forkname_chars(&name[pos + 1], NULL);

        if (forkchar <= 0)
            return false;
        pos += forkchar + 1;
    }
    if (name[pos] == '.')
    {
        int         segchar;

        for (segchar = 1; isdigit((unsigned char) name[pos + segchar]); ++segchar)
            ;
        if (segchar <= 1)
            return false;
        pos += segchar;
    }

    /* Now we should be at the end. */
    if (name[pos] != '\0')
        return false;
    return true;
}

static void LruDelete ( File  file  )  [static]

Definition at line 628 of file fd.c.

References Assert, close, Delete(), DO_DB, elog, ERROR, vfd::fd, vfd::fileName, LOG, nfile, and vfd::seekPos.

Referenced by closeAllVfds(), and ReleaseLruFile().

{
    Vfd        *vfdP;

    Assert(file != 0);

    DO_DB(elog(LOG, "LruDelete %d (%s)",
               file, VfdCache[file].fileName));

    vfdP = &VfdCache[file];

    /* delete the vfd record from the LRU ring */
    Delete(file);

    /* save the seek position */
    vfdP->seekPos = lseek(vfdP->fd, (off_t) 0, SEEK_CUR);
    Assert(vfdP->seekPos != (off_t) -1);

    /* close the file */
    if (close(vfdP->fd))
        elog(ERROR, "could not close file \"%s\": %m", vfdP->fileName);

    --nfile;
    vfdP->fd = VFD_CLOSED;
}

static int LruInsert ( File  file  )  [static]

Definition at line 677 of file fd.c.

References Assert, BasicOpenFile(), DO_DB, elog, vfd::fd, vfd::fileFlags, FileIsNotOpen, vfd::fileMode, vfd::fileName, Insert(), LOG, max_safe_fds, nfile, numAllocatedDescs, ReleaseLruFile(), and vfd::seekPos.

Referenced by FileAccess().

{
    Vfd        *vfdP;

    Assert(file != 0);

    DO_DB(elog(LOG, "LruInsert %d (%s)",
               file, VfdCache[file].fileName));

    vfdP = &VfdCache[file];

    if (FileIsNotOpen(file))
    {
        while (nfile + numAllocatedDescs >= max_safe_fds)
        {
            if (!ReleaseLruFile())
                break;
        }

        /*
         * The open could still fail for lack of file descriptors, eg due to
         * overall system file table being full.  So, be prepared to release
         * another FD if necessary...
         */
        vfdP->fd = BasicOpenFile(vfdP->fileName, vfdP->fileFlags,
                                 vfdP->fileMode);
        if (vfdP->fd < 0)
        {
            DO_DB(elog(LOG, "RE_OPEN FAILED: %d", errno));
            return vfdP->fd;
        }
        else
        {
            DO_DB(elog(LOG, "RE_OPEN SUCCESS"));
            ++nfile;
        }

        /* seek to the right position */
        if (vfdP->seekPos != (off_t) 0)
        {
            off_t returnValue PG_USED_FOR_ASSERTS_ONLY;

            returnValue = lseek(vfdP->fd, vfdP->seekPos, SEEK_SET);
            Assert(returnValue != (off_t) -1);
        }
    }

    /*
     * put it at the head of the Lru ring
     */

    Insert(file);

    return 0;
}

FILE* OpenPipeStream ( const char *  command,
const char *  mode 
)

Definition at line 1595 of file fd.c.

References AllocateDesc::create_subid, AllocateDesc::desc, DO_DB, elog, ereport, errcode(), errmsg(), ERROR, AllocateDesc::file, GetCurrentSubTransactionId(), AllocateDesc::kind, LOG, MAX_ALLOCATED_DESCS, max_safe_fds, NULL, numAllocatedDescs, and ReleaseLruFile().

Referenced by BeginCopyFrom(), and BeginCopyTo().

{
    FILE       *file;

    DO_DB(elog(LOG, "OpenPipeStream: Allocated %d (%s)",
               numAllocatedDescs, command));

    /*
     * The test against MAX_ALLOCATED_DESCS prevents us from overflowing
     * allocatedFiles[]; the test against max_safe_fds prevents AllocateFile
     * 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 execute command \"%s\"",
             command);

TryAgain:
    fflush(stdout);
    fflush(stderr);
    errno = 0;
    if ((file = popen(command, mode)) != NULL)
    {
        AllocateDesc *desc = &allocatedDescs[numAllocatedDescs];

        desc->kind = AllocateDescPipe;
        desc->desc.file = file;
        desc->create_subid = GetCurrentSubTransactionId();
        numAllocatedDescs++;
        return desc->desc.file;
    }

    if (errno == EMFILE || errno == ENFILE)
    {
        int         save_errno = errno;

        ereport(LOG,
                (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
                 errmsg("out of file descriptors: %m; release and retry")));
        errno = 0;
        if (ReleaseLruFile())
            goto TryAgain;
        errno = save_errno;
    }

    return NULL;
}

File OpenTemporaryFile ( bool  interXact  ) 

Definition at line 951 of file fd.c.

References CurrentResourceOwner, DEFAULTTABLESPACE_OID, vfd::fdstate, GetNextTempTableSpace(), have_xact_temporary_files, MyDatabaseTableSpace, numTempTableSpaces, OidIsValid, OpenTemporaryFileInTablespace(), ResourceOwnerEnlargeFiles(), ResourceOwnerRememberFile(), and vfd::resowner.

Referenced by BufFileCreateTemp(), and extendBufFile().

{
    File        file = 0;

    /*
     * If some temp tablespace(s) have been given to us, try to use the next
     * one.  If a given tablespace can't be found, we silently fall back to
     * the database's default tablespace.
     *
     * BUT: if the temp file is slated to outlive the current transaction,
     * force it into the database's default tablespace, so that it will not
     * pose a threat to possible tablespace drop attempts.
     */
    if (numTempTableSpaces > 0 && !interXact)
    {
        Oid         tblspcOid = GetNextTempTableSpace();

        if (OidIsValid(tblspcOid))
            file = OpenTemporaryFileInTablespace(tblspcOid, false);
    }

    /*
     * If not, or if tablespace is bad, create in database's default
     * tablespace.  MyDatabaseTableSpace should normally be set before we get
     * here, but just in case it isn't, fall back to pg_default tablespace.
     */
    if (file <= 0)
        file = OpenTemporaryFileInTablespace(MyDatabaseTableSpace ?
                                             MyDatabaseTableSpace :
                                             DEFAULTTABLESPACE_OID,
                                             true);

    /* Mark it for deletion at close */
    VfdCache[file].fdstate |= FD_TEMPORARY;

    /* Register it with the current resource owner */
    if (!interXact)
    {
        VfdCache[file].fdstate |= FD_XACT_TEMPORARY;

        ResourceOwnerEnlargeFiles(CurrentResourceOwner);
        ResourceOwnerRememberFile(CurrentResourceOwner, file);
        VfdCache[file].resowner = CurrentResourceOwner;

        /* ensure cleanup happens at eoxact */
        have_xact_temporary_files = true;
    }

    return file;
}

static File OpenTemporaryFileInTablespace ( Oid  tblspcOid,
bool  rejectError 
) [static]

Definition at line 1007 of file fd.c.

References DEFAULTTABLESPACE_OID, elog, ERROR, GLOBALTABLESPACE_OID, mkdir, MyProcPid, PathNameOpenFile(), PG_BINARY, PG_TEMP_FILE_PREFIX, PG_TEMP_FILES_DIR, snprintf(), TABLESPACE_VERSION_DIRECTORY, and tempFileCounter.

Referenced by OpenTemporaryFile().

{
    char        tempdirpath[MAXPGPATH];
    char        tempfilepath[MAXPGPATH];
    File        file;

    /*
     * Identify the tempfile directory for this tablespace.
     *
     * If someone tries to specify pg_global, use pg_default instead.
     */
    if (tblspcOid == DEFAULTTABLESPACE_OID ||
        tblspcOid == GLOBALTABLESPACE_OID)
    {
        /* The default tablespace is {datadir}/base */
        snprintf(tempdirpath, sizeof(tempdirpath), "base/%s",
                 PG_TEMP_FILES_DIR);
    }
    else
    {
        /* All other tablespaces are accessed via symlinks */
        snprintf(tempdirpath, sizeof(tempdirpath), "pg_tblspc/%u/%s/%s",
                 tblspcOid, TABLESPACE_VERSION_DIRECTORY, PG_TEMP_FILES_DIR);
    }

    /*
     * Generate a tempfile name that should be unique within the current
     * database instance.
     */
    snprintf(tempfilepath, sizeof(tempfilepath), "%s/%s%d.%ld",
             tempdirpath, PG_TEMP_FILE_PREFIX, MyProcPid, tempFileCounter++);

    /*
     * Open the file.  Note: we don't use O_EXCL, in case there is an orphaned
     * temp file that can be reused.
     */
    file = PathNameOpenFile(tempfilepath,
                            O_RDWR | O_CREAT | O_TRUNC | PG_BINARY,
                            0600);
    if (file <= 0)
    {
        /*
         * We might need to create the tablespace's tempfile directory, if no
         * one has yet done so.
         *
         * Don't check for error from mkdir; it could fail if someone else
         * just did the same thing.  If it doesn't work then we'll bomb out on
         * the second create attempt, instead.
         */
        mkdir(tempdirpath, S_IRWXU);

        file = PathNameOpenFile(tempfilepath,
                                O_RDWR | O_CREAT | O_TRUNC | PG_BINARY,
                                0600);
        if (file <= 0 && rejectError)
            elog(ERROR, "could not create temporary file \"%s\": %m",
                 tempfilepath);
    }

    return file;
}

int OpenTransientFile ( FileName  fileName,
int  fileFlags,
int  fileMode 
)

Definition at line 1553 of file fd.c.

References BasicOpenFile(), AllocateDesc::create_subid, AllocateDesc::desc, DO_DB, elog, ERROR, AllocateDesc::fd, GetCurrentSubTransactionId(), AllocateDesc::kind, LOG, MAX_ALLOCATED_DESCS, max_safe_fds, and numAllocatedDescs.

Referenced by CheckPointTwoPhase(), copy_file(), EndPrepare(), fsync_fname(), lo_export(), lo_import_internal(), load_relmap_file(), mdunlinkfork(), ReadTwoPhaseFile(), RecreateTwoPhaseFile(), SendTimeLineHistory(), SlruPhysicalReadPage(), SlruPhysicalWritePage(), write_relmap_file(), writeTimeLineHistory(), writeTimeLineHistoryFile(), and XLogFileCopy().

{
    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 */
}

File PathNameOpenFile ( FileName  fileName,
int  fileFlags,
int  fileMode 
)

Definition at line 883 of file fd.c.

References AllocateVfd(), BasicOpenFile(), DO_DB, elog, ereport, errcode(), errmsg(), ERROR, vfd::fd, vfd::fdstate, vfd::fileFlags, vfd::fileMode, vfd::fileName, vfd::fileSize, free, FreeVfd(), Insert(), LOG, max_safe_fds, nfile, NULL, numAllocatedDescs, ReleaseLruFile(), vfd::resowner, and vfd::seekPos.

Referenced by _mdfd_openseg(), mdcreate(), mdopen(), and OpenTemporaryFileInTablespace().

{
    char       *fnamecopy;
    File        file;
    Vfd        *vfdP;

    DO_DB(elog(LOG, "PathNameOpenFile: %s %x %o",
               fileName, fileFlags, fileMode));

    /*
     * We need a malloc'd copy of the file name; fail cleanly if no room.
     */
    fnamecopy = strdup(fileName);
    if (fnamecopy == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("out of memory")));

    file = AllocateVfd();
    vfdP = &VfdCache[file];

    while (nfile + numAllocatedDescs >= max_safe_fds)
    {
        if (!ReleaseLruFile())
            break;
    }

    vfdP->fd = BasicOpenFile(fileName, fileFlags, fileMode);

    if (vfdP->fd < 0)
    {
        FreeVfd(file);
        free(fnamecopy);
        return -1;
    }
    ++nfile;
    DO_DB(elog(LOG, "PathNameOpenFile: success %d",
               vfdP->fd));

    Insert(file);

    vfdP->fileName = fnamecopy;
    /* Saved flags are adjusted to be OK for re-opening file */
    vfdP->fileFlags = fileFlags & ~(O_CREAT | O_TRUNC | O_EXCL);
    vfdP->fileMode = fileMode;
    vfdP->seekPos = 0;
    vfdP->fileSize = 0;
    vfdP->fdstate = 0x0;
    vfdP->resowner = NULL;

    return file;
}

int pg_fdatasync ( int  fd  ) 

Definition at line 345 of file fd.c.

References enableFsync, and fsync.

Referenced by issue_xlog_fsync().

{
    if (enableFsync)
    {
#ifdef HAVE_FDATASYNC
        return fdatasync(fd);
#else
        return fsync(fd);
#endif
    }
    else
        return 0;
}

int pg_flush_data ( int  fd,
off_t  offset,
off_t  amount 
)

Definition at line 368 of file fd.c.

References enableFsync.

Referenced by copy_file().

{
    if (enableFsync)
    {
#if defined(HAVE_SYNC_FILE_RANGE)
        return sync_file_range(fd, offset, amount, SYNC_FILE_RANGE_WRITE);
#elif defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
        return posix_fadvise(fd, offset, amount, POSIX_FADV_DONTNEED);
#endif
    }
    return 0;
}

int pg_fsync ( int  fd  ) 
int pg_fsync_no_writethrough ( int  fd  ) 

Definition at line 310 of file fd.c.

References enableFsync, and fsync.

Referenced by issue_xlog_fsync(), and pg_fsync().

{
    if (enableFsync)
        return fsync(fd);
    else
        return 0;
}

int pg_fsync_writethrough ( int  fd  ) 

Definition at line 322 of file fd.c.

References enableFsync.

Referenced by issue_xlog_fsync(), pg_fsync(), and test_sync().

{
    if (enableFsync)
    {
#ifdef WIN32
        return _commit(fd);
#elif defined(F_FULLFSYNC)
        return (fcntl(fd, F_FULLFSYNC, 0) == -1) ? -1 : 0;
#else
        errno = ENOSYS;
        return -1;
#endif
    }
    else
        return 0;
}

struct dirent* ReadDir ( DIR dir,
const char *  dirname 
) [read]

Definition at line 1814 of file fd.c.

References ereport, errcode_for_file_access(), errmsg(), ERROR, NULL, and readdir().

Referenced by calculate_database_size(), calculate_tablespace_size(), CleanupBackupHistory(), copydir(), db_dir_size(), DeleteAllExportedSnapshotFiles(), destroy_tablespace_directories(), directory_is_empty(), get_available_versions_for_extension(), get_ext_ver_list(), movedb(), perform_base_backup(), pg_available_extension_versions(), pg_available_extensions(), pg_logdir_ls(), pg_ls_dir(), pg_tablespace_databases(), pg_tzenumerate_next(), pgarch_readyXlog(), pgstat_reset_remove_files(), PrescanPreparedTransactions(), RecoverPreparedTransactions(), RelationCacheInitFileRemove(), RelationCacheInitFileRemoveInDir(), RemoveOldXlogFiles(), RemovePgTempFiles(), RemovePgTempFilesInDir(), RemovePgTempRelationFiles(), RemovePgTempRelationFilesInDbspace(), ResetUnloggedRelations(), ResetUnloggedRelationsInDbspaceDir(), ResetUnloggedRelationsInTablespaceDir(), scan_directory_ci(), sendDir(), SlruScanDirectory(), and StandbyRecoverPreparedTransactions().

{
    struct dirent *dent;

    /* Give a generic message for AllocateDir failure, if caller didn't */
    if (dir == NULL)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not open directory \"%s\": %m",
                        dirname)));

    errno = 0;
    if ((dent = readdir(dir)) != NULL)
        return dent;

#ifdef WIN32

    /*
     * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
     * released version
     */
    if (GetLastError() == ERROR_NO_MORE_FILES)
        errno = 0;
#endif

    if (errno)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not read directory \"%s\": %m",
                        dirname)));
    return NULL;
}

static bool ReleaseLruFile ( void   )  [static]

Definition at line 734 of file fd.c.

References Assert, DO_DB, elog, LOG, LruDelete(), and nfile.

Referenced by AllocateDir(), AllocateFile(), BasicOpenFile(), LruInsert(), OpenPipeStream(), and PathNameOpenFile().

{
    DO_DB(elog(LOG, "ReleaseLruFile. Opened %d", nfile));

    if (nfile > 0)
    {
        /*
         * There are opened files and so there should be at least one used vfd
         * in the ring.
         */
        Assert(VfdCache[0].lruMoreRecently != 0);
        LruDelete(VfdCache[0].lruMoreRecently);
        return true;            /* freed a file */
    }
    return false;               /* no files available to free */
}

void RemovePgTempFiles ( void   ) 

Definition at line 2116 of file fd.c.

References AllocateDir(), dirent::d_name, FreeDir(), NULL, PG_TEMP_FILES_DIR, ReadDir(), RemovePgTempFilesInDir(), RemovePgTempRelationFiles(), snprintf(), and TABLESPACE_VERSION_DIRECTORY.

Referenced by PostmasterMain().

{
    char        temp_path[MAXPGPATH];
    DIR        *spc_dir;
    struct dirent *spc_de;

    /*
     * First process temp files in pg_default ($PGDATA/base)
     */
    snprintf(temp_path, sizeof(temp_path), "base/%s", PG_TEMP_FILES_DIR);
    RemovePgTempFilesInDir(temp_path);
    RemovePgTempRelationFiles("base");

    /*
     * Cycle through temp directories for all non-default tablespaces.
     */
    spc_dir = AllocateDir("pg_tblspc");

    while ((spc_de = ReadDir(spc_dir, "pg_tblspc")) != NULL)
    {
        if (strcmp(spc_de->d_name, ".") == 0 ||
            strcmp(spc_de->d_name, "..") == 0)
            continue;

        snprintf(temp_path, sizeof(temp_path), "pg_tblspc/%s/%s/%s",
            spc_de->d_name, TABLESPACE_VERSION_DIRECTORY, PG_TEMP_FILES_DIR);
        RemovePgTempFilesInDir(temp_path);

        snprintf(temp_path, sizeof(temp_path), "pg_tblspc/%s/%s",
                 spc_de->d_name, TABLESPACE_VERSION_DIRECTORY);
        RemovePgTempRelationFiles(temp_path);
    }

    FreeDir(spc_dir);

    /*
     * In EXEC_BACKEND case there is a pgsql_tmp directory at the top level of
     * DataDir as well.
     */
#ifdef EXEC_BACKEND
    RemovePgTempFilesInDir(PG_TEMP_FILES_DIR);
#endif
}

static void RemovePgTempFilesInDir ( const char *  tmpdirname  )  [static]

Definition at line 2162 of file fd.c.

References AllocateDir(), dirent::d_name, elog, FreeDir(), LOG, NULL, PG_TEMP_FILE_PREFIX, ReadDir(), snprintf(), and unlink().

Referenced by RemovePgTempFiles().

{
    DIR        *temp_dir;
    struct dirent *temp_de;
    char        rm_path[MAXPGPATH];

    temp_dir = AllocateDir(tmpdirname);
    if (temp_dir == NULL)
    {
        /* anything except ENOENT is fishy */
        if (errno != ENOENT)
            elog(LOG,
                 "could not open temporary-files directory \"%s\": %m",
                 tmpdirname);
        return;
    }

    while ((temp_de = ReadDir(temp_dir, tmpdirname)) != NULL)
    {
        if (strcmp(temp_de->d_name, ".") == 0 ||
            strcmp(temp_de->d_name, "..") == 0)
            continue;

        snprintf(rm_path, sizeof(rm_path), "%s/%s",
                 tmpdirname, temp_de->d_name);

        if (strncmp(temp_de->d_name,
                    PG_TEMP_FILE_PREFIX,
                    strlen(PG_TEMP_FILE_PREFIX)) == 0)
            unlink(rm_path);    /* note we ignore any error */
        else
            elog(LOG,
                 "unexpected file found in temporary-files directory: \"%s\"",
                 rm_path);
    }

    FreeDir(temp_dir);
}

static void RemovePgTempRelationFiles ( const char *  tsdirname  )  [static]

Definition at line 2203 of file fd.c.

References AllocateDir(), dirent::d_name, elog, FreeDir(), i, LOG, NULL, ReadDir(), RemovePgTempRelationFilesInDbspace(), and snprintf().

Referenced by RemovePgTempFiles().

{
    DIR        *ts_dir;
    struct dirent *de;
    char        dbspace_path[MAXPGPATH];

    ts_dir = AllocateDir(tsdirname);
    if (ts_dir == NULL)
    {
        /* anything except ENOENT is fishy */
        if (errno != ENOENT)
            elog(LOG,
                 "could not open tablespace directory \"%s\": %m",
                 tsdirname);
        return;
    }

    while ((de = ReadDir(ts_dir, tsdirname)) != NULL)
    {
        int         i = 0;

        /*
         * We're only interested in the per-database directories, which have
         * numeric names.  Note that this code will also (properly) ignore "."
         * and "..".
         */
        while (isdigit((unsigned char) de->d_name[i]))
            ++i;
        if (de->d_name[i] != '\0' || i == 0)
            continue;

        snprintf(dbspace_path, sizeof(dbspace_path), "%s/%s",
                 tsdirname, de->d_name);
        RemovePgTempRelationFilesInDbspace(dbspace_path);
    }

    FreeDir(ts_dir);
}

static void RemovePgTempRelationFilesInDbspace ( const char *  dbspacedirname  )  [static]

Definition at line 2244 of file fd.c.

References AllocateDir(), dirent::d_name, elog, FreeDir(), LOG, looks_like_temp_rel_name(), NULL, ReadDir(), snprintf(), and unlink().

Referenced by RemovePgTempRelationFiles().

{
    DIR        *dbspace_dir;
    struct dirent *de;
    char        rm_path[MAXPGPATH];

    dbspace_dir = AllocateDir(dbspacedirname);
    if (dbspace_dir == NULL)
    {
        /* we just saw this directory, so it really ought to be there */
        elog(LOG,
             "could not open dbspace directory \"%s\": %m",
             dbspacedirname);
        return;
    }

    while ((de = ReadDir(dbspace_dir, dbspacedirname)) != NULL)
    {
        if (!looks_like_temp_rel_name(de->d_name))
            continue;

        snprintf(rm_path, sizeof(rm_path), "%s/%s",
                 dbspacedirname, de->d_name);

        unlink(rm_path);        /* note we ignore any error */
    }

    FreeDir(dbspace_dir);
}

void set_max_safe_fds ( void   ) 

Definition at line 506 of file fd.c.

References count_usable_fds(), DEBUG2, elog, ereport, errcode(), errdetail(), errmsg(), FATAL, FD_MINFREE, max_files_per_process, max_safe_fds, Min, and NUM_RESERVED_FDS.

Referenced by PostmasterMain().

{
    int         usable_fds;
    int         already_open;

    /*----------
     * We want to set max_safe_fds to
     *          MIN(usable_fds, max_files_per_process - already_open)
     * less the slop factor for files that are opened without consulting
     * fd.c.  This ensures that we won't exceed either max_files_per_process
     * or the experimentally-determined EMFILE limit.
     *----------
     */
    count_usable_fds(max_files_per_process,
                     &usable_fds, &already_open);

    max_safe_fds = Min(usable_fds, max_files_per_process - already_open);

    /*
     * Take off the FDs reserved for system() etc.
     */
    max_safe_fds -= NUM_RESERVED_FDS;

    /*
     * Make sure we still have enough to get by.
     */
    if (max_safe_fds < FD_MINFREE)
        ereport(FATAL,
                (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
                 errmsg("insufficient file descriptors available to start server process"),
                 errdetail("System allows %d, we need at least %d.",
                           max_safe_fds + NUM_RESERVED_FDS,
                           FD_MINFREE + NUM_RESERVED_FDS)));

    elog(DEBUG2, "max_safe_fds = %d, usable_fds = %d, already_open = %d",
         max_safe_fds, usable_fds, already_open);
}

void SetTempTablespaces ( Oid tableSpaces,
int  numSpaces 
)

Definition at line 1935 of file fd.c.

References Assert, nextTempTableSpace, numTempTableSpaces, random(), and tempTableSpaces.

Referenced by assign_temp_tablespaces(), and PrepareTempTablespaces().

{
    Assert(numSpaces >= 0);
    tempTableSpaces = tableSpaces;
    numTempTableSpaces = numSpaces;

    /*
     * Select a random starting point in the list.  This is to minimize
     * conflicts between backends that are most likely sharing the same list
     * of temp tablespaces.  Note that if we create multiple temp files in the
     * same transaction, we'll advance circularly through the list --- this
     * ensures that large temporary sort files are nicely spread across all
     * available tablespaces.
     */
    if (numSpaces > 1)
        nextTempTableSpace = random() % numSpaces;
    else
        nextTempTableSpace = 0;
}

bool TempTablespacesAreSet ( void   ) 

Definition at line 1963 of file fd.c.

References numTempTableSpaces.

Referenced by PrepareTempTablespaces().

{
    return (numTempTableSpaces >= 0);
}


Variable Documentation

AllocateDesc allocatedDescs[MAX_ALLOCATED_DESCS] [static]

Definition at line 223 of file fd.c.

bool have_xact_temporary_files = false [static]

Definition at line 182 of file fd.c.

Referenced by CleanupTempFiles(), and OpenTemporaryFile().

Definition at line 112 of file fd.c.

Referenced by set_max_safe_fds().

int max_safe_fds = 32
int nextTempTableSpace = 0 [static]

Definition at line 237 of file fd.c.

Referenced by GetNextTempTableSpace(), and SetTempTablespaces().

int nfile = 0 [static]

Definition at line 176 of file fd.c.

Referenced by FileClose(), LruDelete(), LruInsert(), PathNameOpenFile(), and ReleaseLruFile().

int numAllocatedDescs = 0 [static]
int numTempTableSpaces = -1 [static]
Size SizeVfdCache = 0 [static]

Definition at line 171 of file fd.c.

Referenced by AllocateVfd(), CleanupTempFiles(), closeAllVfds(), and InitFileAccess().

long tempFileCounter = 0 [static]

Definition at line 229 of file fd.c.

Referenced by OpenTemporaryFileInTablespace().

uint64 temporary_files_size = 0 [static]

Definition at line 190 of file fd.c.

Referenced by FileClose(), FileTruncate(), and FileWrite().

Oid* tempTableSpaces = NULL [static]

Definition at line 235 of file fd.c.

Referenced by AtEOXact_Files(), GetNextTempTableSpace(), and SetTempTablespaces().

Vfd* VfdCache [static]

Definition at line 170 of file fd.c.