summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Paquier2021-01-15 01:33:13 +0000
committerMichael Paquier2021-01-15 01:33:13 +0000
commit5ae1572993ae8bf1f6c33a933915c07cc9bc0add (patch)
tree168aed6378d35f24973cba9db39137d5cdfea053
parent5e5f4fcd89c082bba0239e8db1552834b4905c34 (diff)
Fix O(N^2) stat() calls when recycling WAL segments
The counter tracking the last segment number recycled was getting initialized when recycling one single segment, while it should be used across a full cycle of segments recycled to prevent useless checks related to entries already recycled. This performance issue has been introduced by b2a5545, and it was first implemented in 61b86142. No backpatch is done per the lack of field complaints. Reported-by: Andres Freund, Thomas Munro Author: Michael Paquier Reviewed-By: Andres Freund Discussion: https://postgr.es/m/[email protected] Discussion: https://postgr.es/m/CA+hUKG+DRiF9z1_MU4fWq+RfJMxP7zjoptfcmuCFPeO4JM2iVg@mail.gmail.com
-rw-r--r--src/backend/access/transam/xlog.c61
1 files changed, 31 insertions, 30 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index b18257c1980..199d911be76 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -930,7 +930,8 @@ static void XLogFileClose(void);
static void PreallocXlogFiles(XLogRecPtr endptr);
static void RemoveTempXlogFiles(void);
static void RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr);
-static void RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr);
+static void RemoveXlogFile(const char *segname, XLogSegNo recycleSegNo,
+ XLogSegNo *endlogSegNo);
static void UpdateLastRemovedPtr(char *filename);
static void ValidateXLOGDirectoryStructure(void);
static void CleanupBackupHistory(void);
@@ -4055,6 +4056,12 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr)
DIR *xldir;
struct dirent *xlde;
char lastoff[MAXFNAMELEN];
+ XLogSegNo endlogSegNo;
+ XLogSegNo recycleSegNo;
+
+ /* Initialize info about where to try to recycle to */
+ XLByteToSeg(endptr, endlogSegNo, wal_segment_size);
+ recycleSegNo = XLOGfileslop(lastredoptr);
/*
* Construct a filename of the last segment to be kept. The timeline ID
@@ -4093,7 +4100,7 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr)
/* Update the last removed location in shared memory first */
UpdateLastRemovedPtr(xlde->d_name);
- RemoveXlogFile(xlde->d_name, lastredoptr, endptr);
+ RemoveXlogFile(xlde->d_name, recycleSegNo, &endlogSegNo);
}
}
}
@@ -4123,13 +4130,21 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
struct dirent *xlde;
char switchseg[MAXFNAMELEN];
XLogSegNo endLogSegNo;
+ XLogSegNo switchLogSegNo;
+ XLogSegNo recycleSegNo;
- XLByteToPrevSeg(switchpoint, endLogSegNo, wal_segment_size);
+ /*
+ * Initialize info about where to begin the work. This will recycle,
+ * somewhat arbitrarily, 10 future segments.
+ */
+ XLByteToPrevSeg(switchpoint, switchLogSegNo, wal_segment_size);
+ XLByteToSeg(switchpoint, endLogSegNo, wal_segment_size);
+ recycleSegNo = endLogSegNo + 10;
/*
* Construct a filename of the last segment to be kept.
*/
- XLogFileName(switchseg, newTLI, endLogSegNo, wal_segment_size);
+ XLogFileName(switchseg, newTLI, switchLogSegNo, wal_segment_size);
elog(DEBUG2, "attempting to remove WAL segments newer than log file %s",
switchseg);
@@ -4157,7 +4172,7 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
* - but seems safer to let them be archived and removed later.
*/
if (!XLogArchiveIsReady(xlde->d_name))
- RemoveXlogFile(xlde->d_name, InvalidXLogRecPtr, switchpoint);
+ RemoveXlogFile(xlde->d_name, recycleSegNo, &endLogSegNo);
}
}
@@ -4167,36 +4182,22 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
/*
* Recycle or remove a log file that's no longer needed.
*
- * endptr is current (or recent) end of xlog, and lastredoptr is the
- * redo pointer of the last checkpoint. These are used to determine
- * whether we want to recycle rather than delete no-longer-wanted log files.
- * If lastredoptr is not known, pass invalid, and the function will recycle,
- * somewhat arbitrarily, 10 future segments.
+ * segname is the name of the segment to recycle or remove. recycleSegNo
+ * is the segment number to recycle up to. endlogSegNo is the segment
+ * number of the current (or recent) end of WAL.
+ *
+ * endlogSegNo gets incremented if the segment is recycled so as it is not
+ * checked again with future callers of this function.
*/
static void
-RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr)
+RemoveXlogFile(const char *segname, XLogSegNo recycleSegNo,
+ XLogSegNo *endlogSegNo)
{
char path[MAXPGPATH];
#ifdef WIN32
char newpath[MAXPGPATH];
#endif
struct stat statbuf;
- XLogSegNo endlogSegNo;
- XLogSegNo recycleSegNo;
-
- if (wal_recycle)
- {
- /*
- * Initialize info about where to try to recycle to.
- */
- XLByteToSeg(endptr, endlogSegNo, wal_segment_size);
- if (lastredoptr == InvalidXLogRecPtr)
- recycleSegNo = endlogSegNo + 10;
- else
- recycleSegNo = XLOGfileslop(lastredoptr);
- }
- else
- recycleSegNo = 0; /* keep compiler quiet */
snprintf(path, MAXPGPATH, XLOGDIR "/%s", segname);
@@ -4206,9 +4207,9 @@ RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr)
* symbolic links pointing to a separate archive directory.
*/
if (wal_recycle &&
- endlogSegNo <= recycleSegNo &&
+ *endlogSegNo <= recycleSegNo &&
lstat(path, &statbuf) == 0 && S_ISREG(statbuf.st_mode) &&
- InstallXLogFileSegment(&endlogSegNo, path,
+ InstallXLogFileSegment(endlogSegNo, path,
true, recycleSegNo, true))
{
ereport(DEBUG2,
@@ -4216,7 +4217,7 @@ RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr)
segname)));
CheckpointStats.ckpt_segs_recycled++;
/* Needn't recheck that slot on future iterations */
- endlogSegNo++;
+ (*endlogSegNo)++;
}
else
{