* Cleanup all temporary slots created in current session.
*/
void
-ReplicationSlotCleanup()
+ReplicationSlotCleanup(void)
{
int i;
* pg_database oid for the database to prevent creation of new slots on the db
* or replay from existing slots.
*
- * This routine isn't as efficient as it could be - but we don't drop databases
- * often, especially databases with lots of 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)
for (i = 0; i < max_replication_slots; i++)
{
ReplicationSlot *s;
- NameData slotname;
+ char *slotname;
int active_pid;
s = &ReplicationSlotCtl->replication_slots[i];
if (s->data.database != dboid)
continue;
- /* Claim the slot, as if ReplicationSlotAcquire()ing. */
+ /* acquire slot, so ReplicationSlotDropAcquired can be reused */
SpinLockAcquire(&s->mutex);
- strncpy(NameStr(slotname), NameStr(s->data.name), NAMEDATALEN);
- NameStr(slotname)[NAMEDATALEN-1] = '\0';
+ /* can't change while ReplicationSlotControlLock is held */
+ slotname = NameStr(s->data.name);
active_pid = s->active_pid;
if (active_pid == 0)
{
SpinLockRelease(&s->mutex);
/*
- * We might fail here if the slot was active. Even though we hold an
- * exclusive lock on the database object a logical slot for that DB can
- * still be active if it's being dropped by a backend connected to
- * another DB or is otherwise acquired.
+ * 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.
*
- * It's an unlikely race that'll only arise from concurrent user action,
- * so we'll just bail out.
+ * That's fairly unlikely in practice, so we'll just bail out.
*/
if (active_pid)
- elog(ERROR, "replication slot %s is in use by pid %d",
- NameStr(slotname), active_pid);
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_IN_USE),
+ errmsg("replication slot \"%s\" is active for PID %d",
+ slotname, active_pid)));
/*
- * To avoid largely duplicating ReplicationSlotDropAcquired() or
- * complicating it with already_locked flags for ProcArrayLock,
- * ReplicationSlotControlLock and ReplicationSlotAllocationLock, we
- * just release our ReplicationSlotControlLock to drop the slot.
+ * To avoid duplicating ReplicationSlotDropAcquired() and to avoid
+ * holding ReplicationSlotControlLock over filesystem operations,
+ * release ReplicationSlotControlLock and use
+ * ReplicationSlotDropAcquired.
*
- * For safety we'll restart our scan from the beginning each
- * time we release the lock.
+ * 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);
-
- /* recompute limits once after all slots are dropped */
- ReplicationSlotsComputeRequiredXmin(false);
- ReplicationSlotsComputeRequiredLSN();
}