walreceiver uses a temporary replication slot by default

If no permanent replication slot is configured using
primary_slot_name, the walreceiver now creates and uses a temporary
replication slot.  A new setting wal_receiver_create_temp_slot can be
used to disable this behavior, for example, if the remote instance is
out of replication slots.

Reviewed-by: Masahiko Sawada <masahiko.sawada@2ndquadrant.com>
Discussion: https://www.postgresql.org/message-id/CA%2Bfd4k4dM0iEPLxyVyme2RAFsn8SUgrNtBJOu81YqTY4V%2BnqZA%40mail.gmail.com
This commit is contained in:
Peter Eisentraut 2020-01-14 14:07:11 +01:00
parent ee4ac46c8e
commit 3297308278
6 changed files with 82 additions and 0 deletions

View File

@ -4124,6 +4124,26 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class="
</listitem>
</varlistentry>
<varlistentry id="guc-wal-receiver-create-temp-slot" xreflabel="wal_receiver_create_temp_slot">
<term><varname>wal_receiver_create_temp_slot</varname> (<type>boolean</type>)
<indexterm>
<primary><varname>wal_receiver_create_temp_slot</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
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.
</para>
</listitem>
</varlistentry>
<varlistentry id="guc-wal-receiver-status-interval" xreflabel="wal_receiver_status_interval">
<term><varname>wal_receiver_status_interval</varname> (<type>integer</type>)
<indexterm>

View File

@ -834,6 +834,10 @@ libpqrcv_create_slot(WalReceiverConn *conn, const char *slotname,
break;
}
}
else
{
appendStringInfoString(&cmd, " PHYSICAL RESERVE_WAL");
}
res = libpqrcv_PQexec(conn->streamConn, cmd.data);
pfree(cmd.data);

View File

@ -73,6 +73,7 @@
/* GUC variables */
bool wal_receiver_create_temp_slot;
int wal_receiver_status_interval;
int wal_receiver_timeout;
bool hot_standby_feedback;
@ -169,6 +170,7 @@ WalReceiverMain(void)
char conninfo[MAXCONNINFO];
char *tmp_conninfo;
char slotname[NAMEDATALEN];
bool is_temp_slot;
XLogRecPtr startpoint;
TimeLineID startpointTLI;
TimeLineID primaryTLI;
@ -230,6 +232,7 @@ WalReceiverMain(void)
walrcv->ready_to_display = false;
strlcpy(conninfo, (char *) walrcv->conninfo, MAXCONNINFO);
strlcpy(slotname, (char *) walrcv->slotname, NAMEDATALEN);
is_temp_slot = walrcv->is_temp_slot;
startpoint = walrcv->receiveStart;
startpointTLI = walrcv->receiveStartTLI;
@ -345,6 +348,44 @@ 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.)
*/
if (slotname[0] == '\0' || is_temp_slot)
{
bool changed = false;
if (wal_receiver_create_temp_slot)
{
snprintf(slotname, sizeof(slotname),
"pg_walreceiver_%d", walrcv_get_backend_pid(wrconn));
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);
}
}
/*
* Start streaming.
*

View File

@ -1969,6 +1969,15 @@ static struct config_bool ConfigureNamesBool[] =
NULL, NULL, NULL
},
{
{"wal_receiver_create_temp_slot", PGC_SIGHUP, 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,
NULL, NULL, NULL
},
/* End-of-list marker */
{
{NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL

View File

@ -321,6 +321,7 @@
#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_status_interval = 10s # send replies at least this often
# 0 disables
#hot_standby_feedback = off # send info from standby to prevent

View File

@ -23,6 +23,7 @@
#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;
@ -121,6 +122,12 @@ typedef struct
*/
char slotname[NAMEDATALEN];
/*
* If it's a temporary replication slot, it needs to be recreated when
* connecting.
*/
bool is_temp_slot;
/* set true once conninfo is ready to display (obfuscated pwds etc) */
bool ready_to_display;