Header And Logo

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

Defines | Typedefs | Functions | Variables

fd.h File Reference

#include <dirent.h>
Include dependency graph for fd.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Defines

#define PG_TEMP_FILES_DIR   "pgsql_tmp"
#define PG_TEMP_FILE_PREFIX   "pgsql_tmp"

Typedefs

typedef char * FileName
typedef int File

Functions

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 FreeFile (FILE *file)
FILE * OpenPipeStream (const char *command, const char *mode)
int ClosePipeStream (FILE *file)
DIRAllocateDir (const char *dirname)
struct direntReadDir (DIR *dir, const char *dirname)
int FreeDir (DIR *dir)
int OpenTransientFile (FileName fileName, int fileFlags, int fileMode)
int CloseTransientFile (int fd)
int BasicOpenFile (FileName fileName, int fileFlags, int fileMode)
void InitFileAccess (void)
void set_max_safe_fds (void)
void closeAllVfds (void)
void SetTempTablespaces (Oid *tableSpaces, int numSpaces)
bool TempTablespacesAreSet (void)
Oid GetNextTempTableSpace (void)
void AtEOXact_Files (void)
void AtEOSubXact_Files (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
void RemovePgTempFiles (void)
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)

Variables

int max_files_per_process
int max_safe_fds

Define Documentation

#define PG_TEMP_FILE_PREFIX   "pgsql_tmp"

Definition at line 119 of file fd.h.

Referenced by OpenTemporaryFileInTablespace(), RemovePgTempFilesInDir(), and sendDir().

#define PG_TEMP_FILES_DIR   "pgsql_tmp"

Definition at line 118 of file fd.h.

Referenced by OpenTemporaryFileInTablespace(), and RemovePgTempFiles().


Typedef Documentation

typedef int File

Definition at line 51 of file fd.h.

typedef char* FileName

Definition at line 49 of file fd.h.


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

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

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

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

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

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

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

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
}

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

Definition at line 112 of file fd.c.

Referenced by set_max_safe_fds().