mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
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.
This commit is contained in:
@ -520,6 +520,12 @@ PostgreSQL documentation
|
|||||||
for all additional tablespaces must be identical whenever a backup is
|
for all additional tablespaces must be identical whenever a backup is
|
||||||
restored. The main data directory, however, is relocatable to any location.
|
restored. The main data directory, however, is relocatable to any location.
|
||||||
</para>
|
</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>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
@ -1223,12 +1223,16 @@ BaseBackup(void)
|
|||||||
{
|
{
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
char *sysidentifier;
|
char *sysidentifier;
|
||||||
|
uint32 latesttli;
|
||||||
uint32 starttli;
|
uint32 starttli;
|
||||||
char current_path[MAXPGPATH];
|
char current_path[MAXPGPATH];
|
||||||
char escaped_label[MAXPGPATH];
|
char escaped_label[MAXPGPATH];
|
||||||
int i;
|
int i;
|
||||||
char xlogstart[64];
|
char xlogstart[64];
|
||||||
char xlogend[64];
|
char xlogend[64];
|
||||||
|
int minServerMajor,
|
||||||
|
maxServerMajor;
|
||||||
|
int serverMajor;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Connect in replication mode to the server
|
* Connect in replication mode to the server
|
||||||
@ -1238,6 +1242,31 @@ BaseBackup(void)
|
|||||||
/* Error message already written in GetConnection() */
|
/* Error message already written in GetConnection() */
|
||||||
exit(1);
|
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
|
* Build contents of recovery.conf if requested
|
||||||
*/
|
*/
|
||||||
@ -1262,6 +1291,7 @@ BaseBackup(void)
|
|||||||
disconnect_and_exit(1);
|
disconnect_and_exit(1);
|
||||||
}
|
}
|
||||||
sysidentifier = pg_strdup(PQgetvalue(res, 0, 0));
|
sysidentifier = pg_strdup(PQgetvalue(res, 0, 0));
|
||||||
|
latesttli = atoi(PQgetvalue(res, 0, 1));
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1293,7 +1323,7 @@ BaseBackup(void)
|
|||||||
progname, PQerrorMessage(conn));
|
progname, PQerrorMessage(conn));
|
||||||
disconnect_and_exit(1);
|
disconnect_and_exit(1);
|
||||||
}
|
}
|
||||||
if (PQntuples(res) != 1 || PQnfields(res) < 2)
|
if (PQntuples(res) != 1)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
_("%s: server returned unexpected response to BASE_BACKUP command; got %d rows and %d fields, expected %d rows and %d fields\n"),
|
_("%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));
|
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);
|
PQclear(res);
|
||||||
MemSet(xlogend, 0, sizeof(xlogend));
|
MemSet(xlogend, 0, sizeof(xlogend));
|
||||||
|
|
||||||
|
@ -229,6 +229,16 @@ StreamLog(void)
|
|||||||
/* Error message already written in GetConnection() */
|
/* Error message already written in GetConnection() */
|
||||||
return;
|
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
|
* Run IDENTIFY_SYSTEM so we can get the timeline and current xlog
|
||||||
* position.
|
* position.
|
||||||
|
@ -436,6 +436,40 @@ sendFeedback(PGconn *conn, XLogRecPtr blockpos, int64 now, bool replyRequested)
|
|||||||
return true;
|
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.
|
* Receive a log stream starting at the specified position.
|
||||||
*
|
*
|
||||||
@ -476,19 +510,11 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline,
|
|||||||
XLogRecPtr stoppos;
|
XLogRecPtr stoppos;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The message format used in streaming replication changed in 9.3, so we
|
* The caller should've checked the server version already, but doesn't do
|
||||||
* cannot stream from older servers. Don't know if we would work with
|
* any harm to check it here too.
|
||||||
* newer versions, but let's not take the risk.
|
|
||||||
*/
|
*/
|
||||||
if (PQserverVersion(conn) / 100 != PG_VERSION_NUM / 100)
|
if (!CheckServerVersionForStreaming(conn))
|
||||||
{
|
|
||||||
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);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (sysidentifier != NULL)
|
if (sysidentifier != NULL)
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
typedef bool (*stream_stop_callback) (XLogRecPtr segendpos, uint32 timeline, bool segment_finished);
|
typedef bool (*stream_stop_callback) (XLogRecPtr segendpos, uint32 timeline, bool segment_finished);
|
||||||
|
|
||||||
|
extern bool CheckServerVersionForStreaming(PGconn *conn);
|
||||||
extern bool ReceiveXlogStream(PGconn *conn,
|
extern bool ReceiveXlogStream(PGconn *conn,
|
||||||
XLogRecPtr startpos,
|
XLogRecPtr startpos,
|
||||||
uint32 timeline,
|
uint32 timeline,
|
||||||
|
Reference in New Issue
Block a user