Skip to content

Commit c33a01c

Browse files
committed
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
1 parent 2493e2c commit c33a01c

File tree

3 files changed

+36
-22
lines changed

3 files changed

+36
-22
lines changed

src/backend/replication/logical/logical.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ CheckLogicalDecodingRequirements(void)
7979
{
8080
CheckSlotRequirements();
8181

82+
/*
83+
* NB: Adding a new requirement likely means that RestoreSlotFromDisk()
84+
* needs the same check.
85+
*/
86+
8287
if (wal_level < WAL_LEVEL_LOGICAL)
8388
ereport(ERROR,
8489
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

src/backend/replication/slot.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,11 @@ ReplicationSlotsDropDBSlots(Oid dboid)
972972
void
973973
CheckSlotRequirements(void)
974974
{
975+
/*
976+
* NB: Adding a new requirement likely means that RestoreSlotFromDisk()
977+
* needs the same check.
978+
*/
979+
975980
if (max_replication_slots == 0)
976981
ereport(ERROR,
977982
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -1493,6 +1498,31 @@ RestoreSlotFromDisk(const char *name)
14931498
return;
14941499
}
14951500

1501+
/*
1502+
* Verify that requirements for the specific slot type are met. That's
1503+
* important because if these aren't met we're not guaranteed to retain
1504+
* all the necessary resources for the slot.
1505+
*
1506+
* NB: We have to do so *after* the above checks for ephemeral slots,
1507+
* because otherwise a slot that shouldn't exist anymore could prevent
1508+
* restarts.
1509+
*
1510+
* NB: Changing the requirements here also requires adapting
1511+
* CheckSlotRequirements() and CheckLogicalDecodingRequirements().
1512+
*/
1513+
if (cp.slotdata.database != InvalidOid && wal_level < WAL_LEVEL_LOGICAL)
1514+
ereport(FATAL,
1515+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1516+
errmsg("logical replication slots \"%s\" exists, but wal_level < logical",
1517+
NameStr(cp.slotdata.name)),
1518+
errhint("Change wal_level to be replica or higher.")));
1519+
else if (wal_level < WAL_LEVEL_REPLICA)
1520+
ereport(FATAL,
1521+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1522+
errmsg("physical replication slots \"%s\" exists, but wal_level < replica",
1523+
NameStr(cp.slotdata.name)),
1524+
errhint("Change wal_level to be replica or higher.")));
1525+
14961526
/* nothing can be active yet, don't lock anything */
14971527
for (i = 0; i < max_replication_slots; i++)
14981528
{

src/test/recovery/t/006_logical_decoding.pl

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use warnings;
88
use PostgresNode;
99
use TestLib;
10-
use Test::More tests => 16;
10+
use Test::More tests => 10;
1111
use Config;
1212

1313
# Initialize master node
@@ -135,26 +135,5 @@
135135
is($node_master->slot('otherdb_slot')->{'slot_name'},
136136
undef, 'logical slot was actually dropped with DB');
137137

138-
# Restarting a node with wal_level = logical that has existing
139-
# slots must succeed, but decoding from those slots must fail.
140-
$node_master->safe_psql('postgres', 'ALTER SYSTEM SET wal_level = replica');
141-
is($node_master->safe_psql('postgres', 'SHOW wal_level'),
142-
'logical', 'wal_level is still logical before restart');
143-
$node_master->restart;
144-
is($node_master->safe_psql('postgres', 'SHOW wal_level'),
145-
'replica', 'wal_level is replica');
146-
isnt($node_master->slot('test_slot')->{'catalog_xmin'},
147-
'0', 'restored slot catalog_xmin is nonzero');
148-
is( $node_master->psql(
149-
'postgres',
150-
qq[SELECT pg_logical_slot_get_changes('test_slot', NULL, NULL);]),
151-
3,
152-
'reading from slot with wal_level < logical fails');
153-
is( $node_master->psql(
154-
'postgres', q[SELECT pg_drop_replication_slot('test_slot')]),
155-
0,
156-
'can drop logical slot while wal_level = replica');
157-
is($node_master->slot('test_slot')->{'catalog_xmin'}, '', 'slot was dropped');
158-
159138
# done with the node
160139
$node_master->stop;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy