Skip to content

Commit 183f0b0

Browse files
Vitaly DavydovCommitfest Bot
Vitaly Davydov
authored and
Commitfest Bot
committed
Keep WAL segments by slot's flushed restart LSN
The slot data is flushed to the disk at the beginning of checkpoint. If an existing slot is advanced in the middle of checkpoint execution, its advanced restart LSN is taken to calculate the oldest LSN for WAL segments removal at the end of checkpoint. If the node is restarted just after the checkpoint, the slots data will be read from the disk at recovery with the oldest restart LSN which can refer to removed WAL segments. The patch introduces a new in-memory state for slots - flushed_restart_lsn which is used to calculate the oldest LSN for WAL segments removal. This state is updated every time with the current restart_lsn at the moment, when the slot is saving to disk.
1 parent f8c115a commit 183f0b0

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

src/backend/replication/slot.c

+41
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ ReplicationSlotCreate(const char *name, bool db_specific,
424424
slot->candidate_restart_valid = InvalidXLogRecPtr;
425425
slot->candidate_restart_lsn = InvalidXLogRecPtr;
426426
slot->last_saved_confirmed_flush = InvalidXLogRecPtr;
427+
slot->restart_lsn_flushed = InvalidXLogRecPtr;
427428
slot->inactive_since = 0;
428429

429430
/*
@@ -1165,20 +1166,36 @@ ReplicationSlotsComputeRequiredLSN(void)
11651166
{
11661167
ReplicationSlot *s = &ReplicationSlotCtl->replication_slots[i];
11671168
XLogRecPtr restart_lsn;
1169+
XLogRecPtr restart_lsn_flushed;
11681170
bool invalidated;
1171+
ReplicationSlotPersistency persistency;
11691172

11701173
if (!s->in_use)
11711174
continue;
11721175

11731176
SpinLockAcquire(&s->mutex);
1177+
persistency = s->data.persistency;
11741178
restart_lsn = s->data.restart_lsn;
11751179
invalidated = s->data.invalidated != RS_INVAL_NONE;
1180+
restart_lsn_flushed = s->restart_lsn_flushed;
11761181
SpinLockRelease(&s->mutex);
11771182

11781183
/* invalidated slots need not apply */
11791184
if (invalidated)
11801185
continue;
11811186

1187+
/* Get the flushed restart_lsn for the persistent slot to compute
1188+
* the oldest LSN for WAL segments removals.
1189+
*/
1190+
if (persistency == RS_PERSISTENT)
1191+
{
1192+
if (restart_lsn_flushed != InvalidXLogRecPtr &&
1193+
restart_lsn > restart_lsn_flushed)
1194+
{
1195+
restart_lsn = restart_lsn_flushed;
1196+
}
1197+
}
1198+
11821199
if (restart_lsn != InvalidXLogRecPtr &&
11831200
(min_required == InvalidXLogRecPtr ||
11841201
restart_lsn < min_required))
@@ -1216,7 +1233,9 @@ ReplicationSlotsComputeLogicalRestartLSN(void)
12161233
{
12171234
ReplicationSlot *s;
12181235
XLogRecPtr restart_lsn;
1236+
XLogRecPtr restart_lsn_flushed;
12191237
bool invalidated;
1238+
ReplicationSlotPersistency persistency;
12201239

12211240
s = &ReplicationSlotCtl->replication_slots[i];
12221241

@@ -1230,14 +1249,28 @@ ReplicationSlotsComputeLogicalRestartLSN(void)
12301249

12311250
/* read once, it's ok if it increases while we're checking */
12321251
SpinLockAcquire(&s->mutex);
1252+
persistency = s->data.persistency;
12331253
restart_lsn = s->data.restart_lsn;
12341254
invalidated = s->data.invalidated != RS_INVAL_NONE;
1255+
restart_lsn_flushed = s->restart_lsn_flushed;
12351256
SpinLockRelease(&s->mutex);
12361257

12371258
/* invalidated slots need not apply */
12381259
if (invalidated)
12391260
continue;
12401261

1262+
/* Get the flushed restart_lsn for the persistent slot to compute
1263+
* the oldest LSN for WAL segments removals.
1264+
*/
1265+
if (persistency == RS_PERSISTENT)
1266+
{
1267+
if (restart_lsn_flushed != InvalidXLogRecPtr &&
1268+
restart_lsn > restart_lsn_flushed)
1269+
{
1270+
restart_lsn = restart_lsn_flushed;
1271+
}
1272+
}
1273+
12411274
if (restart_lsn == InvalidXLogRecPtr)
12421275
continue;
12431276

@@ -1455,6 +1488,7 @@ ReplicationSlotReserveWal(void)
14551488

14561489
Assert(slot != NULL);
14571490
Assert(slot->data.restart_lsn == InvalidXLogRecPtr);
1491+
Assert(slot->restart_lsn_flushed == InvalidXLogRecPtr);
14581492

14591493
/*
14601494
* The replication slot mechanism is used to prevent removal of required
@@ -1766,6 +1800,8 @@ InvalidatePossiblyObsoleteSlot(uint32 possible_causes,
17661800
*/
17671801
SpinLockAcquire(&s->mutex);
17681802

1803+
Assert(s->data.restart_lsn >= s->restart_lsn_flushed);
1804+
17691805
restart_lsn = s->data.restart_lsn;
17701806

17711807
/* we do nothing if the slot is already invalid */
@@ -1835,7 +1871,10 @@ InvalidatePossiblyObsoleteSlot(uint32 possible_causes,
18351871
* just rely on .invalidated.
18361872
*/
18371873
if (invalidation_cause == RS_INVAL_WAL_REMOVED)
1874+
{
18381875
s->data.restart_lsn = InvalidXLogRecPtr;
1876+
s->restart_lsn_flushed = InvalidXLogRecPtr;
1877+
}
18391878

18401879
/* Let caller know */
18411880
*invalidated = true;
@@ -2354,6 +2393,7 @@ SaveSlotToPath(ReplicationSlot *slot, const char *dir, int elevel)
23542393
if (!slot->just_dirtied)
23552394
slot->dirty = false;
23562395
slot->last_saved_confirmed_flush = cp.slotdata.confirmed_flush;
2396+
slot->restart_lsn_flushed = cp.slotdata.restart_lsn;
23572397
SpinLockRelease(&slot->mutex);
23582398

23592399
LWLockRelease(&slot->io_in_progress_lock);
@@ -2569,6 +2609,7 @@ RestoreSlotFromDisk(const char *name)
25692609
slot->effective_xmin = cp.slotdata.xmin;
25702610
slot->effective_catalog_xmin = cp.slotdata.catalog_xmin;
25712611
slot->last_saved_confirmed_flush = cp.slotdata.confirmed_flush;
2612+
slot->restart_lsn_flushed = cp.slotdata.restart_lsn;
25722613

25732614
slot->candidate_catalog_xmin = InvalidTransactionId;
25742615
slot->candidate_xmin_lsn = InvalidXLogRecPtr;

src/include/replication/slot.h

+7
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@ typedef struct ReplicationSlot
215215
* recently stopped.
216216
*/
217217
TimestampTz inactive_since;
218+
219+
/* Latest restart_lsn that has been flushed to disk. For persistent slots
220+
* the flushed LSN should be taken into account when calculating the oldest
221+
* LSN for WAL segments removal.
222+
*/
223+
XLogRecPtr restart_lsn_flushed;
224+
218225
} ReplicationSlot;
219226

220227
#define SlotIsPhysical(slot) ((slot)->data.database == InvalidOid)

0 commit comments

Comments
 (0)