diff options
author | Andres Freund <andres@anarazel.de> | 2018-10-31 14:47:41 -0700 |
---|---|---|
committer | Andres Freund <andres@anarazel.de> | 2018-10-31 15:46:40 -0700 |
commit | d35fd17cb58db72122912b57c75c8825ebf24285 (patch) | |
tree | 42a159b248dcbfe153bc4823d48a23123c233c57 | |
parent | 558571afc7c42c47243836c411ad86fc6c0577c5 (diff) | |
download | postgresql-d35fd17cb58db72122912b57c75c8825ebf24285.tar.gz |
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
-rw-r--r-- | src/backend/replication/logical/logical.c | 5 | ||||
-rw-r--r-- | src/backend/replication/slot.c | 30 |
2 files changed, 35 insertions, 0 deletions
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c index f44533eb7f..f9ae9cb2d9 100644 --- a/src/backend/replication/logical/logical.c +++ b/src/backend/replication/logical/logical.c @@ -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), diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c index a206fbf234..f914153f1b 100644 --- a/src/backend/replication/slot.c +++ b/src/backend/replication/slot.c @@ -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++) { |