]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Disallow starting server with insufficient wal_level for existing slot.
authorAndres Freund <andres@anarazel.de>
Wed, 31 Oct 2018 21:47:41 +0000 (14:47 -0700)
committerAndres Freund <andres@anarazel.de>
Wed, 31 Oct 2018 22:46:40 +0000 (15:46 -0700)
Previously it was possible to create a slot, change wal_level, and
restart, even if the new wal_level was insufficient for the
slot. That's a problem for both logical and physical slots, because
the necessary WAL records are not generated.

This removes a few tests in newer versions that, somewhat
inexplicably, whether restarting with a too low wal_level worked (a
buggy behaviour!).

Reported-By: Joshua D. Drake
Author: Andres Freund
Discussion: https://postgr.es/m/20181029191304.lbsmhshkyymhw22w@alap3.anarazel.de
Backpatch: 9.4-, where replication slots where introduced

src/backend/replication/logical/logical.c
src/backend/replication/slot.c

index f44533eb7f75b8ee26aa8963eaf2eacd1342df76..f9ae9cb2d9a33c452fb103b5c7f3a00f52af3cf9 100644 (file)
@@ -77,6 +77,11 @@ CheckLogicalDecodingRequirements(void)
 {
        CheckSlotRequirements();
 
+       /*
+        * NB: Adding a new requirement likely means that RestoreSlotFromDisk()
+        * needs the same check.
+        */
+
        if (wal_level < WAL_LEVEL_LOGICAL)
                ereport(ERROR,
                                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
index a206fbf234d1030d8048efad6b204d26148c9dfd..f914153f1b3ab745d2cf7a8bb210593bdfd1d7b3 100644 (file)
@@ -783,6 +783,11 @@ ReplicationSlotsCountDBSlots(Oid dboid, int *nslots, int *nactive)
 void
 CheckSlotRequirements(void)
 {
+       /*
+        * NB: Adding a new requirement likely means that RestoreSlotFromDisk()
+        * needs the same check.
+        */
+
        if (max_replication_slots == 0)
                ereport(ERROR,
                                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -1286,6 +1291,31 @@ RestoreSlotFromDisk(const char *name)
                return;
        }
 
+       /*
+        * Verify that requirements for the specific slot type are met. That's
+        * important because if these aren't met we're not guaranteed to retain
+        * all the necessary resources for the slot.
+        *
+        * NB: We have to do so *after* the above checks for ephemeral slots,
+        * because otherwise a slot that shouldn't exist anymore could prevent
+        * restarts.
+        *
+        * NB: Changing the requirements here also requires adapting
+        * CheckSlotRequirements() and CheckLogicalDecodingRequirements().
+        */
+       if (cp.slotdata.database != InvalidOid && wal_level < WAL_LEVEL_LOGICAL)
+               ereport(FATAL,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg("logical replication slots \"%s\" exists, but wal_level < logical",
+                                               NameStr(cp.slotdata.name)),
+                                errhint("Change wal_level to be replica or higher.")));
+       else if (wal_level < WAL_LEVEL_REPLICA)
+               ereport(FATAL,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg("physical replication slots \"%s\" exists, but wal_level < replica",
+                                               NameStr(cp.slotdata.name)),
+                                errhint("Change wal_level to be replica or higher.")));
+
        /* nothing can be active yet, don't lock anything */
        for (i = 0; i < max_replication_slots; i++)
        {