Commit 092c6936 authored by Alvaro Herrera's avatar Alvaro Herrera

Set wal_receiver_create_temp_slot PGC_POSTMASTER

Commit 32973082 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: default avatarMichael Paquier <michael@paquier.xyz>
Reviewed-by: default avatarÁlvaro Herrera <alvherre@alvh.no-ip.org>
Discussion: https://postgr.es/m/20200122055510.GH174860@paquier.xyz
parent fbc7a716
...@@ -4163,11 +4163,7 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class=" ...@@ -4163,11 +4163,7 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class="
Specifies whether a WAL receiver should create a temporary replication Specifies whether a WAL receiver should create a temporary replication
slot on the remote instance when no permanent replication slot to use slot on the remote instance when no permanent replication slot to use
has been configured (using <xref linkend="guc-primary-slot-name"/>). 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 The default is off. This parameter can only be set at server start.
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.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
......
...@@ -290,6 +290,7 @@ bool StandbyModeRequested = false; ...@@ -290,6 +290,7 @@ bool StandbyModeRequested = false;
char *PrimaryConnInfo = NULL; char *PrimaryConnInfo = NULL;
char *PrimarySlotName = NULL; char *PrimarySlotName = NULL;
char *PromoteTriggerFile = NULL; char *PromoteTriggerFile = NULL;
bool wal_receiver_create_temp_slot = false;
/* are we currently in standby mode? */ /* are we currently in standby mode? */
bool StandbyMode = false; bool StandbyMode = false;
...@@ -11975,7 +11976,8 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, ...@@ -11975,7 +11976,8 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
} }
curFileTLI = tli; curFileTLI = tli;
RequestXLogStreaming(tli, ptr, PrimaryConnInfo, RequestXLogStreaming(tli, ptr, PrimaryConnInfo,
PrimarySlotName); PrimarySlotName,
wal_receiver_create_temp_slot);
receivedUpto = 0; receivedUpto = 0;
} }
......
...@@ -15,6 +15,12 @@ ...@@ -15,6 +15,12 @@
* WalRcv->receivedUpto variable in shared memory, to inform the startup * WalRcv->receivedUpto variable in shared memory, to inform the startup
* process of how far it can proceed with XLOG replay. * 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 * If the primary server ends streaming, but doesn't disconnect, walreceiver
* goes into "waiting" mode, and waits for the startup process to give new * goes into "waiting" mode, and waits for the startup process to give new
* instructions. The startup process will treat that the same as * instructions. The startup process will treat that the same as
...@@ -73,8 +79,11 @@ ...@@ -73,8 +79,11 @@
#include "utils/timestamp.h" #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_status_interval;
int wal_receiver_timeout; int wal_receiver_timeout;
bool hot_standby_feedback; bool hot_standby_feedback;
...@@ -236,6 +245,12 @@ WalReceiverMain(void) ...@@ -236,6 +245,12 @@ WalReceiverMain(void)
startpoint = walrcv->receiveStart; startpoint = walrcv->receiveStart;
startpointTLI = walrcv->receiveStartTLI; 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 */ /* Initialise to a sanish value */
walrcv->lastMsgSendTime = walrcv->lastMsgSendTime =
walrcv->lastMsgReceiptTime = walrcv->latestWalEndTime = now; walrcv->lastMsgReceiptTime = walrcv->latestWalEndTime = now;
...@@ -349,43 +364,22 @@ WalReceiverMain(void) ...@@ -349,43 +364,22 @@ WalReceiverMain(void)
WalRcvFetchTimeLineHistoryFiles(startpointTLI, primaryTLI); WalRcvFetchTimeLineHistoryFiles(startpointTLI, primaryTLI);
/* /*
* Create temporary replication slot if no slot name is configured or * Create temporary replication slot if requested, and update slot
* the slot from the previous run was temporary, unless * name in shared memory. (Note the slot name cannot already be set
* wal_receiver_create_temp_slot is disabled. We also need to handle * in this case.)
* 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.)
*/ */
if (slotname[0] == '\0' || is_temp_slot) if (is_temp_slot)
{
bool changed = false;
if (wal_receiver_create_temp_slot)
{ {
snprintf(slotname, sizeof(slotname), snprintf(slotname, sizeof(slotname),
"pg_walreceiver_%lld", "pg_walreceiver_%lld",
(long long int) walrcv_get_backend_pid(wrconn)); (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); SpinLockAcquire(&walrcv->mutex);
strlcpy(walrcv->slotname, slotname, NAMEDATALEN); strlcpy(walrcv->slotname, slotname, NAMEDATALEN);
walrcv->is_temp_slot = wal_receiver_create_temp_slot;
SpinLockRelease(&walrcv->mutex); SpinLockRelease(&walrcv->mutex);
} }
}
/* /*
* Start streaming. * Start streaming.
......
...@@ -215,13 +215,19 @@ ShutdownWalRcv(void) ...@@ -215,13 +215,19 @@ ShutdownWalRcv(void)
/* /*
* Request postmaster to start walreceiver. * Request postmaster to start walreceiver.
* *
* recptr indicates the position where streaming should begin, conninfo * "recptr" indicates the position where streaming should begin. "conninfo"
* is a libpq connection string to use, and slotname is, optionally, the name * is a libpq connection string to use. "slotname" is, optionally, the name
* of a replication slot to acquire. * 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 void
RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo, RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo,
const char *slotname) const char *slotname, bool create_temp_slot)
{ {
WalRcvData *walrcv = WalRcv; WalRcvData *walrcv = WalRcv;
bool launch = false; bool launch = false;
...@@ -248,10 +254,22 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo, ...@@ -248,10 +254,22 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo,
else else
walrcv->conninfo[0] = '\0'; 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); strlcpy((char *) walrcv->slotname, slotname, NAMEDATALEN);
walrcv->is_temp_slot = false;
}
else else
{
walrcv->slotname[0] = '\0'; walrcv->slotname[0] = '\0';
walrcv->is_temp_slot = create_temp_slot;
}
if (walrcv->walRcvState == WALRCV_STOPPED) if (walrcv->walRcvState == WALRCV_STOPPED)
{ {
......
...@@ -2050,11 +2050,11 @@ static struct config_bool ConfigureNamesBool[] = ...@@ -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."), gettext_noop("Sets whether a WAL receiver should create a temporary replication slot if no permanent slot is configured."),
}, },
&wal_receiver_create_temp_slot, &wal_receiver_create_temp_slot,
true, false,
NULL, NULL, NULL NULL, NULL, NULL
}, },
......
...@@ -321,7 +321,9 @@ ...@@ -321,7 +321,9 @@
#max_standby_streaming_delay = 30s # max delay before canceling queries #max_standby_streaming_delay = 30s # max delay before canceling queries
# when reading streaming WAL; # when reading streaming WAL;
# -1 allows indefinite delay # -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 #wal_receiver_status_interval = 10s # send replies at least this often
# 0 disables # 0 disables
#hot_standby_feedback = off # send info from standby to prevent #hot_standby_feedback = off # send info from standby to prevent
......
...@@ -129,6 +129,7 @@ extern int recoveryTargetAction; ...@@ -129,6 +129,7 @@ extern int recoveryTargetAction;
extern int recovery_min_apply_delay; extern int recovery_min_apply_delay;
extern char *PrimaryConnInfo; extern char *PrimaryConnInfo;
extern char *PrimarySlotName; extern char *PrimarySlotName;
extern bool wal_receiver_create_temp_slot;
/* indirectly set via GUC system */ /* indirectly set via GUC system */
extern TransactionId recoveryTargetXid; extern TransactionId recoveryTargetXid;
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include "utils/tuplestore.h" #include "utils/tuplestore.h"
/* user-settable parameters */ /* user-settable parameters */
extern bool wal_receiver_create_temp_slot;
extern int wal_receiver_status_interval; extern int wal_receiver_status_interval;
extern int wal_receiver_timeout; extern int wal_receiver_timeout;
extern bool hot_standby_feedback; extern bool hot_standby_feedback;
...@@ -321,7 +320,8 @@ extern void ShutdownWalRcv(void); ...@@ -321,7 +320,8 @@ extern void ShutdownWalRcv(void);
extern bool WalRcvStreaming(void); extern bool WalRcvStreaming(void);
extern bool WalRcvRunning(void); extern bool WalRcvRunning(void);
extern void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, 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 XLogRecPtr GetWalRcvWriteRecPtr(XLogRecPtr *latestChunkStart, TimeLineID *receiveTLI);
extern int GetReplicationApplyDelay(void); extern int GetReplicationApplyDelay(void);
extern int GetReplicationTransferLatency(void); extern int GetReplicationTransferLatency(void);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment