On 2019-11-15 14:52, Sergei Kornilov wrote:
I looked into this. It seems trivial to make walsender create and use a
temporary replication slot by default if no permanent replication slot
is specified. This is basically the logic that pg_basebackup has but
done server-side. See attached patch for a demonstration. Any reason
not to do that?
Seems this would break pg_basebackup --no-slot option?

After thinking about this a bit more, doing the temporary slot stuff on the walsender side might lead to too many complications in practice.

Here is another patch set that implements the temporary slot use on the walreceiver side, essentially mirroring what pg_basebackup already does.

I think this patch set might be useful on its own, even without the base backup stuff to follow.

--
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From 00c816f2ee9b6b8c0668d17a596470a18c6092e1 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Fri, 22 Nov 2019 11:04:26 +0100
Subject: [PATCH 1/3] Make lsn argument walrcv_create_slot() optional

Some callers are not using it, so it's wasteful to have to specify it.
---
 src/backend/commands/subscriptioncmds.c                     | 3 +--
 src/backend/replication/libpqwalreceiver/libpqwalreceiver.c | 6 ++++--
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/backend/commands/subscriptioncmds.c 
b/src/backend/commands/subscriptioncmds.c
index 5408edcfc2..198aa6f4b1 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -428,7 +428,6 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool 
isTopLevel)
         */
        if (connect)
        {
-               XLogRecPtr      lsn;
                char       *err;
                WalReceiverConn *wrconn;
                List       *tables;
@@ -479,7 +478,7 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool 
isTopLevel)
                                Assert(slotname);
 
                                walrcv_create_slot(wrconn, slotname, false,
-                                                                  
CRS_NOEXPORT_SNAPSHOT, &lsn);
+                                                                  
CRS_NOEXPORT_SNAPSHOT, NULL);
                                ereport(NOTICE,
                                                (errmsg("created replication 
slot \"%s\" on publisher",
                                                                slotname)));
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c 
b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index 545d2fcd05..befedb811d 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -844,8 +844,10 @@ libpqrcv_create_slot(WalReceiverConn *conn, const char 
*slotname,
                                                slotname, 
pchomp(PQerrorMessage(conn->streamConn)))));
        }
 
-       *lsn = DatumGetLSN(DirectFunctionCall1Coll(pg_lsn_in, InvalidOid,
-                                                                               
           CStringGetDatum(PQgetvalue(res, 0, 1))));
+       if (lsn)
+               *lsn = DatumGetLSN(DirectFunctionCall1Coll(pg_lsn_in, 
InvalidOid,
+                                                                               
                   CStringGetDatum(PQgetvalue(res, 0, 1))));
+
        if (!PQgetisnull(res, 0, 2))
                snapshot = pstrdup(PQgetvalue(res, 0, 2));
        else

base-commit: 4a0aab14dcb35550b55e623a3c194442c5666084
-- 
2.24.0

From 3e42ec83d06dacf92063111e9dc1f033ef415e8a Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Fri, 22 Nov 2019 11:07:48 +0100
Subject: [PATCH 2/3] Expose PQbackendPID() through walreceiver API

This will be used by a subsequent patch.
---
 .../replication/libpqwalreceiver/libpqwalreceiver.c   | 11 +++++++++++
 src/include/replication/walreceiver.h                 |  4 ++++
 2 files changed, 15 insertions(+)

diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c 
b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index befedb811d..ccc31f3cee 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -74,6 +74,7 @@ static char *libpqrcv_create_slot(WalReceiverConn *conn,
                                                                  bool 
temporary,
                                                                  
CRSSnapshotAction snapshot_action,
                                                                  XLogRecPtr 
*lsn);
+static pid_t libpqrcv_get_backend_pid(WalReceiverConn *conn);
 static WalRcvExecResult *libpqrcv_exec(WalReceiverConn *conn,
                                                                           
const char *query,
                                                                           
const int nRetTypes,
@@ -93,6 +94,7 @@ static WalReceiverFunctionsType PQWalReceiverFunctions = {
        libpqrcv_receive,
        libpqrcv_send,
        libpqrcv_create_slot,
+       libpqrcv_get_backend_pid,
        libpqrcv_exec,
        libpqrcv_disconnect
 };
@@ -858,6 +860,15 @@ libpqrcv_create_slot(WalReceiverConn *conn, const char 
*slotname,
        return snapshot;
 }
 
+/*
+ * Return PID of remote backend process.
+ */
+static pid_t
+libpqrcv_get_backend_pid(WalReceiverConn *conn)
+{
+       return PQbackendPID(conn->streamConn);
+}
+
 /*
  * Convert tuple query result to tuplestore.
  */
diff --git a/src/include/replication/walreceiver.h 
b/src/include/replication/walreceiver.h
index e12a934966..39be805172 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -226,6 +226,7 @@ typedef char *(*walrcv_create_slot_fn) (WalReceiverConn 
*conn,
                                                                                
const char *slotname, bool temporary,
                                                                                
CRSSnapshotAction snapshot_action,
                                                                                
XLogRecPtr *lsn);
+typedef pid_t (*walrcv_get_backend_pid_fn) (WalReceiverConn *conn);
 typedef WalRcvExecResult *(*walrcv_exec_fn) (WalReceiverConn *conn,
                                                                                
         const char *query,
                                                                                
         const int nRetTypes,
@@ -246,6 +247,7 @@ typedef struct WalReceiverFunctionsType
        walrcv_receive_fn walrcv_receive;
        walrcv_send_fn walrcv_send;
        walrcv_create_slot_fn walrcv_create_slot;
+       walrcv_get_backend_pid_fn walrcv_get_backend_pid;
        walrcv_exec_fn walrcv_exec;
        walrcv_disconnect_fn walrcv_disconnect;
 } WalReceiverFunctionsType;
@@ -276,6 +278,8 @@ extern PGDLLIMPORT WalReceiverFunctionsType 
*WalReceiverFunctions;
        WalReceiverFunctions->walrcv_send(conn, buffer, nbytes)
 #define walrcv_create_slot(conn, slotname, temporary, snapshot_action, lsn) \
        WalReceiverFunctions->walrcv_create_slot(conn, slotname, temporary, 
snapshot_action, lsn)
+#define walrcv_get_backend_pid(conn) \
+       WalReceiverFunctions->walrcv_get_backend_pid(conn)
 #define walrcv_exec(conn, exec, nRetTypes, retTypes) \
        WalReceiverFunctions->walrcv_exec(conn, exec, nRetTypes, retTypes)
 #define walrcv_disconnect(conn) \
-- 
2.24.0

From c26defb3c50ceea9308b3441ac65bb28267e9f1c Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Fri, 22 Nov 2019 11:09:26 +0100
Subject: [PATCH 3/3] 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         | 14 +++++++++++++
 src/backend/utils/misc/guc.c                  |  9 +++++++++
 src/backend/utils/misc/postgresql.conf.sample |  1 +
 src/include/replication/walreceiver.h         |  1 +
 7 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index d4d1fe45cc..af700f1edf 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -4126,6 +4126,26 @@ <title>Standby Servers</title>
       </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>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index a3c5f86b7e..eac7aa44b6 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2113,7 +2113,14 @@ <title><structname>pg_stat_wal_receiver</structname> 
View</title>
     <row>
      <entry><structfield>slot_name</structfield></entry>
      <entry><type>text</type></entry>
-     <entry>Replication slot name used by this WAL receiver</entry>
+     <entry>
+      Replication slot name used by this WAL receiver.  This is only set if a
+      permanent replication slot is set using <xref
+      linkend="guc-primary-slot-name"/>.  Otherwise, the WAL receiver may use
+      a temporary replication slot (determined by <xref
+      linkend="guc-wal-receiver-create-temp-slot"/>), but these are not shown
+      here.
+     </entry>
     </row>
     <row>
      <entry><structfield>sender_host</structfield></entry>
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c 
b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index ccc31f3cee..e1c4c78217 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 f54ae7690d..b11ecc5a12 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -72,6 +72,7 @@
 
 
 /* GUC variables */
+bool           wal_receiver_create_temp_slot;
 int                    wal_receiver_status_interval;
 int                    wal_receiver_timeout;
 bool           hot_standby_feedback;
@@ -345,6 +346,19 @@ WalReceiverMain(void)
                 */
                WalRcvFetchTimeLineHistoryFiles(startpointTLI, primaryTLI);
 
+               /*
+                * Create temporary replication slot if no slot name is 
configured,
+                * unless disabled.  Note that we don't copy the slot name into 
shared
+                * memory, since it will go away when this walreceiver session 
ends.
+                */
+               if (slotname[0] == '\0' && 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);
+               }
+
                /*
                 * Start streaming.
                 *
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index ba4edde71a..4f590ad5af 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -1959,6 +1959,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 46a06ffacd..501c4e49ac 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 39be805172..0c06b5c3de 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;
-- 
2.24.0

Reply via email to