Now, would anyone be too upset if I push these in this other order? I realized that the reason the tests broke after Sergei's patch is that recovery/t/001_stream_rep.pl's get_slot_xmins() is broken for temp walreceiver slots, since it's using the non-temp name it tries to give to the slot, rather than the temp name under which it is actually created. The workaround proposed by 0002 is to edit standby_1's config to set walreceiver's slot to be non-temp.
Thanks to Justin Pryzby for offlist typo corrections. The reason is that I think I would like to get Sergei's patch pushed right away (0001+0002, as a single commit); but that I think there's more to attack in the walreceiver temp slot code than 0003 here, and I don't want to delay the new feature any longer while I figure out the fix for that. (The thing is: if I specify primary_slot_name in the config, why is the temp walreceiver slot code not obeying that name? I think walreceiver should create a temp slot, sure, but using the given name rather than coming up with a random name.) (The other reason is that I would like to push one patch to fix walreceiver tmp slot rather than two, setting the thing first this way and then the opposite way.) -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
>From f7a9717caa9dd73c00fb5e6a1dddb354ad78d09a Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Wed, 25 Mar 2020 20:48:56 -0300 Subject: [PATCH v11 1/3] Allow changing primary_conninfo and primary_slot_name in SIGHUP --- doc/src/sgml/config.sgml | 16 ++- src/backend/access/transam/xlog.c | 130 +++++++++++------- src/backend/access/transam/xlogreader.c | 6 +- src/backend/postmaster/startup.c | 30 +++- src/backend/replication/walreceiver.c | 12 +- src/backend/utils/misc/guc.c | 4 +- src/backend/utils/misc/postgresql.conf.sample | 2 - src/include/access/xlog.h | 2 + src/test/recovery/t/001_stream_rep.pl | 24 +++- 9 files changed, 165 insertions(+), 61 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 355b408b0a..1cf88e953d 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -4028,9 +4028,15 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class=" <varname>primary_conninfo</varname> string. </para> <para> - This parameter can only be set at server start. + This parameter can only be set in the <filename>postgresql.conf</filename> + file or on the server command line. This setting has no effect if the server is not in standby mode. </para> + <para> + If <varname>primary_conninfo</varname> is changed while WAL receiver is running, + the WAL receiver shuts down and then restarts with new setting, + except when primary_conninfo is an empty string. + </para> </listitem> </varlistentry> <varlistentry id="guc-primary-slot-name" xreflabel="primary_slot_name"> @@ -4045,9 +4051,13 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class=" connecting to the sending server via streaming replication to control resource removal on the upstream node (see <xref linkend="streaming-replication-slots"/>). - This parameter can only be set at server start. + This parameter can only be set in the <filename>postgresql.conf</filename> + file or on the server command line. This setting has no effect if <varname>primary_conninfo</varname> is not - set. + set or the server is not in standby mode. + </para> + <para> + The WAL receiver is restarted after an update of <varname>primary_slot_name</varname>. </para> </listitem> </varlistentry> diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 7621fc05e2..bbf8d4eee5 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -815,9 +815,13 @@ static XLogSource readSource = XLOG_FROM_ANY; * currently have a WAL file open. If lastSourceFailed is set, our last * attempt to read from currentSource failed, and we should try another source * next. + * + * pendingWalRcvRestart is set when a config change occurs that requires a + * walreceiver restart. This is only valid in XLOG_FROM_STREAM state. */ static XLogSource currentSource = XLOG_FROM_ANY; static bool lastSourceFailed = false; +static bool pendingWalRcvRestart = false; typedef struct XLogPageReadPrivate { @@ -11904,6 +11908,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, for (;;) { XLogSource oldSource = currentSource; + bool startWalReceiver = false; /* * First check if we failed to read from the current source, and @@ -11938,53 +11943,11 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, return false; /* - * If primary_conninfo is set, launch walreceiver to try - * to stream the missing WAL. - * - * If fetching_ckpt is true, RecPtr points to the initial - * checkpoint location. In that case, we use RedoStartLSN - * as the streaming start position instead of RecPtr, so - * that when we later jump backwards to start redo at - * RedoStartLSN, we will have the logs streamed already. - */ - if (PrimaryConnInfo && strcmp(PrimaryConnInfo, "") != 0) - { - XLogRecPtr ptr; - TimeLineID tli; - - if (fetching_ckpt) - { - ptr = RedoStartLSN; - tli = ControlFile->checkPointCopy.ThisTimeLineID; - } - else - { - ptr = RecPtr; - - /* - * Use the record begin position to determine the - * TLI, rather than the position we're reading. - */ - tli = tliOfPointInHistory(tliRecPtr, expectedTLEs); - - if (curFileTLI > 0 && tli < curFileTLI) - elog(ERROR, "according to history file, WAL location %X/%X belongs to timeline %u, but previous recovered WAL file came from timeline %u", - (uint32) (tliRecPtr >> 32), - (uint32) tliRecPtr, - tli, curFileTLI); - } - curFileTLI = tli; - RequestXLogStreaming(tli, ptr, PrimaryConnInfo, - PrimarySlotName); - receivedUpto = 0; - } - - /* - * Move to XLOG_FROM_STREAM state in either case. We'll - * get immediate failure if we didn't launch walreceiver, - * and move on to the next state. + * Move to XLOG_FROM_STREAM state, and set to start a + * walreceiver if necessary. */ currentSource = XLOG_FROM_STREAM; + startWalReceiver = true; break; case XLOG_FROM_STREAM: @@ -12136,7 +12099,70 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, Assert(StandbyMode); /* - * Check if WAL receiver is still active. + * First, shutdown walreceiver if its restart has been + * requested -- but no point if we're already slated for + * starting it. + */ + if (pendingWalRcvRestart && !startWalReceiver) + { + ShutdownWalRcv(); + + /* + * Re-scan for possible new timelines if we were + * requested to recover to the latest timeline. + */ + if (recoveryTargetTimeLineGoal == + RECOVERY_TARGET_TIMELINE_LATEST) + rescanLatestTimeLine(); + + startWalReceiver = true; + } + pendingWalRcvRestart = false; + + /* + * Launch walreceiver if needed. + * + * If fetching_ckpt is true, RecPtr points to the initial + * checkpoint location. In that case, we use RedoStartLSN + * as the streaming start position instead of RecPtr, so + * that when we later jump backwards to start redo at + * RedoStartLSN, we will have the logs streamed already. + */ + if (startWalReceiver && + PrimaryConnInfo && strcmp(PrimaryConnInfo, "") != 0) + { + XLogRecPtr ptr; + TimeLineID tli; + + if (fetching_ckpt) + { + ptr = RedoStartLSN; + tli = ControlFile->checkPointCopy.ThisTimeLineID; + } + else + { + ptr = RecPtr; + + /* + * Use the record begin position to determine the + * TLI, rather than the position we're reading. + */ + tli = tliOfPointInHistory(tliRecPtr, expectedTLEs); + + if (curFileTLI > 0 && tli < curFileTLI) + elog(ERROR, "according to history file, WAL location %X/%X belongs to timeline %u, but previous recovered WAL file came from timeline %u", + (uint32) (tliRecPtr >> 32), + (uint32) tliRecPtr, + tli, curFileTLI); + } + curFileTLI = tli; + RequestXLogStreaming(tli, ptr, PrimaryConnInfo, + PrimarySlotName); + receivedUpto = 0; + } + + /* + * Check if WAL receiver is active or wait to start up. */ if (!WalRcvStreaming()) { @@ -12264,6 +12290,18 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, return false; /* not reached */ } +void +StartupRequestWalReceiverRestart(void) +{ + if (currentSource == XLOG_FROM_STREAM && WalRcvRunning()) + { + ereport(LOG, + (errmsg("wal receiver process shutdown requested"))); + + pendingWalRcvRestart = true; + } +} + /* * Determine what log level should be used to report a corrupt WAL record * in the current WAL page, previously read by XLogPageRead(). diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c index 32f02256ed..f3fea5132f 100644 --- a/src/backend/access/transam/xlogreader.c +++ b/src/backend/access/transam/xlogreader.c @@ -585,9 +585,9 @@ ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen) /* * Data is not in our buffer. * - * Every time we actually read the page, even if we looked at parts of it - * before, we need to do verification as the read_page callback might now - * be rereading data from a different source. + * Every time we actually read the segment, even if we looked at parts of + * it before, we need to do verification as the read_page callback might + * now be rereading data from a different source. * * Whenever switching to a new WAL segment, we read the first page of the * file and validate its header, even if that's not where the target diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c index 8952676765..f35b5adf7d 100644 --- a/src/backend/postmaster/startup.c +++ b/src/backend/postmaster/startup.c @@ -96,17 +96,43 @@ StartupProcShutdownHandler(SIGNAL_ARGS) errno = save_errno; } +/* + * Re-read the config file. + * + * If one of the critical walreceiver options has changed, flag xlog.c + * to restart it. + */ +static void +StartupRereadConfig(void) +{ + char *conninfo = pstrdup(PrimaryConnInfo); + char *slotname = pstrdup(PrimarySlotName); + bool conninfoChanged; + bool slotnameChanged; + + ProcessConfigFile(PGC_SIGHUP); + + conninfoChanged = strcmp(conninfo, PrimaryConnInfo) != 0; + slotnameChanged = strcmp(slotname, PrimarySlotName) != 0; + + pfree(conninfo); + pfree(slotname); + + if (conninfoChanged || slotnameChanged) + StartupRequestWalReceiverRestart(); +} + /* Handle various signals that might be sent to the startup process */ void HandleStartupProcInterrupts(void) { /* - * Check if we were requested to re-read config file. + * Process any requests or signals received recently. */ if (got_SIGHUP) { got_SIGHUP = false; - ProcessConfigFile(PGC_SIGHUP); + StartupRereadConfig(); } /* diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 25e0333c9e..b471a49d12 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -15,6 +15,12 @@ * WalRcv->receivedUpto variable in shared memory, to inform the startup * process of how far it can proceed with XLOG replay. * + * A WAL receiver cannot directly load GUC parameters used when establishing + * its connection to the primary. Instead it relies on parameter values + * that are passed down by the startup process when streaming is requested. + * This applies, for example, to the replication slot and the connection + * string to be used for the connection with the primary. + * * If the primary server ends streaming, but doesn't disconnect, walreceiver * goes into "waiting" mode, and waits for the startup process to give new * instructions. The startup process will treat that the same as @@ -685,7 +691,11 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI) walrcv->walRcvState == WALRCV_STOPPING); if (walrcv->walRcvState == WALRCV_RESTARTING) { - /* we don't expect primary_conninfo to change */ + /* + * No need to handle changes in primary_conninfo or + * primary_slotname here. Startup process will signal us in case + * those change. + */ *startpoint = walrcv->receiveStart; *startpointTLI = walrcv->receiveStartTLI; walrcv->walRcvState = WALRCV_STREAMING; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index af876d1f01..c0b2b75407 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -3717,7 +3717,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 @@ -3728,7 +3728,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/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index aa44f0c9bf..c4f2f881c9 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -309,9 +309,7 @@ # These settings are ignored on a master server. #primary_conninfo = '' # connection string to sending server - # (change requires restart) #primary_slot_name = '' # replication slot on sending server - # (change requires restart) #promote_trigger_file = '' # file name whose presence ends recovery #hot_standby = on # "off" disallows queries during recovery # (change requires restart) diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 331497bcfb..42c4df0262 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -318,8 +318,10 @@ extern bool CheckPromoteSignal(void); extern void WakeupRecovery(void); extern void SetWalWriterSleeping(bool sleeping); +extern void StartupRequestWalReceiverRestart(void); extern void XLogRequestWalReceiverReply(void); +extern void ProcessStartupSigHup(void); extern void assign_max_wal_size(int newval, void *extra); extern void assign_checkpoint_completion_target(double newval, void *extra); diff --git a/src/test/recovery/t/001_stream_rep.pl b/src/test/recovery/t/001_stream_rep.pl index d09ebe65a3..52585a1014 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 => 34; +use Test::More tests => 35; # Initialize master node my $node_master = get_new_node('master'); @@ -208,7 +208,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 @@ -345,6 +347,24 @@ 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"); + # Test physical slot advancing and its durability. Create a new slot on # the primary, not used by any of the standbys. This reserves WAL at creation. my $phys_slot = 'phys_slot'; -- 2.20.1
>From 14ac73a42247fdfc5d02a19ac1b9b13dc9efeccf Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Thu, 26 Mar 2020 21:04:42 -0300 Subject: [PATCH v11 2/3] Fix tests --- src/test/recovery/t/001_stream_rep.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/recovery/t/001_stream_rep.pl b/src/test/recovery/t/001_stream_rep.pl index 52585a1014..3408eaf551 100644 --- a/src/test/recovery/t/001_stream_rep.pl +++ b/src/test/recovery/t/001_stream_rep.pl @@ -22,6 +22,7 @@ $node_master->backup($backup_name); my $node_standby_1 = get_new_node('standby_1'); $node_standby_1->init_from_backup($node_master, $backup_name, has_streaming => 1); +$node_standby_1->append_conf('postgresql.conf', "wal_receiver_create_temp_slot = false"); $node_standby_1->start; # Take backup of standby 1 (not mandatory, but useful to check if -- 2.20.1
>From 29acdc47bf6a805c9ed24cb20d6a8a01a7fe93fc Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Wed, 25 Mar 2020 20:48:44 -0300 Subject: [PATCH v11 3/3] Rework wal_receiver_create_temp_slot using new infrastructure --- doc/src/sgml/config.sgml | 10 ++--- src/backend/access/transam/xlog.c | 3 +- src/backend/postmaster/startup.c | 10 ++++- src/backend/replication/walreceiver.c | 40 +++++-------------- src/backend/replication/walreceiverfuncs.c | 28 ++++++++++--- src/backend/utils/misc/guc.c | 2 +- src/backend/utils/misc/postgresql.conf.sample | 3 +- src/include/access/xlog.h | 1 + src/include/replication/walreceiver.h | 4 +- 9 files changed, 55 insertions(+), 46 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 1cf88e953d..c5160fe907 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -4173,11 +4173,11 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class=" Specifies whether a WAL receiver should create a temporary replication slot on the remote instance when no permanent replication slot to use has been configured (using <xref linkend="guc-primary-slot-name"/>). - The default is on. The only reason to turn this off would be if the - remote instance is currently out of available replication slots. This - parameter can only be set in the <filename>postgresql.conf</filename> - file or on the server command line. Changes only take effect when the - WAL receiver process starts a new connection. + The default is off. This parameter can only be set in the + <filename>postgresql.conf</filename> file or on the server command line. + </para> + <para> + The WAL receiver is restarted after an update of <varname>wal_receiver_create_temp_slot</varname>. </para> </listitem> </varlistentry> diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index bbf8d4eee5..2ecb319438 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -290,6 +290,7 @@ bool StandbyModeRequested = false; char *PrimaryConnInfo = NULL; char *PrimarySlotName = NULL; char *PromoteTriggerFile = NULL; +bool wal_receiver_create_temp_slot = false; /* are we currently in standby mode? */ bool StandbyMode = false; @@ -12157,7 +12158,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, } curFileTLI = tli; RequestXLogStreaming(tli, ptr, PrimaryConnInfo, - PrimarySlotName); + PrimarySlotName, wal_receiver_create_temp_slot); receivedUpto = 0; } diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c index f35b5adf7d..fd9ac35dac 100644 --- a/src/backend/postmaster/startup.c +++ b/src/backend/postmaster/startup.c @@ -107,18 +107,26 @@ StartupRereadConfig(void) { char *conninfo = pstrdup(PrimaryConnInfo); char *slotname = pstrdup(PrimarySlotName); + bool tempSlot = wal_receiver_create_temp_slot; bool conninfoChanged; bool slotnameChanged; + bool tempSlotChanged = false; ProcessConfigFile(PGC_SIGHUP); conninfoChanged = strcmp(conninfo, PrimaryConnInfo) != 0; slotnameChanged = strcmp(slotname, PrimarySlotName) != 0; + /* + * wal_receiver_create_temp_slot is used only when we have no slot + * configured. We do not need to track this change if it has no effect. + */ + if (!slotnameChanged && strcmp(PrimarySlotName, "") == 0) + tempSlotChanged = tempSlot != wal_receiver_create_temp_slot; pfree(conninfo); pfree(slotname); - if (conninfoChanged || slotnameChanged) + if (conninfoChanged || slotnameChanged || tempSlotChanged) StartupRequestWalReceiverRestart(); } diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index b471a49d12..0aa0c52c49 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -80,7 +80,6 @@ /* GUC variables */ -bool wal_receiver_create_temp_slot; int wal_receiver_status_interval; int wal_receiver_timeout; bool hot_standby_feedback; @@ -355,42 +354,23 @@ WalReceiverMain(void) WalRcvFetchTimeLineHistoryFiles(startpointTLI, primaryTLI); /* - * Create temporary replication slot if no slot name is configured or - * the slot from the previous run was temporary, unless - * wal_receiver_create_temp_slot is disabled. We also need to handle - * the case where the previous run used a temporary slot but - * wal_receiver_create_temp_slot was changed in the meantime. In that - * case, we delete the old slot name in shared memory. (This would + * Create temporary replication slot if requested. In that + * case, we update slot name in shared memory. (This would * all be a bit easier if we just didn't copy the slot name into * shared memory, since we won't need it again later, but then we * can't see the slot name in the stats views.) */ - if (slotname[0] == '\0' || is_temp_slot) + if (is_temp_slot) { - bool changed = false; + snprintf(slotname, sizeof(slotname), + "pg_walreceiver_%lld", + (long long int) walrcv_get_backend_pid(wrconn)); - if (wal_receiver_create_temp_slot) - { - snprintf(slotname, sizeof(slotname), - "pg_walreceiver_%lld", - (long long int) walrcv_get_backend_pid(wrconn)); + walrcv_create_slot(wrconn, slotname, true, 0, NULL); - walrcv_create_slot(wrconn, slotname, true, 0, NULL); - changed = true; - } - else if (slotname[0] != '\0') - { - slotname[0] = '\0'; - changed = true; - } - - if (changed) - { - SpinLockAcquire(&walrcv->mutex); - strlcpy(walrcv->slotname, slotname, NAMEDATALEN); - walrcv->is_temp_slot = wal_receiver_create_temp_slot; - SpinLockRelease(&walrcv->mutex); - } + SpinLockAcquire(&walrcv->mutex); + strlcpy(walrcv->slotname, slotname, NAMEDATALEN); + SpinLockRelease(&walrcv->mutex); } /* diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c index 89c903e45a..21d1823607 100644 --- a/src/backend/replication/walreceiverfuncs.c +++ b/src/backend/replication/walreceiverfuncs.c @@ -215,13 +215,19 @@ ShutdownWalRcv(void) /* * Request postmaster to start walreceiver. * - * recptr indicates the position where streaming should begin, conninfo - * is a libpq connection string to use, and slotname is, optionally, the name - * of a replication slot to acquire. + * "recptr" indicates the position where streaming should begin. "conninfo" + * is a libpq connection string to use. "slotname" is, optionally, the name + * of a replication slot to acquire. "create_temp_slot" indicates to create + * a temporary slot when no "slotname" is given. + * + * WAL receivers do not directly load GUC parameters used for the connection + * to the primary, and rely on the values passed down by the caller of this + * routine instead. Hence, the addition of any new parameters should happen + * through this code path. */ void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo, - const char *slotname) + const char *slotname, bool create_temp_slot) { WalRcvData *walrcv = WalRcv; bool launch = false; @@ -248,10 +254,22 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo, else walrcv->conninfo[0] = '\0'; - if (slotname != NULL) + /* + * Use configured replication slot if present, and ignore the value + * of create_temp_slot as the slot name should be persistent. Otherwise, + * use create_temp_slot to determine whether this WAL receiver should + * create a temporary slot by itself and use it, or not. + */ + if (slotname != NULL && slotname[0] != '\0') + { strlcpy((char *) walrcv->slotname, slotname, NAMEDATALEN); + walrcv->is_temp_slot = false; + } else + { walrcv->slotname[0] = '\0'; + walrcv->is_temp_slot = create_temp_slot; + } if (walrcv->walRcvState == WALRCV_STOPPED) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index c0b2b75407..53665971f5 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2054,7 +2054,7 @@ static struct config_bool ConfigureNamesBool[] = gettext_noop("Sets whether a WAL receiver should create a temporary replication slot if no permanent slot is configured."), }, &wal_receiver_create_temp_slot, - true, + false, NULL, NULL, NULL }, diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index c4f2f881c9..f01e43b818 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -319,7 +319,8 @@ #max_standby_streaming_delay = 30s # max delay before canceling queries # when reading streaming WAL; # -1 allows indefinite delay -#wal_receiver_create_temp_slot = on # create temp slot if primary_slot_name not set +#wal_receiver_create_temp_slot = off # Create temp slot if primary_slot_name + # is not set. #wal_receiver_status_interval = 10s # send replies at least this often # 0 disables #hot_standby_feedback = off # send info from standby to prevent diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 42c4df0262..997db214cc 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -129,6 +129,7 @@ extern int recoveryTargetAction; extern int recovery_min_apply_delay; extern char *PrimaryConnInfo; extern char *PrimarySlotName; +extern bool wal_receiver_create_temp_slot; /* indirectly set via GUC system */ extern TransactionId recoveryTargetXid; diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h index e08afc6548..cf3e43128c 100644 --- a/src/include/replication/walreceiver.h +++ b/src/include/replication/walreceiver.h @@ -23,7 +23,6 @@ #include "utils/tuplestore.h" /* user-settable parameters */ -extern bool wal_receiver_create_temp_slot; extern int wal_receiver_status_interval; extern int wal_receiver_timeout; extern bool hot_standby_feedback; @@ -321,7 +320,8 @@ extern void ShutdownWalRcv(void); extern bool WalRcvStreaming(void); extern bool WalRcvRunning(void); extern void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, - const char *conninfo, const char *slotname); + const char *conninfo, const char *slotname, + bool create_temp_slot); extern XLogRecPtr GetWalRcvWriteRecPtr(XLogRecPtr *latestChunkStart, TimeLineID *receiveTLI); extern int GetReplicationApplyDelay(void); extern int GetReplicationTransferLatency(void); -- 2.20.1