From df8ec9634ccdc3c67871e36fcc54c44370639b37 Mon Sep 17 00:00:00 2001 From: Noah Misch Date: Mon, 28 Jun 2021 18:34:55 -0700 Subject: [PATCH] Remove XLogFileInit() ability to skip ControlFileLock. Cold paths, initdb and end-of-recovery, used it. Don't optimize them. This commit has been applied as of c53c6b98d38a in v15 and newer versions. This is required on stable branches of v13 and v14 to fix a regression reported by Noah Misch, introduced by 1f95181b44c8, causing spurious failures in archive recovery (neither streaming nor archive recovery) with concurrent restartpoints. The backpatched versions of the patches have been aligned on these branches by me, Noah Misch is the author. Tests have been conducted by the both of us. Reported-by: Arun Thirupathi Author: Noah Misch Discussion: https://postgr.es/m/20210202151416.GB3304930@rfd.leadboat.com Discussion: https://postgr.es/m/20250306193013.36.nmisch@google.com Backpatch-through: 13 --- src/backend/access/transam/xlog.c | 46 ++++++++------------------- src/backend/replication/walreceiver.c | 2 +- src/include/access/xlog.h | 2 +- 3 files changed, 16 insertions(+), 34 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 769f4a202f2..859f86cfc3c 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -917,8 +917,7 @@ static void AdvanceXLInsertBuffer(XLogRecPtr upto, bool opportunistic); static bool XLogCheckpointNeeded(XLogSegNo new_segno); static void XLogWrite(XLogwrtRqst WriteRqst, bool flexible); static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath, - bool find_free, XLogSegNo max_segno, - bool use_lock); + bool find_free, XLogSegNo max_segno); static int XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli, XLogSource source, bool notfoundOk); static int XLogFileReadAnyTLI(XLogSegNo segno, int emode, XLogSource source); @@ -2509,7 +2508,7 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible) /* create/use new log file */ use_existent = true; - openLogFile = XLogFileInit(openLogSegNo, &use_existent, true); + openLogFile = XLogFileInit(openLogSegNo, &use_existent); ReserveExternalFD(); } @@ -3263,10 +3262,6 @@ XLogNeedsFlush(XLogRecPtr record) * pre-existing file will be deleted). On return, true if a pre-existing * file was used. * - * use_lock: if true, acquire ControlFileLock while moving file into - * place. This should be true except during bootstrap log creation. The - * caller must *not* hold the lock at call. - * * Returns FD of opened file. * * Note: errors here are ERROR not PANIC because we might or might not be @@ -3275,7 +3270,7 @@ XLogNeedsFlush(XLogRecPtr record) * in a critical section. */ int -XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock) +XLogFileInit(XLogSegNo logsegno, bool *use_existent) { char path[MAXPGPATH]; char tmppath[MAXPGPATH]; @@ -3420,8 +3415,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock) */ max_segno = logsegno + CheckPointSegments; if (!InstallXLogFileSegment(&installed_segno, tmppath, - *use_existent, max_segno, - use_lock)) + *use_existent, max_segno)) { /* * No need for any more future segments, or InstallXLogFileSegment() @@ -3578,7 +3572,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno, /* * Now move the segment into place with its final name. */ - if (!InstallXLogFileSegment(&destsegno, tmppath, false, 0, false)) + if (!InstallXLogFileSegment(&destsegno, tmppath, false, 0)) elog(ERROR, "InstallXLogFileSegment should not have failed"); } @@ -3602,29 +3596,20 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno, * free slot is found between *segno and max_segno. (Ignored when find_free * is false.) * - * use_lock: if true, acquire ControlFileLock while moving file into - * place. This should be true except during bootstrap log creation. The - * caller must *not* hold the lock at call. - * * Returns true if the file was installed successfully. false indicates that * max_segno limit was exceeded, or an error occurred while renaming the * file into place. */ static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath, - bool find_free, XLogSegNo max_segno, - bool use_lock) + bool find_free, XLogSegNo max_segno) { char path[MAXPGPATH]; struct stat stat_buf; XLogFilePath(path, ThisTimeLineID, *segno, wal_segment_size); - /* - * We want to be sure that only one process does this at a time. - */ - if (use_lock) - LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); + LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); if (!find_free) { @@ -3639,8 +3624,7 @@ InstallXLogFileSegment(XLogSegNo *segno, char *tmppath, if ((*segno) >= max_segno) { /* Failed to find a free slot within specified range */ - if (use_lock) - LWLockRelease(ControlFileLock); + LWLockRelease(ControlFileLock); return false; } (*segno)++; @@ -3651,14 +3635,12 @@ InstallXLogFileSegment(XLogSegNo *segno, char *tmppath, Assert(access(path, F_OK) != 0 && errno == ENOENT); if (durable_rename(tmppath, path, LOG) != 0) { - if (use_lock) - LWLockRelease(ControlFileLock); + LWLockRelease(ControlFileLock); /* durable_rename already emitted log message */ return false; } - if (use_lock) - LWLockRelease(ControlFileLock); + LWLockRelease(ControlFileLock); return true; } @@ -3929,7 +3911,7 @@ PreallocXlogFiles(XLogRecPtr endptr) { _logSegNo++; use_existent = true; - lf = XLogFileInit(_logSegNo, &use_existent, true); + lf = XLogFileInit(_logSegNo, &use_existent); close(lf); if (!use_existent) CheckpointStats.ckpt_segs_added++; @@ -4206,7 +4188,7 @@ RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr) endlogSegNo <= recycleSegNo && lstat(path, &statbuf) == 0 && S_ISREG(statbuf.st_mode) && InstallXLogFileSegment(&endlogSegNo, path, - true, recycleSegNo, true)) + true, recycleSegNo)) { ereport(DEBUG2, (errmsg("recycled write-ahead log file \"%s\"", @@ -5342,7 +5324,7 @@ BootStrapXLOG(void) /* Create first XLOG segment file */ use_existent = false; - openLogFile = XLogFileInit(1, &use_existent, false); + openLogFile = XLogFileInit(1, &use_existent); /* * We needn't bother with Reserve/ReleaseExternalFD here, since we'll @@ -5651,7 +5633,7 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog) bool use_existent = true; int fd; - fd = XLogFileInit(startLogSegNo, &use_existent, true); + fd = XLogFileInit(startLogSegNo, &use_existent); if (close(fd) != 0) { diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 479c6c441bd..b874cf364f0 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -922,7 +922,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr) /* Create/use new log file */ XLByteToSeg(recptr, recvSegNo, wal_segment_size); - recvFile = XLogFileInit(recvSegNo, &use_existent, true); + recvFile = XLogFileInit(recvSegNo, &use_existent); recvFileTLI = ThisTimeLineID; } diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 01b3b0a767d..7cb147a7ee3 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -286,7 +286,7 @@ extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata, extern void XLogFlush(XLogRecPtr RecPtr); extern bool XLogBackgroundFlush(void); extern bool XLogNeedsFlush(XLogRecPtr RecPtr); -extern int XLogFileInit(XLogSegNo segno, bool *use_existent, bool use_lock); +extern int XLogFileInit(XLogSegNo segno, bool *use_existent); extern int XLogFileOpen(XLogSegNo segno); extern void CheckXLogRemoved(XLogSegNo segno, TimeLineID tli);