Set wal_receiver_create_temp_slot PGC_POSTMASTER

Commit 3297308278 gave walreceiver the ability to create and use a
temporary replication slot, and made it controllable by a GUC (enabled
by default) that can be changed with SIGHUP.  That's useful but has two
problems: one, it's possible to cause the origin server to fill its disk
if the slot doesn't advance in time; and also there's a disconnect
between state passed down via the startup process and GUCs that
walreceiver reads directly.

We handle the first problem by setting the option to disabled by
default.  If the user enables it, its on their head to make sure that
disk doesn't fill up.

We handle the second problem by passing the flag via startup rather than
having walreceiver acquire it directly, and making it PGC_POSTMASTER
(which ensures a walreceiver always has the fresh value).  A future
commit can relax this (to PGC_SIGHUP again) by having the startup
process signal walreceiver to shutdown whenever the value changes.

Author: Sergei Kornilov <sk@zsrv.org>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Álvaro Herrera <alvherre@alvh.no-ip.org>
Discussion: https://postgr.es/m/20200122055510.GH174860@paquier.xyz
This commit is contained in:
Alvaro Herrera 2020-03-27 16:04:52 -03:00
parent fbc7a71608
commit 092c6936de
No known key found for this signature in database
GPG Key ID: 1C20ACB9D5C564AE
8 changed files with 63 additions and 50 deletions

View File

@ -4163,11 +4163,7 @@ 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 at server start.
</para>
</listitem>
</varlistentry>

View File

@ -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;
@ -11975,7 +11976,8 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
}
curFileTLI = tli;
RequestXLogStreaming(tli, ptr, PrimaryConnInfo,
PrimarySlotName);
PrimarySlotName,
wal_receiver_create_temp_slot);
receivedUpto = 0;
}

View File

@ -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
@ -73,8 +79,11 @@
#include "utils/timestamp.h"
/* GUC variables */
bool wal_receiver_create_temp_slot;
/*
* GUC variables. (Other variables that affect walreceiver are in xlog.c
* because they're passed down from the startup process, for better
* synchronization.)
*/
int wal_receiver_status_interval;
int wal_receiver_timeout;
bool hot_standby_feedback;
@ -236,6 +245,12 @@ WalReceiverMain(void)
startpoint = walrcv->receiveStart;
startpointTLI = walrcv->receiveStartTLI;
/*
* At most one of is_temp_slot and slotname can be set; otherwise,
* RequestXLogStreaming messed up.
*/
Assert(!is_temp_slot || (slotname[0] == '\0'));
/* Initialise to a sanish value */
walrcv->lastMsgSendTime =
walrcv->lastMsgReceiptTime = walrcv->latestWalEndTime = now;
@ -349,42 +364,21 @@ 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
* 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.)
* Create temporary replication slot if requested, and update slot
* name in shared memory. (Note the slot name cannot already be set
* in this case.)
*/
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);
}
/*

View File

@ -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)
{

View File

@ -2050,11 +2050,11 @@ static struct config_bool ConfigureNamesBool[] =
},
{
{"wal_receiver_create_temp_slot", PGC_SIGHUP, REPLICATION_STANDBY,
{"wal_receiver_create_temp_slot", PGC_POSTMASTER, REPLICATION_STANDBY,
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
},

View File

@ -321,7 +321,9 @@
#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.
# (change requires restart)
#wal_receiver_status_interval = 10s # send replies at least this often
# 0 disables
#hot_standby_feedback = off # send info from standby to prevent

View File

@ -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;

View File

@ -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);