summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndres Freund2018-10-31 21:47:41 +0000
committerAndres Freund2018-10-31 22:46:40 +0000
commitcf358a2c066ccb8fc9e82dc59358130aa61075ab (patch)
tree5b67f7cf3e7d5c65009273f8bf2f576cdd70ce41 /src
parent95015b1f8e8eef895ddbfe38697c6da5754ba1d4 (diff)
Disallow starting server with insufficient wal_level for existing slot.
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
Diffstat (limited to 'src')
-rw-r--r--src/backend/replication/logical/logical.c5
-rw-r--r--src/backend/replication/slot.c30
2 files changed, 35 insertions, 0 deletions
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 3745edb445d..29b8cbaaf9c 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -72,6 +72,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),
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index a538ae17541..909d9f3df4c 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -795,6 +795,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),
@@ -1236,6 +1241,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_ARCHIVE)
+ ereport(FATAL,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("physical replication slots \"%s\" exists, but wal_level < archive",
+ NameStr(cp.slotdata.name)),
+ errhint("Change wal_level to be archive or higher.")));
+
/* nothing can be active yet, don't lock anything */
for (i = 0; i < max_replication_slots; i++)
{