Skip to content

Commit 5ee12b0

Browse files
Vitaly DavydovCommitfest Bot
Vitaly Davydov
authored and
Commitfest Bot
committed
Keep WAL segments by slot's flushed restart LSN
The patch fixes the issue with unexpected removal of old WAL segments after checkpoint followed by immediate restart. The issue occurs when a slot is advanced after the start of checkpoint and before old WAL segments removal at end of checkpoint. The idea of the patch is to get the minimal restart_lsn at the beginning of checkpoint (or restart point) creation and use this value when calculating oldest LSN for WAL segments removal at the end of checkpoint. This idea was proposed by Tomas Vondra in the discussion. Discussion: https://www.postgresql.org/message-id/flat/1d12d2-67235980-35-19a406a0%4063439497
1 parent c5b5cf6 commit 5ee12b0

File tree

1 file changed

+29
-8
lines changed
  • src/backend/access/transam

1 file changed

+29
-8
lines changed

src/backend/access/transam/xlog.c

+29-8
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,8 @@ static XLogRecPtr CreateOverwriteContrecordRecord(XLogRecPtr aborted_lsn,
677677
XLogRecPtr pagePtr,
678678
TimeLineID newTLI);
679679
static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags);
680-
static void KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo);
680+
static void KeepLogSeg(XLogRecPtr recptr, XLogRecPtr slotsMinLSN,
681+
XLogSegNo *logSegNo);
681682
static XLogRecPtr XLogGetReplicationSlotMinimumLSN(void);
682683

683684
static void AdvanceXLInsertBuffer(XLogRecPtr upto, TimeLineID tli,
@@ -7087,6 +7088,7 @@ CreateCheckPoint(int flags)
70877088
VirtualTransactionId *vxids;
70887089
int nvxids;
70897090
int oldXLogAllowed = 0;
7091+
XLogRecPtr slotsMinReqLSN;
70907092

70917093
/*
70927094
* An end-of-recovery checkpoint is really a shutdown checkpoint, just
@@ -7315,6 +7317,11 @@ CreateCheckPoint(int flags)
73157317
*/
73167318
END_CRIT_SECTION();
73177319

7320+
/*
7321+
* Get the current minimum LSN to be used later in WAL segments cleanup.
7322+
*/
7323+
slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN();
7324+
73187325
/*
73197326
* In some cases there are groups of actions that must all occur on one
73207327
* side or the other of a checkpoint record. Before flushing the
@@ -7507,17 +7514,20 @@ CreateCheckPoint(int flags)
75077514
* prevent the disk holding the xlog from growing full.
75087515
*/
75097516
XLByteToSeg(RedoRecPtr, _logSegNo, wal_segment_size);
7510-
KeepLogSeg(recptr, &_logSegNo);
7517+
KeepLogSeg(recptr, slotsMinReqLSN, &_logSegNo);
75117518
if (InvalidateObsoleteReplicationSlots(RS_INVAL_WAL_REMOVED | RS_INVAL_IDLE_TIMEOUT,
75127519
_logSegNo, InvalidOid,
75137520
InvalidTransactionId))
75147521
{
7522+
slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN();
7523+
CheckPointReplicationSlots(shutdown);
7524+
75157525
/*
75167526
* Some slots have been invalidated; recalculate the old-segment
75177527
* horizon, starting again from RedoRecPtr.
75187528
*/
75197529
XLByteToSeg(RedoRecPtr, _logSegNo, wal_segment_size);
7520-
KeepLogSeg(recptr, &_logSegNo);
7530+
KeepLogSeg(recptr, slotsMinReqLSN, &_logSegNo);
75217531
}
75227532
_logSegNo--;
75237533
RemoveOldXlogFiles(_logSegNo, RedoRecPtr, recptr,
@@ -7792,6 +7802,7 @@ CreateRestartPoint(int flags)
77927802
XLogRecPtr endptr;
77937803
XLogSegNo _logSegNo;
77947804
TimestampTz xtime;
7805+
XLogRecPtr slotsMinReqLSN;
77957806

77967807
/* Concurrent checkpoint/restartpoint cannot happen */
77977808
Assert(!IsUnderPostmaster || MyBackendType == B_CHECKPOINTER);
@@ -7874,6 +7885,11 @@ CreateRestartPoint(int flags)
78747885
MemSet(&CheckpointStats, 0, sizeof(CheckpointStats));
78757886
CheckpointStats.ckpt_start_t = GetCurrentTimestamp();
78767887

7888+
/*
7889+
* Get the current minimum LSN to be used later in WAL segments cleanup.
7890+
*/
7891+
slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN();
7892+
78777893
if (log_checkpoints)
78787894
LogCheckpointStart(flags, true);
78797895

@@ -7962,17 +7978,20 @@ CreateRestartPoint(int flags)
79627978
receivePtr = GetWalRcvFlushRecPtr(NULL, NULL);
79637979
replayPtr = GetXLogReplayRecPtr(&replayTLI);
79647980
endptr = (receivePtr < replayPtr) ? replayPtr : receivePtr;
7965-
KeepLogSeg(endptr, &_logSegNo);
7981+
KeepLogSeg(endptr, slotsMinReqLSN, &_logSegNo);
79667982
if (InvalidateObsoleteReplicationSlots(RS_INVAL_WAL_REMOVED | RS_INVAL_IDLE_TIMEOUT,
79677983
_logSegNo, InvalidOid,
79687984
InvalidTransactionId))
79697985
{
7986+
slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN();
7987+
CheckPointReplicationSlots(flags & CHECKPOINT_IS_SHUTDOWN);
7988+
79707989
/*
79717990
* Some slots have been invalidated; recalculate the old-segment
79727991
* horizon, starting again from RedoRecPtr.
79737992
*/
79747993
XLByteToSeg(RedoRecPtr, _logSegNo, wal_segment_size);
7975-
KeepLogSeg(endptr, &_logSegNo);
7994+
KeepLogSeg(endptr, slotsMinReqLSN, &_logSegNo);
79767995
}
79777996
_logSegNo--;
79787997

@@ -8067,6 +8086,7 @@ GetWALAvailability(XLogRecPtr targetLSN)
80678086
XLogSegNo oldestSegMaxWalSize; /* oldest segid kept by max_wal_size */
80688087
XLogSegNo oldestSlotSeg; /* oldest segid kept by slot */
80698088
uint64 keepSegs;
8089+
XLogRecPtr slotsMinReqLSN;
80708090

80718091
/*
80728092
* slot does not reserve WAL. Either deactivated, or has never been active
@@ -8080,8 +8100,9 @@ GetWALAvailability(XLogRecPtr targetLSN)
80808100
* oldestSlotSeg to the current segment.
80818101
*/
80828102
currpos = GetXLogWriteRecPtr();
8103+
slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN();
80838104
XLByteToSeg(currpos, oldestSlotSeg, wal_segment_size);
8084-
KeepLogSeg(currpos, &oldestSlotSeg);
8105+
KeepLogSeg(currpos, slotsMinReqLSN, &oldestSlotSeg);
80858106

80868107
/*
80878108
* Find the oldest extant segment file. We get 1 until checkpoint removes
@@ -8142,7 +8163,7 @@ GetWALAvailability(XLogRecPtr targetLSN)
81428163
* invalidation is optionally done here, instead.
81438164
*/
81448165
static void
8145-
KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
8166+
KeepLogSeg(XLogRecPtr recptr, XLogRecPtr slotsMinReqLSN, XLogSegNo *logSegNo)
81468167
{
81478168
XLogSegNo currSegNo;
81488169
XLogSegNo segno;
@@ -8155,7 +8176,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
81558176
* Calculate how many segments are kept by slots first, adjusting for
81568177
* max_slot_wal_keep_size.
81578178
*/
8158-
keep = XLogGetReplicationSlotMinimumLSN();
8179+
keep = slotsMinReqLSN;
81598180
if (keep != InvalidXLogRecPtr && keep < recptr)
81608181
{
81618182
XLByteToSeg(keep, segno, wal_segment_size);

0 commit comments

Comments
 (0)