@@ -424,6 +424,7 @@ ReplicationSlotCreate(const char *name, bool db_specific,
424
424
slot -> candidate_restart_valid = InvalidXLogRecPtr ;
425
425
slot -> candidate_restart_lsn = InvalidXLogRecPtr ;
426
426
slot -> last_saved_confirmed_flush = InvalidXLogRecPtr ;
427
+ slot -> last_saved_restart_lsn = InvalidXLogRecPtr ;
427
428
slot -> inactive_since = 0 ;
428
429
429
430
/*
@@ -1165,20 +1166,41 @@ ReplicationSlotsComputeRequiredLSN(void)
1165
1166
{
1166
1167
ReplicationSlot * s = & ReplicationSlotCtl -> replication_slots [i ];
1167
1168
XLogRecPtr restart_lsn ;
1169
+ XLogRecPtr last_saved_restart_lsn ;
1168
1170
bool invalidated ;
1171
+ ReplicationSlotPersistency persistency ;
1169
1172
1170
1173
if (!s -> in_use )
1171
1174
continue ;
1172
1175
1173
1176
SpinLockAcquire (& s -> mutex );
1177
+ persistency = s -> data .persistency ;
1174
1178
restart_lsn = s -> data .restart_lsn ;
1175
1179
invalidated = s -> data .invalidated != RS_INVAL_NONE ;
1180
+ last_saved_restart_lsn = s -> last_saved_restart_lsn ;
1176
1181
SpinLockRelease (& s -> mutex );
1177
1182
1178
1183
/* invalidated slots need not apply */
1179
1184
if (invalidated )
1180
1185
continue ;
1181
1186
1187
+ /*
1188
+ * For persistent slot use last_saved_restart_lsn to compute the
1189
+ * oldest LSN for removal of WAL segments. The segments between
1190
+ * last_saved_restart_lsn and restart_lsn might be needed by a
1191
+ * persistent slot in the case of database crash. Non-persistent
1192
+ * slots can't survive the database crash, so we don't care about
1193
+ * last_saved_restart_lsn for them.
1194
+ */
1195
+ if (persistency == RS_PERSISTENT )
1196
+ {
1197
+ if (last_saved_restart_lsn != InvalidXLogRecPtr &&
1198
+ restart_lsn > last_saved_restart_lsn )
1199
+ {
1200
+ restart_lsn = last_saved_restart_lsn ;
1201
+ }
1202
+ }
1203
+
1182
1204
if (restart_lsn != InvalidXLogRecPtr &&
1183
1205
(min_required == InvalidXLogRecPtr ||
1184
1206
restart_lsn < min_required ))
@@ -1216,7 +1238,9 @@ ReplicationSlotsComputeLogicalRestartLSN(void)
1216
1238
{
1217
1239
ReplicationSlot * s ;
1218
1240
XLogRecPtr restart_lsn ;
1241
+ XLogRecPtr last_saved_restart_lsn ;
1219
1242
bool invalidated ;
1243
+ ReplicationSlotPersistency persistency ;
1220
1244
1221
1245
s = & ReplicationSlotCtl -> replication_slots [i ];
1222
1246
@@ -1230,14 +1254,33 @@ ReplicationSlotsComputeLogicalRestartLSN(void)
1230
1254
1231
1255
/* read once, it's ok if it increases while we're checking */
1232
1256
SpinLockAcquire (& s -> mutex );
1257
+ persistency = s -> data .persistency ;
1233
1258
restart_lsn = s -> data .restart_lsn ;
1234
1259
invalidated = s -> data .invalidated != RS_INVAL_NONE ;
1260
+ last_saved_restart_lsn = s -> last_saved_restart_lsn ;
1235
1261
SpinLockRelease (& s -> mutex );
1236
1262
1237
1263
/* invalidated slots need not apply */
1238
1264
if (invalidated )
1239
1265
continue ;
1240
1266
1267
+ /*
1268
+ * For persistent slot use last_saved_restart_lsn to compute the
1269
+ * oldest LSN for removal of WAL segments. The segments between
1270
+ * last_saved_restart_lsn and restart_lsn might be needed by a
1271
+ * persistent slot in the case of database crash. Non-persistent
1272
+ * slots can't survive the database crash, so we don't care about
1273
+ * last_saved_restart_lsn for them.
1274
+ */
1275
+ if (persistency == RS_PERSISTENT )
1276
+ {
1277
+ if (last_saved_restart_lsn != InvalidXLogRecPtr &&
1278
+ restart_lsn > last_saved_restart_lsn )
1279
+ {
1280
+ restart_lsn = last_saved_restart_lsn ;
1281
+ }
1282
+ }
1283
+
1241
1284
if (restart_lsn == InvalidXLogRecPtr )
1242
1285
continue ;
1243
1286
@@ -1455,6 +1498,7 @@ ReplicationSlotReserveWal(void)
1455
1498
1456
1499
Assert (slot != NULL );
1457
1500
Assert (slot -> data .restart_lsn == InvalidXLogRecPtr );
1501
+ Assert (slot -> last_saved_restart_lsn == InvalidXLogRecPtr );
1458
1502
1459
1503
/*
1460
1504
* The replication slot mechanism is used to prevent removal of required
@@ -1766,6 +1810,8 @@ InvalidatePossiblyObsoleteSlot(uint32 possible_causes,
1766
1810
*/
1767
1811
SpinLockAcquire (& s -> mutex );
1768
1812
1813
+ Assert (s -> data .restart_lsn >= s -> last_saved_restart_lsn );
1814
+
1769
1815
restart_lsn = s -> data .restart_lsn ;
1770
1816
1771
1817
/* we do nothing if the slot is already invalid */
@@ -1835,7 +1881,10 @@ InvalidatePossiblyObsoleteSlot(uint32 possible_causes,
1835
1881
* just rely on .invalidated.
1836
1882
*/
1837
1883
if (invalidation_cause == RS_INVAL_WAL_REMOVED )
1884
+ {
1838
1885
s -> data .restart_lsn = InvalidXLogRecPtr ;
1886
+ s -> last_saved_restart_lsn = InvalidXLogRecPtr ;
1887
+ }
1839
1888
1840
1889
/* Let caller know */
1841
1890
* invalidated = true;
@@ -2079,6 +2128,12 @@ CheckPointReplicationSlots(bool is_shutdown)
2079
2128
SaveSlotToPath (s , path , LOG );
2080
2129
}
2081
2130
LWLockRelease (ReplicationSlotAllocationLock );
2131
+
2132
+ /*
2133
+ * Recompute the required LSN as SaveSlotToPath() updated
2134
+ * last_saved_restart_lsn for slots.
2135
+ */
2136
+ ReplicationSlotsComputeRequiredLSN ();
2082
2137
}
2083
2138
2084
2139
/*
@@ -2354,6 +2409,7 @@ SaveSlotToPath(ReplicationSlot *slot, const char *dir, int elevel)
2354
2409
if (!slot -> just_dirtied )
2355
2410
slot -> dirty = false;
2356
2411
slot -> last_saved_confirmed_flush = cp .slotdata .confirmed_flush ;
2412
+ slot -> last_saved_restart_lsn = cp .slotdata .restart_lsn ;
2357
2413
SpinLockRelease (& slot -> mutex );
2358
2414
2359
2415
LWLockRelease (& slot -> io_in_progress_lock );
@@ -2569,6 +2625,7 @@ RestoreSlotFromDisk(const char *name)
2569
2625
slot -> effective_xmin = cp .slotdata .xmin ;
2570
2626
slot -> effective_catalog_xmin = cp .slotdata .catalog_xmin ;
2571
2627
slot -> last_saved_confirmed_flush = cp .slotdata .confirmed_flush ;
2628
+ slot -> last_saved_restart_lsn = cp .slotdata .restart_lsn ;
2572
2629
2573
2630
slot -> candidate_catalog_xmin = InvalidTransactionId ;
2574
2631
slot -> candidate_xmin_lsn = InvalidXLogRecPtr ;
0 commit comments