mirror of
https://github.com/postgres/postgres.git
synced 2025-06-29 10:41:53 +03:00
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 byb2a5545
, and it was first implemented in61b86142
. 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/20170621211016.eln6cxxp3jrv7m4m@alap3.anarazel.de Discussion: https://postgr.es/m/CA+hUKG+DRiF9z1_MU4fWq+RfJMxP7zjoptfcmuCFPeO4JM2iVg@mail.gmail.com
This commit is contained in:
@ -930,7 +930,8 @@ static void XLogFileClose(void);
|
|||||||
static void PreallocXlogFiles(XLogRecPtr endptr);
|
static void PreallocXlogFiles(XLogRecPtr endptr);
|
||||||
static void RemoveTempXlogFiles(void);
|
static void RemoveTempXlogFiles(void);
|
||||||
static void RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr);
|
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 UpdateLastRemovedPtr(char *filename);
|
||||||
static void ValidateXLOGDirectoryStructure(void);
|
static void ValidateXLOGDirectoryStructure(void);
|
||||||
static void CleanupBackupHistory(void);
|
static void CleanupBackupHistory(void);
|
||||||
@ -4055,6 +4056,12 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr)
|
|||||||
DIR *xldir;
|
DIR *xldir;
|
||||||
struct dirent *xlde;
|
struct dirent *xlde;
|
||||||
char lastoff[MAXFNAMELEN];
|
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
|
* 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 */
|
/* Update the last removed location in shared memory first */
|
||||||
UpdateLastRemovedPtr(xlde->d_name);
|
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;
|
struct dirent *xlde;
|
||||||
char switchseg[MAXFNAMELEN];
|
char switchseg[MAXFNAMELEN];
|
||||||
XLogSegNo endLogSegNo;
|
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.
|
* 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",
|
elog(DEBUG2, "attempting to remove WAL segments newer than log file %s",
|
||||||
switchseg);
|
switchseg);
|
||||||
@ -4157,7 +4172,7 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
|
|||||||
* - but seems safer to let them be archived and removed later.
|
* - but seems safer to let them be archived and removed later.
|
||||||
*/
|
*/
|
||||||
if (!XLogArchiveIsReady(xlde->d_name))
|
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.
|
* Recycle or remove a log file that's no longer needed.
|
||||||
*
|
*
|
||||||
* endptr is current (or recent) end of xlog, and lastredoptr is the
|
* segname is the name of the segment to recycle or remove. recycleSegNo
|
||||||
* redo pointer of the last checkpoint. These are used to determine
|
* is the segment number to recycle up to. endlogSegNo is the segment
|
||||||
* whether we want to recycle rather than delete no-longer-wanted log files.
|
* number of the current (or recent) end of WAL.
|
||||||
* If lastredoptr is not known, pass invalid, and the function will recycle,
|
*
|
||||||
* somewhat arbitrarily, 10 future segments.
|
* endlogSegNo gets incremented if the segment is recycled so as it is not
|
||||||
|
* checked again with future callers of this function.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr)
|
RemoveXlogFile(const char *segname, XLogSegNo recycleSegNo,
|
||||||
|
XLogSegNo *endlogSegNo)
|
||||||
{
|
{
|
||||||
char path[MAXPGPATH];
|
char path[MAXPGPATH];
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
char newpath[MAXPGPATH];
|
char newpath[MAXPGPATH];
|
||||||
#endif
|
#endif
|
||||||
struct stat statbuf;
|
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);
|
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.
|
* symbolic links pointing to a separate archive directory.
|
||||||
*/
|
*/
|
||||||
if (wal_recycle &&
|
if (wal_recycle &&
|
||||||
endlogSegNo <= recycleSegNo &&
|
*endlogSegNo <= recycleSegNo &&
|
||||||
lstat(path, &statbuf) == 0 && S_ISREG(statbuf.st_mode) &&
|
lstat(path, &statbuf) == 0 && S_ISREG(statbuf.st_mode) &&
|
||||||
InstallXLogFileSegment(&endlogSegNo, path,
|
InstallXLogFileSegment(endlogSegNo, path,
|
||||||
true, recycleSegNo, true))
|
true, recycleSegNo, true))
|
||||||
{
|
{
|
||||||
ereport(DEBUG2,
|
ereport(DEBUG2,
|
||||||
@ -4216,7 +4217,7 @@ RemoveXlogFile(const char *segname, XLogRecPtr lastredoptr, XLogRecPtr endptr)
|
|||||||
segname)));
|
segname)));
|
||||||
CheckpointStats.ckpt_segs_recycled++;
|
CheckpointStats.ckpt_segs_recycled++;
|
||||||
/* Needn't recheck that slot on future iterations */
|
/* Needn't recheck that slot on future iterations */
|
||||||
endlogSegNo++;
|
(*endlogSegNo)++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user