aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2013-03-22 13:02:59 +0200
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2013-03-25 19:44:11 +0200
commitd298b50a3b469c088bb40a4d36d38111b4cd574d (patch)
treebbb327e9d755e00abf0b74478a58e3f8667624b6
parentea988ee8c8b191615e730f930bcde6144a598688 (diff)
downloadpostgresql-d298b50a3b469c088bb40a4d36d38111b4cd574d.tar.gz
postgresql-d298b50a3b469c088bb40a4d36d38111b4cd574d.zip
Make pg_basebackup work with pre-9.3 servers, and add server version check.
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.
-rw-r--r--doc/src/sgml/ref/pg_basebackup.sgml6
-rw-r--r--src/bin/pg_basebackup/pg_basebackup.c42
-rw-r--r--src/bin/pg_basebackup/pg_receivexlog.c10
-rw-r--r--src/bin/pg_basebackup/receivelog.c48
-rw-r--r--src/bin/pg_basebackup/receivelog.h1
5 files changed, 93 insertions, 14 deletions
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml b/doc/src/sgml/ref/pg_basebackup.sgml
index 578541a1e2a..9fe440a66de 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -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>
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index eacb5922a2a..45585069a5e 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -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
@@ -1239,6 +1243,31 @@ BaseBackup(void)
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
*/
if (writerecoveryconf)
@@ -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));
diff --git a/src/bin/pg_basebackup/pg_receivexlog.c b/src/bin/pg_basebackup/pg_receivexlog.c
index e68f8ea7079..e4da799d1fd 100644
--- a/src/bin/pg_basebackup/pg_receivexlog.c
+++ b/src/bin/pg_basebackup/pg_receivexlog.c
@@ -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.
diff --git a/src/bin/pg_basebackup/receivelog.c b/src/bin/pg_basebackup/receivelog.c
index 1f7611f4440..2bf4df961ea 100644
--- a/src/bin/pg_basebackup/receivelog.c
+++ b/src/bin/pg_basebackup/receivelog.c
@@ -437,6 +437,40 @@ sendFeedback(PGconn *conn, XLogRecPtr blockpos, int64 now, bool replyRequested)
}
/*
+ * 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.
*
* If sysidentifier is specified, validate that both the system
@@ -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)
{
diff --git a/src/bin/pg_basebackup/receivelog.h b/src/bin/pg_basebackup/receivelog.h
index 53f31a78eca..7c983cd604a 100644
--- a/src/bin/pg_basebackup/receivelog.h
+++ b/src/bin/pg_basebackup/receivelog.h
@@ -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,