#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"
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) |
DIR * | AllocateDir (const char *dirname) |
struct dirent * | ReadDir (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 Vfd * | VfdCache |
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 Oid * | tempTableSpaces = NULL |
static int | numTempTableSpaces = -1 |
static int | nextTempTableSpace = 0 |
#define DO_DB | ( | A | ) |
Definition at line 133 of file fd.c.
Referenced by AllocateDir(), AllocateFile(), AllocateVfd(), ClosePipeStream(), CloseTransientFile(), Delete(), FileAccess(), FileClose(), FilePrefetch(), FileRead(), FileSeek(), FileSync(), FileTruncate(), FileWrite(), FreeDir(), FreeFile(), FreeVfd(), Insert(), LruDelete(), LruInsert(), OpenPipeStream(), OpenTransientFile(), PathNameOpenFile(), and ReleaseLruFile().
#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) |
Definition at line 138 of file fd.c.
Referenced by FileClose(), FilePathName(), FilePrefetch(), FileRead(), FileSeek(), FileSync(), FileTruncate(), and FileWrite().
#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().
enum AllocateDescKind |
Definition at line 202 of file fd.c.
{ AllocateDescFile, AllocateDescPipe, AllocateDescDir, AllocateDescRawFD } AllocateDescKind;
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 | ) |
Definition at line 2027 of file fd.c.
References CleanupTempFiles(), numTempTableSpaces, and tempTableSpaces.
Referenced by AbortTransaction(), BackgroundWriterMain(), CheckpointerMain(), CommitTransaction(), PrepareTransaction(), and WalWriterMain().
{ CleanupTempFiles(false); tempTableSpaces = NULL; numTempTableSpaces = -1; }
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 | ) |
Definition at line 1689 of file fd.c.
References AllocateDescFile, AllocateDesc::desc, DO_DB, elog, AllocateDesc::file, FreeDesc(), i, AllocateDesc::kind, LOG, numAllocatedDescs, and WARNING.
Referenced by checkDataDir(), do_pg_start_backup(), do_pg_stop_backup(), EndCopy(), 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_end(), ValidatePgVersion(), write_relcache_init_file(), XLogArchiveForceDone(), and XLogArchiveNotify().
{ int i; DO_DB(elog(LOG, "FreeFile: 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 == AllocateDescFile && desc->desc.file == file) return FreeDesc(desc); } /* Only get here if someone passes us a file not in allocatedDescs */ elog(WARNING, "file passed to FreeFile was not obtained from AllocateFile"); return fclose(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().
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; }
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; }
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 */ }
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 | ) |
Definition at line 293 of file fd.c.
References pg_fsync_no_writethrough(), pg_fsync_writethrough(), sync_method, and SYNC_METHOD_FSYNC_WRITETHROUGH.
Referenced by AddToDataDirLockFile(), assign_xlog_sync_method(), BootStrapXLOG(), CheckPointTwoPhase(), CreateLockFile(), do_pg_start_backup(), FileSync(), fsync_fname(), RecreateTwoPhaseFile(), SimpleLruFlush(), SlruPhysicalWritePage(), UpdateControlFile(), write_relmap_file(), WriteControlFile(), writeTimeLineHistory(), writeTimeLineHistoryFile(), XLogFileCopy(), and XLogFileInit().
{ /* #if is to skip the sync_method test if there's no need for it */ #if defined(HAVE_FSYNC_WRITETHROUGH) && !defined(FSYNC_WRITETHROUGH_IS_FSYNC) if (sync_method == SYNC_METHOD_FSYNC_WRITETHROUGH) return pg_fsync_writethrough(fd); else #endif return pg_fsync_no_writethrough(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; }
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); }
AllocateDesc allocatedDescs[MAX_ALLOCATED_DESCS] [static] |
bool have_xact_temporary_files = false [static] |
Definition at line 182 of file fd.c.
Referenced by CleanupTempFiles(), and OpenTemporaryFile().
int max_files_per_process = 1000 |
Definition at line 112 of file fd.c.
Referenced by set_max_safe_fds().
int max_safe_fds = 32 |
Definition at line 125 of file fd.c.
Referenced by AllocateDir(), AllocateFile(), LruInsert(), OpenPipeStream(), OpenTransientFile(), PathNameOpenFile(), and set_max_safe_fds().
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] |
Definition at line 222 of file fd.c.
Referenced by AllocateDir(), AllocateFile(), AtEOSubXact_Files(), CleanupTempFiles(), ClosePipeStream(), CloseTransientFile(), FreeDesc(), FreeDir(), FreeFile(), LruInsert(), OpenPipeStream(), OpenTransientFile(), and PathNameOpenFile().
int numTempTableSpaces = -1 [static] |
Definition at line 236 of file fd.c.
Referenced by AtEOXact_Files(), GetNextTempTableSpace(), OpenTemporaryFile(), SetTempTablespaces(), and TempTablespacesAreSet().
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().