/* * Release a replication slot, this or another backend can ReAcquire it * later. Resources this slot requires will be preserved. */ void ReplicationSlotRelease(void) { ReplicationSlot *slot = MyReplicationSlot; Assert(slot != NULL && slot->active_pid != 0); if (slot->data.persistency == RS_EPHEMERAL) { /* * Delete the slot. There is no !PANIC case where this is allowed to * fail, all that may happen is an incomplete cleanup of the on-disk * data. */ ReplicationSlotDropAcquired(); } else { /* Mark slot inactive. We're not freeing it, just disconnecting. */ SpinLockAcquire(&slot->mutex); slot->active_pid = 0; SpinLockRelease(&slot->mutex); } MyReplicationSlot = NULL; /* might not have been set when we've been a plain slot */ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); MyPgXact->vacuumFlags &= ~PROC_IN_LOGICAL_DECODING; LWLockRelease(ProcArrayLock); }
/* * Permanently drop replication slot identified by the passed in name. */ void ReplicationSlotDrop(const char *name, bool nowait) { Assert(MyReplicationSlot == NULL); ReplicationSlotAcquire(name, nowait); ReplicationSlotDropAcquired(); }
/* * Permanently drop replication slot identified by the passed in name. */ void ReplicationSlotDrop(const char *name) { Assert(MyReplicationSlot == NULL); ReplicationSlotAcquire(name); ReplicationSlotDropAcquired(); }
/* * Release the replication slot that this backend considers to own. * * This or another backend can re-acquire the slot later. * Resources this slot requires will be preserved. */ void ReplicationSlotRelease(void) { ReplicationSlot *slot = MyReplicationSlot; Assert(slot != NULL && slot->active_pid != 0); if (slot->data.persistency == RS_EPHEMERAL) { /* * Delete the slot. There is no !PANIC case where this is allowed to * fail, all that may happen is an incomplete cleanup of the on-disk * data. */ ReplicationSlotDropAcquired(); } /* * If slot needed to temporarily restrain both data and catalog xmin to * create the catalog snapshot, remove that temporary constraint. * Snapshots can only be exported while the initial snapshot is still * acquired. */ if (!TransactionIdIsValid(slot->data.xmin) && TransactionIdIsValid(slot->effective_xmin)) { SpinLockAcquire(&slot->mutex); slot->effective_xmin = InvalidTransactionId; SpinLockRelease(&slot->mutex); ReplicationSlotsComputeRequiredXmin(false); } if (slot->data.persistency == RS_PERSISTENT) { /* * Mark persistent slot inactive. We're not freeing it, just * disconnecting, but wake up others that may be waiting for it. */ SpinLockAcquire(&slot->mutex); slot->active_pid = 0; SpinLockRelease(&slot->mutex); ConditionVariableBroadcast(&slot->active_cv); } MyReplicationSlot = NULL; /* might not have been set when we've been a plain slot */ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); MyPgXact->vacuumFlags &= ~PROC_IN_LOGICAL_DECODING; LWLockRelease(ProcArrayLock); }
/* * ReplicationSlotsDropDBSlots -- Drop all db-specific slots relating to the * passed database oid. The caller should hold an exclusive lock on the * pg_database oid for the database to prevent creation of new slots on the db * or replay from existing slots. * * Another session that concurrently acquires an existing slot on the target DB * (most likely to drop it) may cause this function to ERROR. If that happens * it may have dropped some but not all slots. * * This routine isn't as efficient as it could be - but we don't drop * databases often, especially databases with lots of slots. */ void ReplicationSlotsDropDBSlots(Oid dboid) { int i; if (max_replication_slots <= 0) return; restart: LWLockAcquire(ReplicationSlotControlLock, LW_SHARED); for (i = 0; i < max_replication_slots; i++) { ReplicationSlot *s; char *slotname; int active_pid; s = &ReplicationSlotCtl->replication_slots[i]; /* cannot change while ReplicationSlotCtlLock is held */ if (!s->in_use) continue; /* only logical slots are database specific, skip */ if (!SlotIsLogical(s)) continue; /* not our database, skip */ if (s->data.database != dboid) continue; /* acquire slot, so ReplicationSlotDropAcquired can be reused */ SpinLockAcquire(&s->mutex); /* can't change while ReplicationSlotControlLock is held */ slotname = NameStr(s->data.name); active_pid = s->active_pid; if (active_pid == 0) { MyReplicationSlot = s; s->active_pid = MyProcPid; } SpinLockRelease(&s->mutex); /* * Even though we hold an exclusive lock on the database object a * logical slot for that DB can still be active, e.g. if it's * concurrently being dropped by a backend connected to another DB. * * That's fairly unlikely in practice, so we'll just bail out. */ if (active_pid) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("replication slot \"%s\" is active for PID %d", slotname, active_pid))); /* * To avoid duplicating ReplicationSlotDropAcquired() and to avoid * holding ReplicationSlotControlLock over filesystem operations, * release ReplicationSlotControlLock and use * ReplicationSlotDropAcquired. * * As that means the set of slots could change, restart scan from the * beginning each time we release the lock. */ LWLockRelease(ReplicationSlotControlLock); ReplicationSlotDropAcquired(); goto restart; } LWLockRelease(ReplicationSlotControlLock); }