]> granicus.if.org Git - postgresql/commitdiff
Make pg_basebackup work with pre-9.3 servers, and add server version check.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Fri, 22 Mar 2013 11:02:59 +0000 (13:02 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 25 Mar 2013 17:44:11 +0000 (19:44 +0200)
A new 'starttli' field was added to the response of BASE_BACKUP command.
Make pg_basebackup tolerate the case that it's missing, so that it still
works with older servers.

Add an explicit check for the server version, so that you get a nicer error
message if you try to use it with a pre-9.1 server.

The streaming protocol message format changed in 9.3, so -X stream still won't
work with pre-9.3 servers. I added a version check to ReceiveXLogStream()
earlier, but write that slightly differently, so that in 9.4, it will still
work with a 9.3 server. (In 9.4, the error message needs to be adjusted to
"9.3 or above", though). Also, if the version check fails, don't retry.

doc/src/sgml/ref/pg_basebackup.sgml
src/bin/pg_basebackup/pg_basebackup.c
src/bin/pg_basebackup/pg_receivexlog.c
src/bin/pg_basebackup/receivelog.c
src/bin/pg_basebackup/receivelog.h

index 578541a1e2a24275d120a776db6d27af62d27948..9fe440a66de6246ed51b82182092f7d3ce9e99c6 100644 (file)
@@ -520,6 +520,12 @@ PostgreSQL documentation
    for all additional tablespaces must be identical whenever a backup is
    restored. The main data directory, however, is relocatable to any location.
   </para>
+
+  <para>
+   <application>pg_basebackup</application> works with servers of the same
+   or an older major version, down to 9.1. However, WAL streaming mode (-X
+   stream) only works with server version 9.3.
+  </para>
  </refsect1>
 
  <refsect1>
index eacb5922a2abcb90fe95badec21428f079882b0c..45585069a5ed998ee547587864a1bafe293c8109 100644 (file)
@@ -1223,12 +1223,16 @@ BaseBackup(void)
 {
        PGresult   *res;
        char       *sysidentifier;
+       uint32          latesttli;
        uint32          starttli;
        char            current_path[MAXPGPATH];
        char            escaped_label[MAXPGPATH];
        int                     i;
        char            xlogstart[64];
        char            xlogend[64];
+       int                     minServerMajor,
+                               maxServerMajor;
+       int                     serverMajor;
 
        /*
         * Connect in replication mode to the server
@@ -1238,6 +1242,31 @@ BaseBackup(void)
                /* Error message already written in GetConnection() */
                exit(1);
 
+       /*
+        * Check server version. BASE_BACKUP command was introduced in 9.1, so
+        * we can't work with servers older than 9.1.
+        */
+       minServerMajor = 901;
+       maxServerMajor = PG_VERSION_NUM / 100;
+       serverMajor = PQserverVersion(conn) / 100;
+       if (serverMajor < minServerMajor || serverMajor > maxServerMajor)
+       {
+               const char *serverver = PQparameterStatus(conn, "server_version");
+               fprintf(stderr, _("%s: incompatible server version %s\n"),
+                               progname, serverver ? serverver : "'unknown'");
+               disconnect_and_exit(1);
+       }
+
+       /*
+        * If WAL streaming was requested, also check that the server is new
+        * enough for that.
+        */
+       if (streamwal && !CheckServerVersionForStreaming(conn))
+       {
+               /* Error message already written in CheckServerVersionForStreaming() */
+               disconnect_and_exit(1);
+       }
+
        /*
         * Build contents of recovery.conf if requested
         */
@@ -1262,6 +1291,7 @@ BaseBackup(void)
                disconnect_and_exit(1);
        }
        sysidentifier = pg_strdup(PQgetvalue(res, 0, 0));
+       latesttli = atoi(PQgetvalue(res, 0, 1));
        PQclear(res);
 
        /*
@@ -1293,7 +1323,7 @@ BaseBackup(void)
                                progname, PQerrorMessage(conn));
                disconnect_and_exit(1);
        }
-       if (PQntuples(res) != 1 || PQnfields(res) < 2)
+       if (PQntuples(res) != 1)
        {
                fprintf(stderr,
                                _("%s: server returned unexpected response to BASE_BACKUP command; got %d rows and %d fields, expected %d rows and %d fields\n"),
@@ -1302,8 +1332,14 @@ BaseBackup(void)
        }
 
        strcpy(xlogstart, PQgetvalue(res, 0, 0));
-       starttli = atoi(PQgetvalue(res, 0, 1));
-
+       /*
+        * 9.3 and later sends the TLI of the starting point. With older servers,
+        * assume it's the same as the latest timeline reported by IDENTIFY_SYSTEM.
+        */
+       if (PQnfields(res) >= 2)
+               starttli = atoi(PQgetvalue(res, 0, 1));
+       else
+               starttli = latesttli;
        PQclear(res);
        MemSet(xlogend, 0, sizeof(xlogend));
 
index e68f8ea7079a6c2c0bf7dc180dadde37c57b9570..e4da799d1fddb28617d46c92f4176618427a71b5 100644 (file)
@@ -229,6 +229,16 @@ StreamLog(void)
                /* Error message already written in GetConnection() */
                return;
 
+       if (!CheckServerVersionForStreaming(conn))
+       {
+               /*
+                * Error message already written in CheckServerVersionForStreaming().
+                * There's no hope of recovering from a version mismatch, so don't
+                * retry.
+                */
+               disconnect_and_exit(1);
+       }
+
        /*
         * Run IDENTIFY_SYSTEM so we can get the timeline and current xlog
         * position.
index 1f7611f4440878ed15c833c8e7b9d5fcbb9dd802..2bf4df961ea6fe849efc82700a6ec809d2d6ab71 100644 (file)
@@ -436,6 +436,40 @@ sendFeedback(PGconn *conn, XLogRecPtr blockpos, int64 now, bool replyRequested)
        return true;
 }
 
+/*
+ * Check that the server version we're connected to is supported by
+ * ReceiveXlogStream().
+ *
+ * If it's not, an error message is printed to stderr, and false is returned.
+ */
+bool
+CheckServerVersionForStreaming(PGconn *conn)
+{
+       int                     minServerMajor,
+                               maxServerMajor;
+       int                     serverMajor;
+
+       /*
+        * The message format used in streaming replication changed in 9.3, so we
+        * cannot stream from older servers. And we don't support servers newer
+        * than the client; it might work, but we don't know, so err on the safe
+        * side.
+        */
+       minServerMajor = 903;
+       maxServerMajor = PG_VERSION_NUM / 100;
+       serverMajor = PQserverVersion(conn) / 100;
+       if (serverMajor < minServerMajor || serverMajor > maxServerMajor)
+       {
+               const char *serverver = PQparameterStatus(conn, "server_version");
+               fprintf(stderr, _("%s: incompatible server version %s; streaming is only supported with server version %s\n"),
+                               progname,
+                               serverver ? serverver : "'unknown'",
+                               "9.3");
+               return false;
+       }
+       return true;
+}
+
 /*
  * Receive a log stream starting at the specified position.
  *
@@ -476,19 +510,11 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline,
        XLogRecPtr      stoppos;
 
        /*
-        * The message format used in streaming replication changed in 9.3, so we
-        * cannot stream from older servers. Don't know if we would work with
-        * newer versions, but let's not take the risk.
+        * The caller should've checked the server version already, but doesn't do
+        * any harm to check it here too.
         */
-       if (PQserverVersion(conn) / 100 != PG_VERSION_NUM / 100)
-       {
-               const char *serverver = PQparameterStatus(conn, "server_version");
-               fprintf(stderr, _("%s: incompatible server version %s; streaming is only supported with server version %s\n"),
-                               progname,
-                               serverver ? serverver : "'unknown'",
-                               PG_MAJORVERSION);
+       if (!CheckServerVersionForStreaming(conn))
                return false;
-       }
 
        if (sysidentifier != NULL)
        {
index 53f31a78ecab4e41600901a738d640475d7324ee..7c983cd604a42a78d8a75ca4843439e3fa9344e7 100644 (file)
@@ -6,6 +6,7 @@
  */
 typedef bool (*stream_stop_callback) (XLogRecPtr segendpos, uint32 timeline, bool segment_finished);
 
+extern bool CheckServerVersionForStreaming(PGconn *conn);
 extern bool ReceiveXlogStream(PGconn *conn,
                                  XLogRecPtr startpos,
                                  uint32 timeline,