Skip to content

Commit 5ae1572

Browse files
committed
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 61b8614. 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
1 parent 5e5f4fc commit 5ae1572

File tree

1 file changed

+31
-30
lines changed
  • src/backend/access/transam

1 file changed

+31
-30
lines changed

src/backend/access/transam/xlog.c

+31-30
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,8 @@ static void XLogFileClose(void);
930930
static void PreallocXlogFiles(XLogRecPtr endptr);
931931
static void RemoveTempXlogFiles(void);
932932
static void RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr);
933-
static void RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr);
933+
static void RemoveXlogFile(const char *segname, XLogSegNo recycleSegNo,
934+
XLogSegNo *endlogSegNo);
934935
static void UpdateLastRemovedPtr(char *filename);
935936
static void ValidateXLOGDirectoryStructure(void);
936937
static void CleanupBackupHistory(void);
@@ -4055,6 +4056,12 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr)
40554056
DIR *xldir;
40564057
struct dirent *xlde;
40574058
char lastoff[MAXFNAMELEN];
4059+
XLogSegNo endlogSegNo;
4060+
XLogSegNo recycleSegNo;
4061+
4062+
/* Initialize info about where to try to recycle to */
4063+
XLByteToSeg(endptr, endlogSegNo, wal_segment_size);
4064+
recycleSegNo = XLOGfileslop(lastredoptr);
40584065

40594066
/*
40604067
* Construct a filename of the last segment to be kept. The timeline ID
@@ -4093,7 +4100,7 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr)
40934100
/* Update the last removed location in shared memory first */
40944101
UpdateLastRemovedPtr(xlde->d_name);
40954102

4096-
RemoveXlogFile(xlde->d_name, lastredoptr, endptr);
4103+
RemoveXlogFile(xlde->d_name, recycleSegNo, &endlogSegNo);
40974104
}
40984105
}
40994106
}
@@ -4123,13 +4130,21 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
41234130
struct dirent *xlde;
41244131
char switchseg[MAXFNAMELEN];
41254132
XLogSegNo endLogSegNo;
4133+
XLogSegNo switchLogSegNo;
4134+
XLogSegNo recycleSegNo;
41264135

4127-
XLByteToPrevSeg(switchpoint, endLogSegNo, wal_segment_size);
4136+
/*
4137+
* Initialize info about where to begin the work. This will recycle,
4138+
* somewhat arbitrarily, 10 future segments.
4139+
*/
4140+
XLByteToPrevSeg(switchpoint, switchLogSegNo, wal_segment_size);
4141+
XLByteToSeg(switchpoint, endLogSegNo, wal_segment_size);
4142+
recycleSegNo = endLogSegNo + 10;
41284143

41294144
/*
41304145
* Construct a filename of the last segment to be kept.
41314146
*/
4132-
XLogFileName(switchseg, newTLI, endLogSegNo, wal_segment_size);
4147+
XLogFileName(switchseg, newTLI, switchLogSegNo, wal_segment_size);
41334148

41344149
elog(DEBUG2, "attempting to remove WAL segments newer than log file %s",
41354150
switchseg);
@@ -4157,7 +4172,7 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
41574172
* - but seems safer to let them be archived and removed later.
41584173
*/
41594174
if (!XLogArchiveIsReady(xlde->d_name))
4160-
RemoveXlogFile(xlde->d_name, InvalidXLogRecPtr, switchpoint);
4175+
RemoveXlogFile(xlde->d_name, recycleSegNo, &endLogSegNo);
41614176
}
41624177
}
41634178

@@ -4167,36 +4182,22 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
41674182
/*
41684183
* Recycle or remove a log file that's no longer needed.
41694184
*
4170-
* endptr is current (or recent) end of xlog, and lastredoptr is the
4171-
* redo pointer of the last checkpoint. These are used to determine
4172-
* whether we want to recycle rather than delete no-longer-wanted log files.
4173-
* If lastredoptr is not known, pass invalid, and the function will recycle,
4174-
* somewhat arbitrarily, 10 future segments.
4185+
* segname is the name of the segment to recycle or remove. recycleSegNo
4186+
* is the segment number to recycle up to. endlogSegNo is the segment
4187+
* number of the current (or recent) end of WAL.
4188+
*
4189+
* endlogSegNo gets incremented if the segment is recycled so as it is not
4190+
* checked again with future callers of this function.
41754191
*/
41764192
static void
4177-
RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr)
4193+
RemoveXlogFile(const char *segname, XLogSegNo recycleSegNo,
4194+
XLogSegNo *endlogSegNo)
41784195
{
41794196
char path[MAXPGPATH];
41804197
#ifdef WIN32
41814198
char newpath[MAXPGPATH];
41824199
#endif
41834200
struct stat statbuf;
4184-
XLogSegNo endlogSegNo;
4185-
XLogSegNo recycleSegNo;
4186-
4187-
if (wal_recycle)
4188-
{
4189-
/*
4190-
* Initialize info about where to try to recycle to.
4191-
*/
4192-
XLByteToSeg(endptr, endlogSegNo, wal_segment_size);
4193-
if (lastredoptr == InvalidXLogRecPtr)
4194-
recycleSegNo = endlogSegNo + 10;
4195-
else
4196-
recycleSegNo = XLOGfileslop(lastredoptr);
4197-
}
4198-
else
4199-
recycleSegNo = 0; /* keep compiler quiet */
42004201

42014202
snprintf(path, MAXPGPATH, XLOGDIR "/%s", segname);
42024203

@@ -4206,17 +4207,17 @@ RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr)
42064207
* symbolic links pointing to a separate archive directory.
42074208
*/
42084209
if (wal_recycle &&
4209-
endlogSegNo <= recycleSegNo &&
4210+
*endlogSegNo <= recycleSegNo &&
42104211
lstat(path, &statbuf) == 0 && S_ISREG(statbuf.st_mode) &&
4211-
InstallXLogFileSegment(&endlogSegNo, path,
4212+
InstallXLogFileSegment(endlogSegNo, path,
42124213
true, recycleSegNo, true))
42134214
{
42144215
ereport(DEBUG2,
42154216
(errmsg("recycled write-ahead log file \"%s\"",
42164217
segname)));
42174218
CheckpointStats.ckpt_segs_recycled++;
42184219
/* Needn't recheck that slot on future iterations */
4219-
endlogSegNo++;
4220+
(*endlogSegNo)++;
42204221
}
42214222
else
42224223
{

0 commit comments

Comments
 (0)