diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 9b7a7388d5..af68afa715 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -3827,9 +3827,14 @@ ANY num_sync ( @@ -3844,9 +3849,14 @@ ANY num_sync ( ). - This parameter can only be set at server start. + This parameter can only be set in the postgresql.conf + file or on the server command line. This setting has no effect if primary_conninfo is not - set. + set or the server is not in standby mode. + + + WAL receiver will be restarted after primary_slot_name + was changed. diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 2e90944ad5..05b90d00a4 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -112,6 +112,12 @@ static struct static StringInfoData reply_message; static StringInfoData incoming_message; +/* + * Copy of current WalReceiverConn connection info (not clobbered) + */ +static char current_conninfo[MAXCONNINFO]; +static char current_slotname[NAMEDATALEN]; + /* * About SIGTERM handling: * @@ -143,6 +149,7 @@ static void XLogWalRcvFlush(bool dying); static void XLogWalRcvSendReply(bool force, bool requestReply); static void XLogWalRcvSendHSFeedback(bool immed); static void ProcessWalSndrMessage(XLogRecPtr walEnd, TimestampTz sendTime); +static void ProcessWalRcvSigHup(void); /* Signal handlers */ static void WalRcvSigHupHandler(SIGNAL_ARGS); @@ -188,9 +195,7 @@ DisableWalRcvImmediateExit(void) void WalReceiverMain(void) { - char conninfo[MAXCONNINFO]; char *tmp_conninfo; - char slotname[NAMEDATALEN]; XLogRecPtr startpoint; TimeLineID startpointTLI; TimeLineID primaryTLI; @@ -250,8 +255,8 @@ WalReceiverMain(void) /* Fetch information required to start streaming */ walrcv->ready_to_display = false; - strlcpy(conninfo, (char *) walrcv->conninfo, MAXCONNINFO); - strlcpy(slotname, (char *) walrcv->slotname, NAMEDATALEN); + strlcpy(current_conninfo, (char *) walrcv->conninfo, MAXCONNINFO); + strlcpy(current_slotname, (char *) walrcv->slotname, NAMEDATALEN); startpoint = walrcv->receiveStart; startpointTLI = walrcv->receiveStartTLI; @@ -293,7 +298,7 @@ WalReceiverMain(void) /* Establish the connection to the primary for XLOG streaming */ EnableWalRcvImmediateExit(); - wrconn = walrcv_connect(conninfo, false, "walreceiver", &err); + wrconn = walrcv_connect(current_conninfo, false, "walreceiver", &err); if (!wrconn) ereport(ERROR, (errmsg("could not connect to the primary server: %s", err))); @@ -387,7 +392,7 @@ WalReceiverMain(void) */ options.logical = false; options.startpoint = startpoint; - options.slotname = slotname[0] != '\0' ? slotname : NULL; + options.slotname = current_slotname[0] != '\0' ? current_slotname : NULL; options.proto.physical.startpointTLI = startpointTLI; ThisTimeLineID = startpointTLI; if (walrcv_startstreaming(wrconn, &options)) @@ -436,8 +441,7 @@ WalReceiverMain(void) if (got_SIGHUP) { got_SIGHUP = false; - ProcessConfigFile(PGC_SIGHUP); - XLogWalRcvSendHSFeedback(true); + ProcessWalRcvSigHup(); } /* See if we can read data immediately */ @@ -1316,6 +1320,37 @@ ProcessWalSndrMessage(XLogRecPtr walEnd, TimestampTz sendTime) } } +/* + * Actual processing SIGHUP signal + */ +static void +ProcessWalRcvSigHup(void) +{ + ProcessConfigFile(PGC_SIGHUP); + + /* + * If primary_conninfo has been changed while walreceiver is running, + * shut down walreceiver so that a new walreceiver is started and + * initiates replication with the new connection information. + */ + if (strcmp(current_conninfo, PrimaryConnInfo) != 0) + ereport(FATAL, + (errcode(ERRCODE_ADMIN_SHUTDOWN), + errmsg("terminating walreceiver process due to change of primary_conninfo"), + errdetail("In a moment starts streaming WAL with new configuration."))); + + /* + * And the same for primary_slot_name. + */ + if (strcmp(current_slotname, PrimarySlotName) != 0) + ereport(FATAL, + (errcode(ERRCODE_ADMIN_SHUTDOWN), + errmsg("terminating walreceiver process due to change of primary_slot_name"), + errdetail("In a moment starts streaming WAL with new configuration."))); + + XLogWalRcvSendHSFeedback(true); +} + /* * Wake up the walreceiver main loop. * diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 8681ada33a..ab3cff2620 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -3484,7 +3484,7 @@ static struct config_string ConfigureNamesString[] = }, { - {"primary_conninfo", PGC_POSTMASTER, REPLICATION_STANDBY, + {"primary_conninfo", PGC_SIGHUP, REPLICATION_STANDBY, gettext_noop("Sets the connection string to be used to connect to the sending server."), NULL, GUC_SUPERUSER_ONLY @@ -3495,7 +3495,7 @@ static struct config_string ConfigureNamesString[] = }, { - {"primary_slot_name", PGC_POSTMASTER, REPLICATION_STANDBY, + {"primary_slot_name", PGC_SIGHUP, REPLICATION_STANDBY, gettext_noop("Sets the name of the replication slot to use on the sending server."), NULL }, diff --git a/src/test/recovery/t/001_stream_rep.pl b/src/test/recovery/t/001_stream_rep.pl index beb45551a2..07ac9642ba 100644 --- a/src/test/recovery/t/001_stream_rep.pl +++ b/src/test/recovery/t/001_stream_rep.pl @@ -3,7 +3,7 @@ use strict; use warnings; use PostgresNode; use TestLib; -use Test::More tests => 26; +use Test::More tests => 27; # Initialize master node my $node_master = get_new_node('master'); @@ -146,7 +146,9 @@ $node_standby_2->append_conf('postgresql.conf', "primary_slot_name = $slotname_2"); $node_standby_2->append_conf('postgresql.conf', "wal_receiver_status_interval = 1"); -$node_standby_2->restart; +# should be able change primary_slot_name without restart +# will wait effect in get_slot_xmins above +$node_standby_2->reload; # Fetch xmin columns from slot's pg_replication_slots row, after waiting for # given boolean condition to be true to ensure we've reached a quiescent state @@ -282,3 +284,21 @@ is($catalog_xmin, '', is($xmin, '', 'xmin of cascaded slot null with hs feedback reset'); is($catalog_xmin, '', 'catalog xmin of cascaded slot still null with hs_feedback reset'); + +note "check change primary_conninfo without restart"; +$node_standby_2->append_conf('postgresql.conf', + "primary_slot_name = ''"); +$node_standby_2->enable_streaming($node_master); +$node_standby_2->reload; + +# be sure do not streaming from cascade +$node_standby_1->stop; + +my $newval = $node_master->safe_psql('postgres', +'INSERT INTO replayed(val) SELECT coalesce(max(val),0) + 1 AS newval FROM replayed RETURNING val' +); +$node_master->wait_for_catchup($node_standby_2, 'replay', + $node_master->lsn('insert')); +my $is_replayed = $node_standby_2->safe_psql('postgres', + qq[SELECT 1 FROM replayed WHERE val = $newval]); +is($is_replayed, qq(1), "standby_2 didn't replay master value $newval");