pg_receivexlog_loop.patch

application/octet-stream

Filename: pg_receivexlog_loop.patch
Type: application/octet-stream
Part: 0
Message: Re: pg_receivexlog stops upon server restart

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
doc/src/sgml/ref/pg_receivexlog.sgml 19 0
src/bin/pg_basebackup/pg_basebackup.c 6 0
src/bin/pg_basebackup/pg_receivexlog.c 35 3
src/bin/pg_basebackup/streamutil.c 6 1
diff --git a/doc/src/sgml/ref/pg_receivexlog.sgml b/doc/src/sgml/ref/pg_receivexlog.sgml
index 8e5fca4..ee31065 100644
--- a/doc/src/sgml/ref/pg_receivexlog.sgml
+++ b/doc/src/sgml/ref/pg_receivexlog.sgml
@@ -58,6 +58,14 @@ PostgreSQL documentation
    configured with <xref linkend="guc-max-wal-senders"> set high enough to
    leave at least one session available for the stream.
   </para>
+
+  <para>
+   If the connection is lost, or if it cannot be initially established,
+   with a non fatal error, <application>pg_receivexlog</application> will
+   retry the connection indefinitely, and reestablish streaming as soon
+   as possible. To avoid this behavior, use the <literal>-n</literal>
+   parameter.
+  </para>
  </refsect1>
 
  <refsect1>
@@ -87,6 +95,17 @@ PostgreSQL documentation
 
     <variablelist>
      <varlistentry>
+      <term><option>-n</option></term>
+      <term><option>--noloop</option></term>
+      <listitem>
+       <para>
+        Don't loop on connection errors. Instead, exit right away with
+        an error.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><option>-v</option></term>
       <term><option>--verbose</option></term>
       <listitem>
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 0289c4b..b08afbd 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -280,6 +280,9 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier)
 
 	/* Get a second connection */
 	param->bgconn = GetConnection();
+	if (!param->bgconn)
+		/* Error message already written in GetConnection() */
+		exit(1);
 
 	/*
 	 * Always in plain format, so we can write to basedir/pg_xlog. But the
@@ -916,6 +919,9 @@ BaseBackup(void)
 	 * Connect in replication mode to the server
 	 */
 	conn = GetConnection();
+	if (!conn)
+		/* Error message already written in GetConnection() */
+		exit(1);
 
 	/*
 	 * Run IDENTIFY_SYSTEM so we can get the timeline
diff --git a/src/bin/pg_basebackup/pg_receivexlog.c b/src/bin/pg_basebackup/pg_receivexlog.c
index 2134c87..c1fae27 100644
--- a/src/bin/pg_basebackup/pg_receivexlog.c
+++ b/src/bin/pg_basebackup/pg_receivexlog.c
@@ -33,9 +33,13 @@
 
 #include "getopt_long.h"
 
+/* Time to sleep between reconnection attempts */
+#define RECONNECT_SLEEP_TIME 5
+
 /* Global options */
 char	   *basedir = NULL;
 int			verbose = 0;
+int			noloop = 0;
 int			standby_message_timeout = 10;		/* 10 sec = default */
 volatile bool time_to_abort = false;
 
@@ -55,6 +59,7 @@ usage(void)
 	printf(_("\nOptions controlling the output:\n"));
 	printf(_("  -D, --dir=directory       receive xlog files into this directory\n"));
 	printf(_("\nGeneral options:\n"));
+	printf(_("  -n, --noloop              do not loop on connection lost\n"));
 	printf(_("  -v, --verbose             output verbose messages\n"));
 	printf(_("  -?, --help                show this help, then exit\n"));
 	printf(_("  -V, --version             output version information, then exit\n"));
@@ -223,6 +228,9 @@ StreamLog(void)
 	 * Connect in replication mode to the server
 	 */
 	conn = GetConnection();
+	if (!conn)
+		/* Error message already written in GetConnection() */
+		return;
 
 	/*
 	 * Run IDENTIFY_SYSTEM so we can get the timeline and current xlog
@@ -326,7 +334,7 @@ main(int argc, char **argv)
 		}
 	}
 
-	while ((c = getopt_long(argc, argv, "D:h:p:U:s:wWv",
+	while ((c = getopt_long(argc, argv, "D:h:p:U:s:nwWv",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -364,6 +372,9 @@ main(int argc, char **argv)
 					exit(1);
 				}
 				break;
+			case 'n':
+				noloop = 1;
+				break;
 			case 'v':
 				verbose++;
 				break;
@@ -406,7 +417,28 @@ main(int argc, char **argv)
 	pqsignal(SIGINT, sigint_handler);
 #endif
 
-	StreamLog();
+	while (true)
+	{
+		StreamLog();
+		if (time_to_abort)
+			/*
+			 * We've been Ctrl-C'ed. That's not an error, so exit without
+			 * an errorcode.
+			 */
+			exit(0);
+		else if (noloop)
+		{
+			fprintf(stderr, _("%s: disconnected.\n"), progname);
+			exit(1);
+		}
+		else
+		{
+			fprintf(stderr, _("%s: disconnected. Waiting %d seconds to try again\n"),
+					progname, RECONNECT_SLEEP_TIME);
+			pg_usleep(RECONNECT_SLEEP_TIME * 1000000);
+		}
+	}
 
-	exit(0);
+	/* Never get here */
+	exit(2);
 }
diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c
index cc01537..1416faa 100644
--- a/src/bin/pg_basebackup/streamutil.c
+++ b/src/bin/pg_basebackup/streamutil.c
@@ -65,6 +65,11 @@ xmalloc0(int size)
 }
 
 
+/*
+ * Connect to the server. Returns a valid PGconn pointer if connected,
+ * or NULL on non-permanent error. On permanent error, the function will
+ * call exit(1) directly.
+ */
 PGconn *
 GetConnection(void)
 {
@@ -151,7 +156,7 @@ GetConnection(void)
 		{
 			fprintf(stderr, _("%s: could not connect to server: %s\n"),
 					progname, PQerrorMessage(tmpconn));
-			exit(1);
+			return NULL;
 		}
 
 		/* Connection ok! */