Don't let ReplicationSlotAcquire succeed in the midst of ReplicationSlotCreate.
authorAndres Freund <andres@anarazel.de>
Tue, 28 Jan 2014 17:51:33 +0000 (18:51 +0100)
committerAndres Freund <andres@anarazel.de>
Tue, 28 Jan 2014 18:36:52 +0000 (19:36 +0100)
src/backend/replication/slot.c

index f3894f150252b6a81796b79e7d0a4393c817df41..cc376b8b0a53aad54d3b21370b0d9e6944b4b955 100644 (file)
@@ -261,27 +261,32 @@ ReplicationSlotCreate(const char *name, bool db_specific)
 
        /*
         * We need to briefly prevent any other backend from iterating over the
-        * slots while we flip the in_use flag.
+        * slots while we flip the in_use flag. We also need to set the active
+        * flag while holding the ControlLock as otherwise a concurrent
+        * SlotAcquire() could acquire the slot as well.
         */
        LWLockAcquire(ReplicationSlotControlLock, LW_EXCLUSIVE);
-       slot->in_use = true;
-       LWLockRelease(ReplicationSlotControlLock);
 
-       /*
-        * Now that the slot has been marked as in_use, it's safe to let somebody
-        * else try to allocate a slot.
-        */
-       LWLockRelease(ReplicationSlotAllocationLock);
+       slot->in_use = true;
 
        /* We can now mark the slot active, and that makes it our slot. */
        {
                volatile ReplicationSlot *vslot = slot;
 
                SpinLockAcquire(&slot->mutex);
+               Assert(!vslot->active);
                vslot->active = true;
                SpinLockRelease(&slot->mutex);
                MyReplicationSlot = slot;
        }
+
+       LWLockRelease(ReplicationSlotControlLock);
+
+       /*
+        * Now that the slot has been marked as in_use and in_active, it's safe to
+        * let somebody else try to allocate a slot.
+        */
+       LWLockRelease(ReplicationSlotAllocationLock);
 }
 
 /*