Content-Length: 577091 | pFad | http://github.com/postgres/postgres/commit/dd9bc1a17d0324448c45c6fc0a2d258b9134bfc3

77 Keep WAL segments by the flushed value of the slot's restart LSN · postgres/postgres@dd9bc1a · GitHub
Skip to content

Commit dd9bc1a

Browse files
committed
Keep WAL segments by the flushed value of the slot's restart LSN
The patch fixes the issue with the unexpected removal of old WAL segments after checkpoint, followed by an immediate restart. The issue occurs when a slot is advanced after the start of the checkpoint and before old WAL segments are removed at the end of the 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 the oldest LSN for WAL segments removal at the end of checkpoint. This idea was proposed by Tomas Vondra in the discussion. Unlike 291221c46575, this fix doesn't affect ABI and is intended for back branches. Discussion: https://postgr.es/m/flat/1d12d2-67235980-35-19a406a0%4063439497 Author: Vitaly Davydov <v.davydov@postgrespro.ru> Reviewed-by: Tomas Vondra <tomas@vondra.me> Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com> Reviewed-by: Amit Kapila <amit.kapila16@gmail.com> Backpatch-through: 13
1 parent d2ec671 commit dd9bc1a

File tree

3 files changed

+60
-9
lines changed

3 files changed

+60
-9
lines changed

src/backend/access/transam/xlog.c

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,8 @@ static XLogRecPtr CreateOverwriteContrecordRecord(XLogRecPtr aborted_lsn,
646646
XLogRecPtr missingContrecPtr,
647647
TimeLineID newTLI);
648648
static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags);
649-
static void KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo);
649+
static void KeepLogSeg(XLogRecPtr recptr, XLogRecPtr slotsMinLSN,
650+
XLogSegNo *logSegNo);
650651
static XLogRecPtr XLogGetReplicationSlotMinimumLSN(void);
651652

652653
static void AdvanceXLInsertBuffer(XLogRecPtr upto, TimeLineID tli,
@@ -6333,6 +6334,7 @@ CreateCheckPoint(int flags)
63336334
VirtualTransactionId *vxids;
63346335
int nvxids;
63356336
int oldXLogAllowed = 0;
6337+
XLogRecPtr slotsMinReqLSN;
63366338

63376339
/*
63386340
* An end-of-recovery checkpoint is really a shutdown checkpoint, just
@@ -6534,6 +6536,15 @@ CreateCheckPoint(int flags)
65346536
*/
65356537
END_CRIT_SECTION();
65366538

6539+
/*
6540+
* Get the current minimum LSN to be used later in the WAL segment
6541+
* cleanup. We may clean up only WAL segments, which are not needed
6542+
* according to synchronized LSNs of replication slots. The slot's LSN
6543+
* might be advanced concurrently, so we call this before
6544+
* CheckPointReplicationSlots() synchronizes replication slots.
6545+
*/
6546+
slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN();
6547+
65376548
/*
65386549
* In some cases there are groups of actions that must all occur on one
65396550
* side or the other of a checkpoint record. Before flushing the
@@ -6699,15 +6710,23 @@ CreateCheckPoint(int flags)
66996710
* prevent the disk holding the xlog from growing full.
67006711
*/
67016712
XLByteToSeg(RedoRecPtr, _logSegNo, wal_segment_size);
6702-
KeepLogSeg(recptr, &_logSegNo);
6713+
KeepLogSeg(recptr, slotsMinReqLSN, &_logSegNo);
67036714
if (InvalidateObsoleteReplicationSlots(_logSegNo))
67046715
{
6716+
/*
6717+
* Recalculate the current minimum LSN to be used in the WAL segment
6718+
* cleanup. Then, we must synchronize the replication slots again in
6719+
* order to make this LSN safe to use.
6720+
*/
6721+
slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN();
6722+
CheckPointReplicationSlots();
6723+
67056724
/*
67066725
* Some slots have been invalidated; recalculate the old-segment
67076726
* horizon, starting again from RedoRecPtr.
67086727
*/
67096728
XLByteToSeg(RedoRecPtr, _logSegNo, wal_segment_size);
6710-
KeepLogSeg(recptr, &_logSegNo);
6729+
KeepLogSeg(recptr, slotsMinReqLSN, &_logSegNo);
67116730
}
67126731
_logSegNo--;
67136732
RemoveOldXlogFiles(_logSegNo, RedoRecPtr, recptr,
@@ -6979,6 +6998,7 @@ CreateRestartPoint(int flags)
69796998
XLogRecPtr endptr;
69806999
XLogSegNo _logSegNo;
69817000
TimestampTz xtime;
7001+
XLogRecPtr slotsMinReqLSN;
69827002

69837003
/* Concurrent checkpoint/restartpoint cannot happen */
69847004
Assert(!IsUnderPostmaster || MyBackendType == B_CHECKPOINTER);
@@ -7061,6 +7081,15 @@ CreateRestartPoint(int flags)
70617081
MemSet(&CheckpointStats, 0, sizeof(CheckpointStats));
70627082
CheckpointStats.ckpt_start_t = GetCurrentTimestamp();
70637083

7084+
/*
7085+
* Get the current minimum LSN to be used later in the WAL segment
7086+
* cleanup. We may clean up only WAL segments, which are not needed
7087+
* according to synchronized LSNs of replication slots. The slot's LSN
7088+
* might be advanced concurrently, so we call this before
7089+
* CheckPointReplicationSlots() synchronizes replication slots.
7090+
*/
7091+
slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN();
7092+
70647093
if (log_checkpoints)
70657094
LogCheckpointStart(flags, true);
70667095

@@ -7143,15 +7172,23 @@ CreateRestartPoint(int flags)
71437172
receivePtr = GetWalRcvFlushRecPtr(NULL, NULL);
71447173
replayPtr = GetXLogReplayRecPtr(&replayTLI);
71457174
endptr = (receivePtr < replayPtr) ? replayPtr : receivePtr;
7146-
KeepLogSeg(endptr, &_logSegNo);
7175+
KeepLogSeg(endptr, slotsMinReqLSN, &_logSegNo);
71477176
if (InvalidateObsoleteReplicationSlots(_logSegNo))
71487177
{
7178+
/*
7179+
* Recalculate the current minimum LSN to be used in the WAL segment
7180+
* cleanup. Then, we must synchronize the replication slots again in
7181+
* order to make this LSN safe to use.
7182+
*/
7183+
slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN();
7184+
CheckPointReplicationSlots();
7185+
71497186
/*
71507187
* Some slots have been invalidated; recalculate the old-segment
71517188
* horizon, starting again from RedoRecPtr.
71527189
*/
71537190
XLByteToSeg(RedoRecPtr, _logSegNo, wal_segment_size);
7154-
KeepLogSeg(endptr, &_logSegNo);
7191+
KeepLogSeg(endptr, slotsMinReqLSN, &_logSegNo);
71557192
}
71567193
_logSegNo--;
71577194

@@ -7245,6 +7282,7 @@ GetWALAvailability(XLogRecPtr targetLSN)
72457282
XLogSegNo oldestSegMaxWalSize; /* oldest segid kept by max_wal_size */
72467283
XLogSegNo oldestSlotSeg; /* oldest segid kept by slot */
72477284
uint64 keepSegs;
7285+
XLogRecPtr slotsMinReqLSN;
72487286

72497287
/*
72507288
* slot does not reserve WAL. Either deactivated, or has never been active
@@ -7258,8 +7296,9 @@ GetWALAvailability(XLogRecPtr targetLSN)
72587296
* oldestSlotSeg to the current segment.
72597297
*/
72607298
currpos = GetXLogWriteRecPtr();
7299+
slotsMinReqLSN = XLogGetReplicationSlotMinimumLSN();
72617300
XLByteToSeg(currpos, oldestSlotSeg, wal_segment_size);
7262-
KeepLogSeg(currpos, &oldestSlotSeg);
7301+
KeepLogSeg(currpos, slotsMinReqLSN, &oldestSlotSeg);
72637302

72647303
/*
72657304
* Find the oldest extant segment file. We get 1 until checkpoint removes
@@ -7320,7 +7359,7 @@ GetWALAvailability(XLogRecPtr targetLSN)
73207359
* invalidation is optionally done here, instead.
73217360
*/
73227361
static void
7323-
KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
7362+
KeepLogSeg(XLogRecPtr recptr, XLogRecPtr slotsMinReqLSN, XLogSegNo *logSegNo)
73247363
{
73257364
XLogSegNo currSegNo;
73267365
XLogSegNo segno;
@@ -7333,7 +7372,7 @@ KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo)
73337372
* Calculate how many segments are kept by slots first, adjusting for
73347373
* max_slot_wal_keep_size.
73357374
*/
7336-
keep = XLogGetReplicationSlotMinimumLSN();
7375+
keep = slotsMinReqLSN;
73377376
if (keep != InvalidXLogRecPtr && keep < recptr)
73387377
{
73397378
XLByteToSeg(keep, segno, wal_segment_size);

src/backend/replication/logical/logical.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1803,7 +1803,15 @@ LogicalConfirmReceivedLocation(XLogRecPtr lsn)
18031803

18041804
SpinLockRelease(&MyReplicationSlot->mutex);
18051805

1806-
/* first write new xmin to disk, so we know what's up after a crash */
1806+
/*
1807+
* First, write new xmin and restart_lsn to disk so we know what's up
1808+
* after a crash. Even when we do this, the checkpointer can see the
1809+
* updated restart_lsn value in the shared memory; then, a crash can
1810+
* happen before we manage to write that value to the disk. Thus,
1811+
* checkpointer still needs to make special efforts to keep WAL
1812+
* segments required by the restart_lsn written to the disk. See
1813+
* CreateCheckPoint() and CreateRestartPoint() for details.
1814+
*/
18071815
if (updated_xmin || updated_restart)
18081816
{
18091817
ReplicationSlotMarkDirty();

src/backend/replication/walsender.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2065,6 +2065,10 @@ PhysicalConfirmReceivedLocation(XLogRecPtr lsn)
20652065
* be energy wasted - the worst lost information can do here is give us
20662066
* wrong information in a statistics view - we'll just potentially be more
20672067
* conservative in removing files.
2068+
*
2069+
* Checkpointer makes special efforts to keep the WAL segments required by
2070+
* the restart_lsn written to the disk. See CreateCheckPoint() and
2071+
* CreateRestartPoint() for details.
20682072
*/
20692073
}
20702074

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/postgres/postgres/commit/dd9bc1a17d0324448c45c6fc0a2d258b9134bfc3

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy