v12-0001-Validate-max_slot_wal_keep_size-in-pg_createsubs.patch
application/octet-stream
Filename: v12-0001-Validate-max_slot_wal_keep_size-in-pg_createsubs.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v12-0001
Subject: Validate-max_slot_wal_keep_size-in-pg_createsubscriber
| File | + | − |
|---|---|---|
| doc/src/sgml/ref/pg_createsubscriber.sgml | 7 | 0 |
| src/bin/pg_basebackup/pg_createsubscriber.c | 19 | 1 |
| src/bin/pg_basebackup/t/040_pg_createsubscriber.pl | 51 | 16 |
From 80a8e6d61f955f94a08f7f6cb443fc44035cd45c Mon Sep 17 00:00:00 2001
From: Khanna <Shubham.Khanna@fujitsu.com>
Date: Wed, 22 Jan 2025 16:32:58 +0530
Subject: [PATCH v12] Validate-max_slot_wal_keep_size-in-pg_createsubscriber
This patch introduces validation for the 'max_slot_wal_keep_size' GUC in the
'pg_createsubscriber' utility. The utility now checks that the publisher's
'max_slot_wal_keep_size' is set to '-1' during subscription creation.
This ensures proper functioning of logical replication slots.
The 'pg_createsubscriber' utility is updated to fetch and validate the
'max_slot_wal_keep_size' setting from the publisher. A warning is raised during
the '--dry-run' mode if the configuration is set to a non-default value.
This patch logs a warning if 'max_slot_wal_keep_size' is not set to '-1',
highlighting a potential risk of required WAL files being deleted on the
publisher, which could disrupt logical replication.
A test case has been added to validate correct warning reporting
when 'max_slot_wal_keep_size' is misconfigured.
---
doc/src/sgml/ref/pg_createsubscriber.sgml | 7 ++
src/bin/pg_basebackup/pg_createsubscriber.c | 20 +++++-
.../t/040_pg_createsubscriber.pl | 67 ++++++++++++++-----
3 files changed, 77 insertions(+), 17 deletions(-)
diff --git a/doc/src/sgml/ref/pg_createsubscriber.sgml b/doc/src/sgml/ref/pg_createsubscriber.sgml
index 26b8e64a4e..d56487fe2c 100644
--- a/doc/src/sgml/ref/pg_createsubscriber.sgml
+++ b/doc/src/sgml/ref/pg_createsubscriber.sgml
@@ -377,6 +377,13 @@ PostgreSQL documentation
server. If the target server has a standby, replication will break and a
fresh standby should be created.
</para>
+
+ <para>
+ Replication failures can occur if required WAL files are missing. To prevent
+ this, the source server must set
+ <xref linkend="guc-max-slot-wal-keep-size"/> to <literal>-1</literal> to
+ ensure that required WAL files are not prematurely removed.
+ </para>
</refsect2>
<refsect2>
diff --git a/src/bin/pg_basebackup/pg_createsubscriber.c b/src/bin/pg_basebackup/pg_createsubscriber.c
index faf18ccf13..7433c7ae2a 100644
--- a/src/bin/pg_basebackup/pg_createsubscriber.c
+++ b/src/bin/pg_basebackup/pg_createsubscriber.c
@@ -849,6 +849,7 @@ check_publisher(const struct LogicalRepInfo *dbinfo)
int max_walsenders;
int cur_walsenders;
int max_prepared_transactions;
+ char *max_slot_wal_keep_size;
pg_log_info("checking settings on publisher");
@@ -872,6 +873,7 @@ check_publisher(const struct LogicalRepInfo *dbinfo)
* - wal_level = logical
* - max_replication_slots >= current + number of dbs to be converted
* - max_wal_senders >= current + number of dbs to be converted
+ * - max_slot_wal_keep_size = -1 (to prevent deletion of required WAL files)
* -----------------------------------------------------------------------
*/
res = PQexec(conn,
@@ -880,7 +882,8 @@ check_publisher(const struct LogicalRepInfo *dbinfo)
" (SELECT count(*) FROM pg_catalog.pg_replication_slots),"
" pg_catalog.current_setting('max_wal_senders'),"
" (SELECT count(*) FROM pg_catalog.pg_stat_activity WHERE backend_type = 'walsender'),"
- " pg_catalog.current_setting('max_prepared_transactions')");
+ " pg_catalog.current_setting('max_prepared_transactions'),"
+ " pg_catalog.current_setting('max_slot_wal_keep_size')");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
@@ -895,6 +898,7 @@ check_publisher(const struct LogicalRepInfo *dbinfo)
max_walsenders = atoi(PQgetvalue(res, 0, 3));
cur_walsenders = atoi(PQgetvalue(res, 0, 4));
max_prepared_transactions = atoi(PQgetvalue(res, 0, 5));
+ max_slot_wal_keep_size = pg_strdup(PQgetvalue(res, 0, 6));
PQclear(res);
@@ -905,6 +909,8 @@ check_publisher(const struct LogicalRepInfo *dbinfo)
pg_log_debug("publisher: current wal senders: %d", cur_walsenders);
pg_log_debug("publisher: max_prepared_transactions: %d",
max_prepared_transactions);
+ pg_log_debug("publisher: max_slot_wal_keep_size: %s",
+ max_slot_wal_keep_size);
disconnect_database(conn, false);
@@ -939,6 +945,18 @@ check_publisher(const struct LogicalRepInfo *dbinfo)
"Prepared transactions will be replicated at COMMIT PREPARED.");
}
+ /*
+ * Validate 'max_slot_wal_keep_size'. If this parameter is set to a
+ * non-default value, it may cause replication failures due to required
+ * WAL files being prematurely removed.
+ */
+ if (dry_run && (strcmp(max_slot_wal_keep_size, "-1") != 0))
+ {
+ pg_log_warning("publisher requires WAL size must not be restricted");
+ pg_log_warning_hint("Set the configuration parameter \"%s\" to -1 to ensure that required WAL files are not prematurely removed.",
+ "max_slot_wal_keep_size");
+ }
+
pg_free(wal_level);
if (failed)
diff --git a/src/bin/pg_basebackup/t/040_pg_createsubscriber.pl b/src/bin/pg_basebackup/t/040_pg_createsubscriber.pl
index c8dbdb7e9b..c52ae8a40a 100644
--- a/src/bin/pg_basebackup/t/040_pg_createsubscriber.pl
+++ b/src/bin/pg_basebackup/t/040_pg_createsubscriber.pl
@@ -331,25 +331,60 @@ $node_p->safe_psql($db1,
$node_p->wait_for_replay_catchup($node_s);
$node_s->stop;
-# dry run mode on node S
+# Configure 'max_slot_wal_keep_size = 10MB' on the publisher and
+# reload configuration
+$node_p->append_conf('postgresql.conf', 'max_slot_wal_keep_size = 10MB');
+$node_p->reload;
+
+# dry run mode on node S and verify the warning message for misconfigured
+# 'max_slot_wal_keep_size'
+command_checks_all(
+ [
+ 'pg_createsubscriber', '--verbose',
+ '--verbose', '--recovery-timeout',
+ "$PostgreSQL::Test::Utils::timeout_default", '--dry-run',
+ '--pgdata', $node_s->data_dir,
+ '--publisher-server', $node_p->connstr($db1),
+ '--socketdir', $node_s->host,
+ '--subscriber-port', $node_s->port,
+ '--publication', 'pub1',
+ '--publication', 'pub2',
+ '--subscription', 'sub1',
+ '--subscription', 'sub2',
+ '--database', $db1,
+ '--database', $db2
+ ],
+ 0,
+ [qr/./],
+ [
+ qr/pg_createsubscriber: warning: publisher requires WAL size must not be restricted/,
+ qr/Set the configuration parameter "max_slot_wal_keep_size" to -1 to ensure that required WAL files are not prematurely removed./,
+ ],
+ 'Validate warning for misconfigured max_slot_wal_keep_size on the publisher'
+);
+
+# And, same again to see the output...
command_ok(
[
- 'pg_createsubscriber',
- '--verbose',
- '--dry-run',
- '--recovery-timeout' => $PostgreSQL::Test::Utils::timeout_default,
- '--pgdata' => $node_s->data_dir,
- '--publisher-server' => $node_p->connstr($db1),
- '--socketdir' => $node_s->host,
- '--subscriber-port' => $node_s->port,
- '--publication' => 'pub1',
- '--publication' => 'pub2',
- '--subscription' => 'sub1',
- '--subscription' => 'sub2',
- '--database' => $db1,
- '--database' => $db2,
+ 'pg_createsubscriber', '--verbose',
+ '--verbose', '--recovery-timeout',
+ "$PostgreSQL::Test::Utils::timeout_default", '--dry-run',
+ '--pgdata', $node_s->data_dir,
+ '--publisher-server', $node_p->connstr($db1),
+ '--socketdir', $node_s->host,
+ '--subscriber-port', $node_s->port,
+ '--publication', 'pub1',
+ '--publication', 'pub2',
+ '--subscription', 'sub1',
+ '--subscription', 'sub2',
+ '--database', $db1,
+ '--database', $db2
],
- 'run pg_createsubscriber --dry-run on node S');
+ 'Ditto above, but this time using command_ok to retain the output');
+
+# Reset 'max_slot_wal_keep_size' to default after the test
+$node_p->append_conf('postgresql.conf', 'max_slot_wal_keep_size = -1');
+$node_p->reload;
# Check if node S is still a standby
$node_s->start;
--
2.41.0.windows.3