summaryrefslogtreecommitdiff
path: root/src/backend/replication/slot.c
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2021-07-16 12:07:30 -0400
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2021-07-16 12:07:30 -0400
commitead9e51e82363a0e492d56aee83ed11b3759a615 (patch)
treeeb7e261b626d5f13bd872753b3970d7305e01dc6 /src/backend/replication/slot.c
parent46111fb7b57876a87eb0630ec12ad30950e38a39 (diff)
downloadpostgresql-ead9e51e82363a0e492d56aee83ed11b3759a615.tar.gz
Advance old-segment horizon properly after slot invalidation
When some slots are invalidated due to the max_slot_wal_keep_size limit, the old segment horizon should move forward to stay within the limit. However, in commit c6550776394e we forgot to call KeepLogSeg again to recompute the horizon after invalidating replication slots. In cases where other slots remained, the limits would be recomputed eventually for other reasons, but if all slots were invalidated, the limits would not move at all afterwards. Repair. Backpatch to 13 where the feature was introduced. Author: Kyotaro Horiguchi <horikyota.ntt@gmail.com> Reported-by: Marcin Krupowicz <mk@071.ovh> Discussion: https://postgr.es/m/17103-004130e8f27782c9@postgresql.org
Diffstat (limited to 'src/backend/replication/slot.c')
-rw-r--r--src/backend/replication/slot.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 33b85d86cc..33e9acab4a 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -1143,11 +1143,14 @@ ReplicationSlotReserveWal(void)
* Returns whether ReplicationSlotControlLock was released in the interim (and
* in that case we're not holding the lock at return, otherwise we are).
*
+ * Sets *invalidated true if the slot was invalidated. (Untouched otherwise.)
+ *
* This is inherently racy, because we release the LWLock
* for syscalls, so caller must restart if we return true.
*/
static bool
-InvalidatePossiblyObsoleteSlot(ReplicationSlot *s, XLogRecPtr oldestLSN)
+InvalidatePossiblyObsoleteSlot(ReplicationSlot *s, XLogRecPtr oldestLSN,
+ bool *invalidated)
{
int last_signaled_pid = 0;
bool released_lock = false;
@@ -1204,6 +1207,9 @@ InvalidatePossiblyObsoleteSlot(ReplicationSlot *s, XLogRecPtr oldestLSN)
s->active_pid = MyProcPid;
s->data.invalidated_at = restart_lsn;
s->data.restart_lsn = InvalidXLogRecPtr;
+
+ /* Let caller know */
+ *invalidated = true;
}
SpinLockRelease(&s->mutex);
@@ -1291,12 +1297,15 @@ InvalidatePossiblyObsoleteSlot(ReplicationSlot *s, XLogRecPtr oldestLSN)
* Mark any slot that points to an LSN older than the given segment
* as invalid; it requires WAL that's about to be removed.
*
+ * Returns true when any slot have got invalidated.
+ *
* NB - this runs as part of checkpoint, so avoid raising errors if possible.
*/
-void
+bool
InvalidateObsoleteReplicationSlots(XLogSegNo oldestSegno)
{
XLogRecPtr oldestLSN;
+ bool invalidated = false;
XLogSegNoOffsetToRecPtr(oldestSegno, 0, wal_segment_size, oldestLSN);
@@ -1309,13 +1318,24 @@ restart:
if (!s->in_use)
continue;
- if (InvalidatePossiblyObsoleteSlot(s, oldestLSN))
+ if (InvalidatePossiblyObsoleteSlot(s, oldestLSN, &invalidated))
{
/* if the lock was released, start from scratch */
goto restart;
}
}
LWLockRelease(ReplicationSlotControlLock);
+
+ /*
+ * If any slots have been invalidated, recalculate the resource limits.
+ */
+ if (invalidated)
+ {
+ ReplicationSlotsComputeRequiredXmin(false);
+ ReplicationSlotsComputeRequiredLSN();
+ }
+
+ return invalidated;
}
/*