diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c index 4bc2be33396..33b7da21a94 100644 --- a/src/backend/replication/slot.c +++ b/src/backend/replication/slot.c @@ -1577,11 +1577,6 @@ InvalidatePossiblyObsoleteSlot(ReplicationSlotInvalidationCause cause, { int last_signaled_pid = 0; bool released_lock = false; - bool terminated = false; - TransactionId initial_effective_xmin = InvalidTransactionId; - TransactionId initial_catalog_effective_xmin = InvalidTransactionId; - XLogRecPtr initial_restart_lsn = InvalidXLogRecPtr; - ReplicationSlotInvalidationCause invalidation_cause_prev PG_USED_FOR_ASSERTS_ONLY = RS_INVAL_NONE; for (;;) { @@ -1613,24 +1608,11 @@ InvalidatePossiblyObsoleteSlot(ReplicationSlotInvalidationCause cause, /* we do nothing if the slot is already invalid */ if (s->data.invalidated == RS_INVAL_NONE) { - /* - * The slot's mutex will be released soon, and it is possible that - * those values change since the process holding the slot has been - * terminated (if any), so record them here to ensure that we - * would report the correct invalidation cause. - */ - if (!terminated) - { - initial_restart_lsn = s->data.restart_lsn; - initial_effective_xmin = s->effective_xmin; - initial_catalog_effective_xmin = s->effective_catalog_xmin; - } - switch (cause) { case RS_INVAL_WAL_REMOVED: - if (initial_restart_lsn != InvalidXLogRecPtr && - initial_restart_lsn < oldestLSN) + if (s->data.restart_lsn != InvalidXLogRecPtr && + s->data.restart_lsn < oldestLSN) invalidation_cause = cause; break; case RS_INVAL_HORIZON: @@ -1639,12 +1621,12 @@ InvalidatePossiblyObsoleteSlot(ReplicationSlotInvalidationCause cause, /* invalid DB oid signals a shared relation */ if (dboid != InvalidOid && dboid != s->data.database) break; - if (TransactionIdIsValid(initial_effective_xmin) && - TransactionIdPrecedesOrEquals(initial_effective_xmin, + if (TransactionIdIsValid(s->effective_xmin) && + TransactionIdPrecedesOrEquals(s->effective_xmin, snapshotConflictHorizon)) invalidation_cause = cause; - else if (TransactionIdIsValid(initial_catalog_effective_xmin) && - TransactionIdPrecedesOrEquals(initial_catalog_effective_xmin, + else if (TransactionIdIsValid(s->effective_catalog_xmin) && + TransactionIdPrecedesOrEquals(s->effective_catalog_xmin, snapshotConflictHorizon)) invalidation_cause = cause; break; @@ -1657,13 +1639,6 @@ InvalidatePossiblyObsoleteSlot(ReplicationSlotInvalidationCause cause, } } - /* - * The invalidation cause recorded previously should not change while - * the process owning the slot (if any) has been terminated. - */ - Assert(!(invalidation_cause_prev != RS_INVAL_NONE && terminated && - invalidation_cause_prev != invalidation_cause)); - /* if there's no invalidation, we're done */ if (invalidation_cause == RS_INVAL_NONE) { @@ -1738,8 +1713,6 @@ InvalidatePossiblyObsoleteSlot(ReplicationSlotInvalidationCause cause, (void) kill(active_pid, SIGTERM); last_signaled_pid = active_pid; - terminated = true; - invalidation_cause_prev = invalidation_cause; } /* Wait until the slot is released. */ @@ -1750,6 +1723,14 @@ InvalidatePossiblyObsoleteSlot(ReplicationSlotInvalidationCause cause, * Re-acquire lock and start over; we expect to invalidate the * slot next time (unless another process acquires the slot in the * meantime). + * + * Note: It is possible for a slot to advance its restart_lsn or + * xmin values sufficiently between when we release the mutex and + * when we recheck, moving from a conflicting state to a non + * conflicting state. This is intentional and safe: if the slot + * has caught up while we're busy here, the resources we were + * concerned about (WAL segments or tuples) have not yet been + * removed, and there's no reason to invalidate the slot. */ LWLockAcquire(ReplicationSlotControlLock, LW_SHARED); continue;