From 4fef4354e214e28cf5481e8750f7576e9d191b40 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Fri, 2 Oct 2026 03:05:13 +0530 Subject: [PATCH v4 1/2] Batch fsyncs when removing old WAL segments RemoveOldXlogFiles() uses durable_unlink() for every old WAL file it cannot recycle. Each call fsyncs pg_wal separately. Unlink all such files first, fsync pg_wal once after the scan, then remove their archive-status files. If a crash precedes the directory fsync, obsolete files may reappear; retaining the status files lets a later checkpoint remove them again. Keep the existing LOG-level failure policy. If the batch directory fsync fails, retain the archive-status files rather than cleaning them up or taking down the server. Keep timeline-switch cleanup unbatched, since it is not part of the normal checkpoint removal pass. --- src/backend/access/transam/xlog.c | 49 +++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 9ec0be77ca0..9071c56f38a 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -768,7 +768,7 @@ static void RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr, TimeLineID insertTLI); static void RemoveXlogFile(const struct dirent *segment_de, XLogSegNo recycleSegNo, XLogSegNo *endlogSegNo, - TimeLineID insertTLI); + TimeLineID insertTLI, List **cleanup_names); static void UpdateLastRemovedPtr(char *filename); static void ValidateXLOGDirectoryStructure(void); static void CleanupBackupHistory(void); @@ -3982,6 +3982,8 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr, char lastoff[MAXFNAMELEN]; XLogSegNo endlogSegNo; XLogSegNo recycleSegNo; + List *cleanup_names = NIL; + ListCell *lc; /* Initialize info about where to try to recycle to */ XLByteToSeg(endptr, endlogSegNo, wal_segment_size); @@ -4024,12 +4026,27 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr, /* Update the last removed location in shared memory first */ UpdateLastRemovedPtr(xlde->d_name); - RemoveXlogFile(xlde, recycleSegNo, &endlogSegNo, insertTLI); + RemoveXlogFile(xlde, recycleSegNo, &endlogSegNo, insertTLI, + &cleanup_names); } } } FreeDir(xldir); + + /* Make all removals durable with one directory fsync. */ + if (cleanup_names != NIL && + fsync_fname_ext(XLOGDIR, true, false, LOG) != 0) + { + list_free_deep(cleanup_names); + return; + } + + /* Remove archive status only after the WAL-file removals are durable. */ + foreach(lc, cleanup_names) + XLogArchiveCleanup((char *) lfirst(lc)); + + list_free_deep(cleanup_names); } /* @@ -4097,7 +4114,7 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI) * - but seems safer to let them be archived and removed later. */ if (!XLogArchiveIsReady(xlde->d_name)) - RemoveXlogFile(xlde, recycleSegNo, &endLogSegNo, newTLI); + RemoveXlogFile(xlde, recycleSegNo, &endLogSegNo, newTLI, NULL); } } @@ -4120,15 +4137,18 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI) static void RemoveXlogFile(const struct dirent *segment_de, XLogSegNo recycleSegNo, XLogSegNo *endlogSegNo, - TimeLineID insertTLI) + TimeLineID insertTLI, List **cleanup_names) { char path[MAXPGPATH]; + bool removed = false; + const char *unlinkpath; #ifdef WIN32 char newpath[MAXPGPATH]; #endif const char *segname = segment_de->d_name; snprintf(path, MAXPGPATH, XLOGDIR "/%s", segname); + unlinkpath = path; /* * Before deleting the file, see if it can be recycled as a future log @@ -4179,19 +4199,30 @@ RemoveXlogFile(const struct dirent *segment_de, path))); return; } - rc = durable_unlink(newpath, LOG); -#else - rc = durable_unlink(path, LOG); + unlinkpath = newpath; #endif + + if (cleanup_names != NULL) + rc = unlink(unlinkpath); + else + rc = durable_unlink(unlinkpath, LOG); if (rc != 0) { - /* Message already logged by durable_unlink() */ + if (cleanup_names != NULL) + ereport(LOG, + (errcode_for_file_access(), + errmsg("could not remove file \"%s\": %m", + unlinkpath))); return; } CheckpointStats.ckpt_segs_removed++; + removed = true; } - XLogArchiveCleanup(segname); + if (removed && cleanup_names != NULL) + *cleanup_names = lappend(*cleanup_names, pstrdup(segname)); + else + XLogArchiveCleanup(segname); } /* base-commit: 42e96cf2fe095c822f76bc94669ea875cb1e3351 -- 2.34.1