mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
Make pg_receivexlog and pg_basebackup -X stream work across timeline switches.
This mirrors the changes done earlier to the server in standby mode. When receivelog reaches the end of a timeline, as reported by the server, it fetches the timeline history file of the next timeline, and restarts streaming from the new timeline by issuing a new START_STREAMING command. When pg_receivexlog crosses a timeline, it leaves the .partial suffix on the last segment on the old timeline. This helps you to tell apart a partial segment left in the directory because of a timeline switch, and a completed segment. If you just follow a single server, it won't make a difference, but it can be significant in more complicated scenarios where new WAL is still generated on the old timeline. This includes two small changes to the streaming replication protocol: First, when you reach the end of timeline while streaming, the server now sends the TLI of the next timeline in the server's history to the client. pg_receivexlog uses that as the next timeline, so that it doesn't need to parse the timeline history file like a standby server does. Second, when BASE_BACKUP command sends the begin and end WAL positions, it now also sends the timeline IDs corresponding the positions.
This commit is contained in:
@@ -243,7 +243,7 @@ LogStreamerMain(logstreamer_param *param)
|
||||
if (!ReceiveXlogStream(param->bgconn, param->startptr, param->timeline,
|
||||
param->sysidentifier, param->xlogdir,
|
||||
reached_end_position, standby_message_timeout,
|
||||
true))
|
||||
NULL))
|
||||
|
||||
/*
|
||||
* Any errors will already have been reported in the function process,
|
||||
@@ -1220,7 +1220,7 @@ BaseBackup(void)
|
||||
{
|
||||
PGresult *res;
|
||||
char *sysidentifier;
|
||||
uint32 timeline;
|
||||
uint32 starttli;
|
||||
char current_path[MAXPGPATH];
|
||||
char escaped_label[MAXPGPATH];
|
||||
int i;
|
||||
@@ -1259,7 +1259,6 @@ BaseBackup(void)
|
||||
disconnect_and_exit(1);
|
||||
}
|
||||
sysidentifier = pg_strdup(PQgetvalue(res, 0, 0));
|
||||
timeline = atoi(PQgetvalue(res, 0, 1));
|
||||
PQclear(res);
|
||||
|
||||
/*
|
||||
@@ -1291,18 +1290,24 @@ BaseBackup(void)
|
||||
progname, PQerrorMessage(conn));
|
||||
disconnect_and_exit(1);
|
||||
}
|
||||
if (PQntuples(res) != 1)
|
||||
if (PQntuples(res) != 1 || PQnfields(res) < 2)
|
||||
{
|
||||
fprintf(stderr, _("%s: no start point returned from server\n"),
|
||||
progname);
|
||||
fprintf(stderr,
|
||||
_("%s: server returned unexpected response to BASE_BACKUP command; got %d rows and %d fields, expected %d rows and %d fields\n"),
|
||||
progname, PQntuples(res), PQnfields(res), 1, 2);
|
||||
disconnect_and_exit(1);
|
||||
}
|
||||
|
||||
strcpy(xlogstart, PQgetvalue(res, 0, 0));
|
||||
if (verbose && includewal)
|
||||
fprintf(stderr, "transaction log start point: %s\n", xlogstart);
|
||||
starttli = atoi(PQgetvalue(res, 0, 1));
|
||||
|
||||
PQclear(res);
|
||||
MemSet(xlogend, 0, sizeof(xlogend));
|
||||
|
||||
if (verbose && includewal)
|
||||
fprintf(stderr, _("transaction log start point: %s on timeline %u\n"),
|
||||
xlogstart, starttli);
|
||||
|
||||
/*
|
||||
* Get the header
|
||||
*/
|
||||
@@ -1358,7 +1363,7 @@ BaseBackup(void)
|
||||
if (verbose)
|
||||
fprintf(stderr, _("%s: starting background WAL receiver\n"),
|
||||
progname);
|
||||
StartLogStreamer(xlogstart, timeline, sysidentifier);
|
||||
StartLogStreamer(xlogstart, starttli, sysidentifier);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user