walreceiver uses a temporary replication slot by default
authorPeter Eisentraut <peter@eisentraut.org>
Tue, 14 Jan 2020 13:07:11 +0000 (14:07 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Tue, 14 Jan 2020 13:40:41 +0000 (14:40 +0100)
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

doc/src/sgml/config.sgml
src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
src/backend/replication/walreceiver.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/include/replication/walreceiver.h

index 5d1c90282f949e229f9318a90f5a3a19e72b938b..5d45b6f7cba7c86d4fdfb9ad39971b9f9c2f6a85 100644 (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>
index b731d3fd04e2cc986d9c486b6f632332a02f95ed..e4fd1f9bb6f0df4a8f0b5713eade8532d1111814 100644 (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);
index 77360f1524b4a159256fe3f7f0a8958284044525..b46411433395843e6266d1730399d0e4c373c543 100644 (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.
         *
index 62285792ecafe5a82f55d8a63a8170662d8a4ea2..e5f8a1301faa3a33f1461029131245792466bd7b 100644 (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
index 087190ce6383fc349423acd4f039d02c3084e646..e1048c0047b88f04ff773fdfb47292a05a9a983b 100644 (file)
 #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
index 172cfa28629c1ea7715ab18d2cb644f35068504c..e08afc6548f8693b5995578b99d7f2f171f1d96a 100644 (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;