Ignore invalidated slots while computing oldest catalog Xmin
authorAlvaro Herrera <[email protected]>
Tue, 22 Nov 2022 09:56:07 +0000 (10:56 +0100)
committerAlvaro Herrera <[email protected]>
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 <[email protected]>
Reviewed-by: Ashutosh Bapat <[email protected]>
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 02047ea92072d30bdb050165a139b7757d9fab39..219d126d36df389b33d009be263559ce6ae6f99b 100644 (file)
@@ -766,6 +766,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;
@@ -773,8 +774,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 251ba9ebb9f4561704079a4f9c5fe1a106b4ce10..baad347eac1f6549664d3b67fe2dc411c11c92ec 100644 (file)
@@ -3203,6 +3203,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);
 }
 
 /*