diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/access/transam/twophase.c | 2 | ||||
-rw-r--r-- | src/backend/access/transam/xlog.c | 8 | ||||
-rw-r--r-- | src/backend/storage/file/fd.c | 32 | ||||
-rw-r--r-- | src/include/storage/fd.h | 2 |
4 files changed, 35 insertions, 9 deletions
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index ae832917ce2..2b3032bde98 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -1735,8 +1735,8 @@ restoreTwoPhaseData(void) DIR *cldir; struct dirent *clde; - cldir = AllocateDir(TWOPHASE_DIR); LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE); + cldir = AllocateDir(TWOPHASE_DIR); while ((clde = ReadDir(cldir, TWOPHASE_DIR)) != NULL) { if (strlen(clde->d_name) == 8 && diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index a63a8853ee3..615ce5c7fd0 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -3760,10 +3760,16 @@ PreallocXlogFiles(XLogRecPtr endptr) * existed while the server has been running, as this function always * succeeds if no WAL segments have been removed since startup. * 'tli' is only used in the error message. + * + * Note: this function guarantees to keep errno unchanged on return. + * This supports callers that use this to possibly deliver a better + * error message about a missing file, while still being able to throw + * a normal file-access error afterwards, if this does return. */ void CheckXLogRemoved(XLogSegNo segno, TimeLineID tli) { + int save_errno = errno; XLogSegNo lastRemovedSegNo; SpinLockAcquire(&XLogCtl->info_lck); @@ -3775,11 +3781,13 @@ CheckXLogRemoved(XLogSegNo segno, TimeLineID tli) char filename[MAXFNAMELEN]; XLogFileName(filename, tli, segno); + errno = save_errno; ereport(ERROR, (errcode_for_file_access(), errmsg("requested WAL segment %s has already been removed", filename))); } + errno = save_errno; } /* diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index 594251da422..3172092a914 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -304,7 +304,6 @@ static int FileAccess(File file); static File OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError); static bool reserveAllocatedDesc(void); static int FreeDesc(AllocateDesc *desc); -static struct dirent *ReadDirExtended(DIR *dir, const char *dirname, int elevel); static void AtProcExit_Files(int code, Datum arg); static void CleanupTempFiles(bool isProcExit); @@ -2335,6 +2334,10 @@ CloseTransientFile(int fd) * necessary to open the directory, and with closing it after an elog. * When done, call FreeDir rather than closedir. * + * Returns NULL, with errno set, on failure. Note that failure detection + * is commonly left to the following call of ReadDir or ReadDirExtended; + * see the comments for ReadDir. + * * Ideally this should be the *only* direct call of opendir() in the backend. */ DIR * @@ -2397,8 +2400,8 @@ TryAgain: * FreeDir(dir); * * since a NULL dir parameter is taken as indicating AllocateDir failed. - * (Make sure errno hasn't been changed since AllocateDir if you use this - * shortcut.) + * (Make sure errno isn't changed between AllocateDir and ReadDir if you + * use this shortcut.) * * The pathname passed to AllocateDir must be passed to this routine too, * but it is only used for error reporting. @@ -2410,10 +2413,15 @@ ReadDir(DIR *dir, const char *dirname) } /* - * Alternate version that allows caller to specify the elevel for any - * error report. If elevel < ERROR, returns NULL on any error. + * Alternate version of ReadDir that allows caller to specify the elevel + * for any error report (whether it's reporting an initial failure of + * AllocateDir or a subsequent directory read failure). + * + * If elevel < ERROR, returns NULL after any error. With the normal coding + * pattern, this will result in falling out of the loop immediately as + * though the directory contained no (more) entries. */ -static struct dirent * +struct dirent * ReadDirExtended(DIR *dir, const char *dirname, int elevel) { struct dirent *dent; @@ -2443,14 +2451,22 @@ ReadDirExtended(DIR *dir, const char *dirname, int elevel) /* * Close a directory opened with AllocateDir. * - * Note we do not check closedir's return value --- it is up to the caller - * to handle close errors. + * Returns closedir's return value (with errno set if it's not 0). + * Note we do not check the return value --- it is up to the caller + * to handle close errors if wanted. + * + * Does nothing if dir == NULL; we assume that directory open failure was + * already reported if desired. */ int FreeDir(DIR *dir) { int i; + /* Nothing to do if AllocateDir failed */ + if (dir == NULL) + return 0; + DO_DB(elog(LOG, "FreeDir: Allocated %d", numAllocatedDescs)); /* Remove dir from list of allocated dirs, if it's present */ diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index faef39e78d3..87265400776 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -91,6 +91,8 @@ extern int ClosePipeStream(FILE *file); /* Operations to allow use of the <dirent.h> library routines */ extern DIR *AllocateDir(const char *dirname); extern struct dirent *ReadDir(DIR *dir, const char *dirname); +extern struct dirent *ReadDirExtended(DIR *dir, const char *dirname, + int elevel); extern int FreeDir(DIR *dir); /* Operations to allow use of a plain kernel FD, with automatic cleanup */ |