From c9be37adca214ec221f8766bbee0341aed1ceead Mon Sep 17 00:00:00 2001 From: Ants Aasma Date: Sun, 2 Aug 2026 11:53:23 +0200 Subject: [PATCH] Checkpoint replication slots later in the cycle CheckPointReplicationSlots() runs at the start of CheckPointGuts(), but WAL cleanup (KeepLogSeg -> RemoveOldXlogFiles) runs at the end of CreateCheckPoint(), after the checkpoint record has been written to WAL. For spread checkpoints the gap between these two points can be many minutes: all dirty buffer writes (CheckPointBuffers) and the full fsync phase (ProcessSyncRequests) happen in between. During that window, active logical replication consumers advance slot->data.restart_lsn. But XLogCtl->replicationSlotMinLSN was already computed at checkpoint start, against the stale value of restart_lsn. KeepLogSeg() therefore retains WAL segments that are no longer needed, bloating WAL storage unnecessarily. Move CheckPointReplicationSlots(), CheckPointSnapBuild(), and CheckPointLogicalRewriteHeap() to just before CheckPointTwoPhase(), alongside the other checkpoint step that is already deliberately delayed as long as possible, so that replication slot state -- and therefore WAL retention -- reflects the most current data. Author: Ants Aasma Discussion: https://www.postgresql.org/message-id/CAJ7c6TOYJsrmI4Ysfo1FbQU9ioP=+aVVpaPQKsZfMvgVkQDRPw@mail.gmail.com --- src/backend/access/transam/xlog.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f8b939853e9..6f4afbea0db 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -8049,9 +8049,6 @@ static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags) { CheckPointRelationMap(); - CheckPointReplicationSlots(flags & CHECKPOINT_IS_SHUTDOWN); - CheckPointSnapBuild(); - CheckPointLogicalRewriteHeap(); CheckPointReplicationOrigin(); /* Write out all dirty data in SLRUs and the main buffer pool */ @@ -8071,7 +8068,16 @@ CheckPointGuts(XLogRecPtr checkPointRedo, int flags) CheckpointStats.ckpt_sync_end_t = GetCurrentTimestamp(); TRACE_POSTGRESQL_BUFFER_CHECKPOINT_DONE(); - /* We deliberately delay 2PC checkpointing as long as possible */ + /* + * Delay replication slot checkpointing as long as possible, so that + * last_saved_restart_lsn computed here reflects the most recent slot + * state. Delay logical snapshot and rewrite heap checkpointing as well, + * so they benefit from the updated restart_lsn for cleanup decisions. + * Also delay 2PC checkpointing as long as possible. + */ + CheckPointReplicationSlots(flags & CHECKPOINT_IS_SHUTDOWN); + CheckPointSnapBuild(); + CheckPointLogicalRewriteHeap(); CheckPointTwoPhase(checkPointRedo); } -- 2.50.1 (Apple Git-155)