diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 4a7121a..bce99ce 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -3796,9 +3796,14 @@ ANY num_sync ( @@ -3813,9 +3818,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. + + + walreceiver will be restarted after + primary_slot_name was changed. diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 9643c2e..cdd9f40 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -113,6 +113,12 @@ 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: * * We can't just exit(1) within SIGTERM signal handler, because the signal @@ -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 */ @@ -1317,6 +1321,35 @@ 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("closing replication connection because primary_conninfo was changed"))); + + /* + * And the same for primary_slot_name. + */ + if (strcmp(current_slotname, PrimarySlotName) != 0) + ereport(FATAL, + (errcode(ERRCODE_ADMIN_SHUTDOWN), + errmsg("closing replication connection because primary_slot_name was changed"))); + + XLogWalRcvSendHSFeedback(true); +} + +/* * Wake up the walreceiver main loop. * * This is called by the startup process whenever interesting xlog records diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 6fe1939..09948ee 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -3448,7 +3448,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 @@ -3459,7 +3459,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 beb4555..07ac964 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");