Ignore invalidated slots while computing oldest catalog Xmin
authorAlvaro Herrera
Tue, 22 Nov 2022 09:56:07 +0000 (10:56 +0100)
committerAlvaro Herrera
Tue, 22 Nov 2022 09:56:07 +0000 (10:56 +0100)
Once a logical slot has acquired a catalog_xmin, it doesn't let go of
it, even when invalidated by exceeding the max_slot_wal_keep_size, which
means that dead catalog tuples are not removed by vacuum anymore since
the point is invalidated, until the slot is dropped.  This could be
catastrophic if catalog churn is high.

Change the computation of Xmin to ignore invalidated slots,
to prevent dead rows from accumulating.

Backpatch to 13, where slot invalidation appeared.

Author: Sirisha Chamarthi 
Reviewed-by: Ashutosh Bapat
Discussion: https://postgr.es/m/CAKrAKeUEDeqquN9vwzNeG-CN8wuVsfRYbeOUV9qKO_RHok=j+g@mail.gmail.com

src/backend/replication/slot.c
src/backend/storage/ipc/procarray.c

index 3f348321518ede86bdfbfd989231dc64c283f7b5..037a347cba0171a3c55e721848dc4315105740de 100644 (file)
@@ -778,6 +778,7 @@ ReplicationSlotsComputeRequiredXmin(bool already_locked)
        ReplicationSlot *s = &ReplicationSlotCtl->replication_slots[i];
        TransactionId effective_xmin;
        TransactionId effective_catalog_xmin;
+       bool        invalidated;
 
        if (!s->in_use)
            continue;
@@ -785,8 +786,14 @@ ReplicationSlotsComputeRequiredXmin(bool already_locked)
        SpinLockAcquire(&s->mutex);
        effective_xmin = s->effective_xmin;
        effective_catalog_xmin = s->effective_catalog_xmin;
+       invalidated = (!XLogRecPtrIsInvalid(s->data.invalidated_at) &&
+                      XLogRecPtrIsInvalid(s->data.restart_lsn));
        SpinLockRelease(&s->mutex);
 
+       /* invalidated slots need not apply */
+       if (invalidated)
+           continue;
+
        /* check the data xmin */
        if (TransactionIdIsValid(effective_xmin) &&
            (!TransactionIdIsValid(agg_xmin) ||
index 755f842d6a7e6b058f9a8757592478b70a0c197a..ea8278645e4a5f28961d3ba07d897b94f7dee08c 100644 (file)
@@ -3946,6 +3946,9 @@ ProcArraySetReplicationSlotXmin(TransactionId xmin, TransactionId catalog_xmin,
 
    if (!already_locked)
        LWLockRelease(ProcArrayLock);
+
+   elog(DEBUG1, "xmin required by slots: data %u, catalog %u",
+        xmin, catalog_xmin);
 }
 
 /*