From c6ebd1275f8e2490c8a1a5dba981bdce53aafe20 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sat, 11 Jan 2020 10:24:49 +0100 Subject: [PATCH v2 2/2] 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. --- doc/src/sgml/config.sgml | 20 +++++++++ doc/src/sgml/monitoring.sgml | 9 +++- .../libpqwalreceiver/libpqwalreceiver.c | 4 ++ src/backend/replication/walreceiver.c | 41 +++++++++++++++++++ src/backend/utils/misc/guc.c | 9 ++++ src/backend/utils/misc/postgresql.conf.sample | 1 + src/include/replication/walreceiver.h | 7 ++++ 7 files changed, 90 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 5d1c90282f..5d45b6f7cb 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -4124,6 +4124,26 @@ Standby Servers + + wal_receiver_create_temp_slot (boolean) + + wal_receiver_create_temp_slot configuration parameter + + + + + 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 ). + 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 postgresql.conf + file or on the server command line. Changes only take effect when the + WAL receiver process starts a new connection. + + + + wal_receiver_status_interval (integer) diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index dcb58115af..a2f5bbae66 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -2117,7 +2117,14 @@ <structname>pg_stat_wal_receiver</structname> View slot_name text - Replication slot name used by this WAL receiver + + Replication slot name used by this WAL receiver. This is only set if a + permanent replication slot is set using . Otherwise, the WAL receiver may use + a temporary replication slot (determined by ), but these are not shown + here. + sender_host diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c index b731d3fd04..e4fd1f9bb6 100644 --- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c +++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c @@ -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); diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 77360f1524..b464114333 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -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. * diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 62285792ec..e5f8a1301f 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -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 diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 087190ce63..e1048c0047 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -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 diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h index 172cfa2862..e08afc6548 100644 --- a/src/include/replication/walreceiver.h +++ b/src/include/replication/walreceiver.h @@ -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; -- 2.24.1