@@ -667,7 +667,8 @@ static XLogRecPtr CreateOverwriteContrecordRecord(XLogRecPtr aborted_lsn,
667
667
XLogRecPtr pagePtr ,
668
668
TimeLineID newTLI );
669
669
static void CheckPointGuts (XLogRecPtr checkPointRedo , int flags );
670
- static void KeepLogSeg (XLogRecPtr recptr , XLogSegNo * logSegNo );
670
+ static void KeepLogSeg (XLogRecPtr recptr , XLogRecPtr slotsMinLSN ,
671
+ XLogSegNo * logSegNo );
671
672
static XLogRecPtr XLogGetReplicationSlotMinimumLSN (void );
672
673
673
674
static void AdvanceXLInsertBuffer (XLogRecPtr upto , TimeLineID tli ,
@@ -6891,6 +6892,7 @@ CreateCheckPoint(int flags)
6891
6892
VirtualTransactionId * vxids ;
6892
6893
int nvxids ;
6893
6894
int oldXLogAllowed = 0 ;
6895
+ XLogRecPtr slotsMinReqLSN ;
6894
6896
6895
6897
/*
6896
6898
* An end-of-recovery checkpoint is really a shutdown checkpoint, just
@@ -7119,6 +7121,15 @@ CreateCheckPoint(int flags)
7119
7121
*/
7120
7122
END_CRIT_SECTION ();
7121
7123
7124
+ /*
7125
+ * Get the current minimum LSN to be used later in the WAL segment
7126
+ * cleanup. We may clean up only WAL segments, which are not needed
7127
+ * according to synchronized LSNs of replication slots. The slot's LSN
7128
+ * might be advanced concurrently, so we call this before
7129
+ * CheckPointReplicationSlots() synchronizes replication slots.
7130
+ */
7131
+ slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN ();
7132
+
7122
7133
/*
7123
7134
* In some cases there are groups of actions that must all occur on one
7124
7135
* side or the other of a checkpoint record. Before flushing the
@@ -7307,17 +7318,25 @@ CreateCheckPoint(int flags)
7307
7318
* prevent the disk holding the xlog from growing full.
7308
7319
*/
7309
7320
XLByteToSeg (RedoRecPtr , _logSegNo , wal_segment_size );
7310
- KeepLogSeg (recptr , & _logSegNo );
7321
+ KeepLogSeg (recptr , slotsMinReqLSN , & _logSegNo );
7311
7322
if (InvalidateObsoleteReplicationSlots (RS_INVAL_WAL_REMOVED ,
7312
7323
_logSegNo , InvalidOid ,
7313
7324
InvalidTransactionId ))
7314
7325
{
7326
+ /*
7327
+ * Recalculate the current minimum LSN to be used in the WAL segment
7328
+ * cleanup. Then, we must synchronize the replication slots again in
7329
+ * order to make this LSN safe to use.
7330
+ */
7331
+ slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN ();
7332
+ CheckPointReplicationSlots (shutdown );
7333
+
7315
7334
/*
7316
7335
* Some slots have been invalidated; recalculate the old-segment
7317
7336
* horizon, starting again from RedoRecPtr.
7318
7337
*/
7319
7338
XLByteToSeg (RedoRecPtr , _logSegNo , wal_segment_size );
7320
- KeepLogSeg (recptr , & _logSegNo );
7339
+ KeepLogSeg (recptr , slotsMinReqLSN , & _logSegNo );
7321
7340
}
7322
7341
_logSegNo -- ;
7323
7342
RemoveOldXlogFiles (_logSegNo , RedoRecPtr , recptr ,
@@ -7590,6 +7609,7 @@ CreateRestartPoint(int flags)
7590
7609
XLogRecPtr endptr ;
7591
7610
XLogSegNo _logSegNo ;
7592
7611
TimestampTz xtime ;
7612
+ XLogRecPtr slotsMinReqLSN ;
7593
7613
7594
7614
/* Concurrent checkpoint/restartpoint cannot happen */
7595
7615
Assert (!IsUnderPostmaster || MyBackendType == B_CHECKPOINTER );
@@ -7672,6 +7692,15 @@ CreateRestartPoint(int flags)
7672
7692
MemSet (& CheckpointStats , 0 , sizeof (CheckpointStats ));
7673
7693
CheckpointStats .ckpt_start_t = GetCurrentTimestamp ();
7674
7694
7695
+ /*
7696
+ * Get the current minimum LSN to be used later in the WAL segment
7697
+ * cleanup. We may clean up only WAL segments, which are not needed
7698
+ * according to synchronized LSNs of replication slots. The slot's LSN
7699
+ * might be advanced concurrently, so we call this before
7700
+ * CheckPointReplicationSlots() synchronizes replication slots.
7701
+ */
7702
+ slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN ();
7703
+
7675
7704
if (log_checkpoints )
7676
7705
LogCheckpointStart (flags , true);
7677
7706
@@ -7760,17 +7789,25 @@ CreateRestartPoint(int flags)
7760
7789
receivePtr = GetWalRcvFlushRecPtr (NULL , NULL );
7761
7790
replayPtr = GetXLogReplayRecPtr (& replayTLI );
7762
7791
endptr = (receivePtr < replayPtr ) ? replayPtr : receivePtr ;
7763
- KeepLogSeg (endptr , & _logSegNo );
7792
+ KeepLogSeg (endptr , slotsMinReqLSN , & _logSegNo );
7764
7793
if (InvalidateObsoleteReplicationSlots (RS_INVAL_WAL_REMOVED ,
7765
7794
_logSegNo , InvalidOid ,
7766
7795
InvalidTransactionId ))
7767
7796
{
7797
+ /*
7798
+ * Recalculate the current minimum LSN to be used in the WAL segment
7799
+ * cleanup. Then, we must synchronize the replication slots again in
7800
+ * order to make this LSN safe to use.
7801
+ */
7802
+ slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN ();
7803
+ CheckPointReplicationSlots (flags & CHECKPOINT_IS_SHUTDOWN );
7804
+
7768
7805
/*
7769
7806
* Some slots have been invalidated; recalculate the old-segment
7770
7807
* horizon, starting again from RedoRecPtr.
7771
7808
*/
7772
7809
XLByteToSeg (RedoRecPtr , _logSegNo , wal_segment_size );
7773
- KeepLogSeg (endptr , & _logSegNo );
7810
+ KeepLogSeg (endptr , slotsMinReqLSN , & _logSegNo );
7774
7811
}
7775
7812
_logSegNo -- ;
7776
7813
@@ -7865,6 +7902,7 @@ GetWALAvailability(XLogRecPtr targetLSN)
7865
7902
XLogSegNo oldestSegMaxWalSize ; /* oldest segid kept by max_wal_size */
7866
7903
XLogSegNo oldestSlotSeg ; /* oldest segid kept by slot */
7867
7904
uint64 keepSegs ;
7905
+ XLogRecPtr slotsMinReqLSN ;
7868
7906
7869
7907
/*
7870
7908
* slot does not reserve WAL. Either deactivated, or has never been active
@@ -7878,8 +7916,9 @@ GetWALAvailability(XLogRecPtr targetLSN)
7878
7916
* oldestSlotSeg to the current segment.
7879
7917
*/
7880
7918
currpos = GetXLogWriteRecPtr ();
7919
+ slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN ();
7881
7920
XLByteToSeg (currpos , oldestSlotSeg , wal_segment_size );
7882
- KeepLogSeg (currpos , & oldestSlotSeg );
7921
+ KeepLogSeg (currpos , slotsMinReqLSN , & oldestSlotSeg );
7883
7922
7884
7923
/*
7885
7924
* Find the oldest extant segment file. We get 1 until checkpoint removes
@@ -7940,7 +7979,7 @@ GetWALAvailability(XLogRecPtr targetLSN)
7940
7979
* invalidation is optionally done here, instead.
7941
7980
*/
7942
7981
static void
7943
- KeepLogSeg (XLogRecPtr recptr , XLogSegNo * logSegNo )
7982
+ KeepLogSeg (XLogRecPtr recptr , XLogRecPtr slotsMinReqLSN , XLogSegNo * logSegNo )
7944
7983
{
7945
7984
XLogSegNo currSegNo ;
7946
7985
XLogSegNo segno ;
@@ -7953,7 +7992,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
7953
7992
* Calculate how many segments are kept by slots first, adjusting for
7954
7993
* max_slot_wal_keep_size.
7955
7994
*/
7956
- keep = XLogGetReplicationSlotMinimumLSN () ;
7995
+ keep = slotsMinReqLSN ;
7957
7996
if (keep != InvalidXLogRecPtr && keep < recptr )
7958
7997
{
7959
7998
XLByteToSeg (keep , segno , wal_segment_size );
0 commit comments