2011-10-26 20:13:33 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
2017-05-12 17:49:56 +02:00
|
|
|
* pg_receivewal.c - receive streaming WAL data and write it
|
2011-10-26 20:13:33 +02:00
|
|
|
* to a local file.
|
|
|
|
*
|
|
|
|
* Author: Magnus Hagander <magnus@hagander.net>
|
|
|
|
*
|
2017-01-03 19:48:53 +01:00
|
|
|
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
|
2011-10-26 20:13:33 +02:00
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2017-02-09 22:23:46 +01:00
|
|
|
* src/bin/pg_basebackup/pg_receivewal.c
|
2011-10-26 20:13:33 +02:00
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2012-12-13 13:59:13 +01:00
|
|
|
#include "postgres_fe.h"
|
2011-10-26 20:13:33 +02:00
|
|
|
|
|
|
|
#include <dirent.h>
|
2013-03-17 19:11:48 +01:00
|
|
|
#include <signal.h>
|
2011-10-26 20:13:33 +02:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2013-03-17 19:11:48 +01:00
|
|
|
#include "libpq-fe.h"
|
|
|
|
#include "access/xlog_internal.h"
|
2011-10-26 20:13:33 +02:00
|
|
|
#include "getopt_long.h"
|
|
|
|
|
2013-03-17 19:11:48 +01:00
|
|
|
#include "receivelog.h"
|
|
|
|
#include "streamutil.h"
|
|
|
|
|
|
|
|
|
2012-05-27 11:05:24 +02:00
|
|
|
/* Time to sleep between reconnection attempts */
|
|
|
|
#define RECONNECT_SLEEP_TIME 5
|
|
|
|
|
2011-10-26 20:13:33 +02:00
|
|
|
/* Global options */
|
2013-12-16 10:27:30 +01:00
|
|
|
static char *basedir = NULL;
|
|
|
|
static int verbose = 0;
|
2017-01-17 12:10:26 +01:00
|
|
|
static int compresslevel = 0;
|
2013-12-16 10:27:30 +01:00
|
|
|
static int noloop = 0;
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
static int standby_message_timeout = 10 * 1000; /* 10 sec = default */
|
2017-09-11 22:30:50 +02:00
|
|
|
static volatile bool time_to_stop = false;
|
2014-10-06 12:51:37 +02:00
|
|
|
static bool do_create_slot = false;
|
2015-07-12 22:06:27 +02:00
|
|
|
static bool slot_exists_ok = false;
|
2014-10-06 12:51:37 +02:00
|
|
|
static bool do_drop_slot = false;
|
2017-10-29 08:16:55 +01:00
|
|
|
static bool do_sync = true;
|
2014-11-17 18:32:48 +01:00
|
|
|
static bool synchronous = false;
|
2017-01-16 13:56:43 +01:00
|
|
|
static char *replication_slot = NULL;
|
2017-09-11 22:30:50 +02:00
|
|
|
static XLogRecPtr endpos = InvalidXLogRecPtr;
|
2011-10-26 20:13:33 +02:00
|
|
|
|
|
|
|
|
|
|
|
static void usage(void);
|
2015-05-24 03:35:49 +02:00
|
|
|
static DIR *get_destination_dir(char *dest_folder);
|
2014-10-06 12:51:37 +02:00
|
|
|
static void close_destination_dir(DIR *dest_dir, char *dest_folder);
|
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.
2013-01-17 19:23:00 +01:00
|
|
|
static XLogRecPtr FindStreamingStart(uint32 *tli);
|
2014-10-06 12:51:37 +02:00
|
|
|
static void StreamLog(void);
|
2012-07-31 16:11:11 +02:00
|
|
|
static bool stop_streaming(XLogRecPtr segendpos, uint32 timeline,
|
|
|
|
bool segment_finished);
|
2011-10-26 20:13:33 +02:00
|
|
|
|
2014-02-09 13:10:14 +01:00
|
|
|
#define disconnect_and_exit(code) \
|
|
|
|
{ \
|
|
|
|
if (conn != NULL) PQfinish(conn); \
|
|
|
|
exit(code); \
|
|
|
|
}
|
|
|
|
|
2017-01-17 12:10:26 +01:00
|
|
|
/* Routines to evaluate segment file format */
|
2017-05-17 22:31:56 +02:00
|
|
|
#define IsCompressXLogFileName(fname) \
|
|
|
|
(strlen(fname) == XLOG_FNAME_LEN + strlen(".gz") && \
|
2017-01-17 12:10:26 +01:00
|
|
|
strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \
|
|
|
|
strcmp((fname) + XLOG_FNAME_LEN, ".gz") == 0)
|
2017-05-17 22:31:56 +02:00
|
|
|
#define IsPartialCompressXLogFileName(fname) \
|
|
|
|
(strlen(fname) == XLOG_FNAME_LEN + strlen(".gz.partial") && \
|
2017-01-17 12:10:26 +01:00
|
|
|
strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \
|
|
|
|
strcmp((fname) + XLOG_FNAME_LEN, ".gz.partial") == 0)
|
2014-02-09 13:10:14 +01:00
|
|
|
|
2011-10-26 20:13:33 +02:00
|
|
|
static void
|
|
|
|
usage(void)
|
|
|
|
{
|
2017-05-12 17:49:56 +02:00
|
|
|
printf(_("%s receives PostgreSQL streaming write-ahead logs.\n\n"),
|
2011-10-26 20:13:33 +02:00
|
|
|
progname);
|
|
|
|
printf(_("Usage:\n"));
|
|
|
|
printf(_(" %s [OPTION]...\n"), progname);
|
2012-06-11 23:55:27 +02:00
|
|
|
printf(_("\nOptions:\n"));
|
2017-05-12 17:49:56 +02:00
|
|
|
printf(_(" -D, --directory=DIR receive write-ahead log files into this directory\n"));
|
2017-09-11 22:30:50 +02:00
|
|
|
printf(_(" -E, --endpos=LSN exit after receiving the specified LSN\n"));
|
2015-09-16 06:37:39 +02:00
|
|
|
printf(_(" --if-not-exists do not error if slot already exists when creating a slot\n"));
|
2012-07-31 16:11:11 +02:00
|
|
|
printf(_(" -n, --no-loop do not loop on connection lost\n"));
|
2017-10-29 08:16:55 +01:00
|
|
|
printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
|
2014-10-12 07:45:25 +02:00
|
|
|
printf(_(" -s, --status-interval=SECS\n"
|
|
|
|
" time between status packets sent to server (default: %d)\n"), (standby_message_timeout / 1000));
|
|
|
|
printf(_(" -S, --slot=SLOTNAME replication slot to use\n"));
|
2017-05-12 17:49:56 +02:00
|
|
|
printf(_(" --synchronous flush write-ahead log immediately after writing\n"));
|
2012-07-31 16:11:11 +02:00
|
|
|
printf(_(" -v, --verbose output verbose messages\n"));
|
|
|
|
printf(_(" -V, --version output version information, then exit\n"));
|
2017-01-17 12:10:26 +01:00
|
|
|
printf(_(" -Z, --compress=0-9 compress logs with given compression level\n"));
|
2012-07-31 16:11:11 +02:00
|
|
|
printf(_(" -?, --help show this help, then exit\n"));
|
2011-10-26 20:13:33 +02:00
|
|
|
printf(_("\nConnection options:\n"));
|
2013-02-25 13:48:27 +01:00
|
|
|
printf(_(" -d, --dbname=CONNSTR connection string\n"));
|
2012-07-31 16:11:11 +02:00
|
|
|
printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
|
|
|
|
printf(_(" -p, --port=PORT database server port number\n"));
|
|
|
|
printf(_(" -U, --username=NAME connect as specified database user\n"));
|
|
|
|
printf(_(" -w, --no-password never prompt for password\n"));
|
|
|
|
printf(_(" -W, --password force password prompt (should happen automatically)\n"));
|
2014-10-06 12:51:37 +02:00
|
|
|
printf(_("\nOptional actions:\n"));
|
|
|
|
printf(_(" --create-slot create a new replication slot (for the slot's name see --slot)\n"));
|
|
|
|
printf(_(" --drop-slot drop the replication slot (for the slot's name see --slot)\n"));
|
2011-10-26 20:13:33 +02:00
|
|
|
printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
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.
2013-01-17 19:23:00 +01:00
|
|
|
stop_streaming(XLogRecPtr xlogpos, uint32 timeline, bool segment_finished)
|
2011-10-26 20:13:33 +02: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.
2013-01-17 19:23:00 +01:00
|
|
|
static uint32 prevtimeline = 0;
|
|
|
|
static XLogRecPtr prevpos = InvalidXLogRecPtr;
|
|
|
|
|
|
|
|
/* we assume that we get called once at the end of each segment */
|
2012-05-25 11:36:22 +02:00
|
|
|
if (verbose && segment_finished)
|
2011-10-26 20:13:33 +02:00
|
|
|
fprintf(stderr, _("%s: finished segment at %X/%X (timeline %u)\n"),
|
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.
2013-01-17 19:23:00 +01:00
|
|
|
progname, (uint32) (xlogpos >> 32), (uint32) xlogpos,
|
2012-06-24 17:51:37 +02:00
|
|
|
timeline);
|
2011-10-26 20:13:33 +02:00
|
|
|
|
2017-09-11 22:30:50 +02:00
|
|
|
if (!XLogRecPtrIsInvalid(endpos) && endpos < xlogpos)
|
|
|
|
{
|
|
|
|
if (verbose)
|
|
|
|
fprintf(stderr, _("%s: stopped streaming at %X/%X (timeline %u)\n"),
|
|
|
|
progname, (uint32) (xlogpos >> 32), (uint32) xlogpos,
|
|
|
|
timeline);
|
|
|
|
time_to_stop = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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.
2013-01-17 19:23:00 +01:00
|
|
|
/*
|
Fix walsender failure at promotion.
If a standby server has a cascading standby server connected to it, it's
possible that WAL has already been sent up to the next WAL page boundary,
splitting a WAL record in the middle, when the first standby server is
promoted. Don't throw an assertion failure or error in walsender if that
happens.
Also, fix a variant of the same bug in pg_receivexlog: if it had already
received WAL on previous timeline up to a segment boundary, when the
upstream standby server is promoted so that the timeline switch record falls
on the previous segment, pg_receivexlog would miss the segment containing
the timeline switch. To fix that, have walsender send the position of the
timeline switch at end-of-streaming, in addition to the next timeline's ID.
It was previously assumed that the switch happened exactly where the
streaming stopped.
Note: this is an incompatible change in the streaming protocol. You might
get an error if you try to stream over timeline switches, if the client is
running 9.3beta1 and the server is more recent. It should be fine after a
reconnect, however.
Reported by Fujii Masao.
2013-05-08 19:10:17 +02:00
|
|
|
* Note that we report the previous, not current, position here. After a
|
|
|
|
* timeline switch, xlogpos points to the beginning of the segment because
|
|
|
|
* that's where we always begin streaming. Reporting the end of previous
|
|
|
|
* timeline isn't totally accurate, because the next timeline can begin
|
|
|
|
* slightly before the end of the WAL that we received on the previous
|
|
|
|
* timeline, but it's close enough for reporting purposes.
|
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.
2013-01-17 19:23:00 +01:00
|
|
|
*/
|
2017-08-16 02:25:37 +02:00
|
|
|
if (verbose && prevtimeline != 0 && prevtimeline != timeline)
|
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.
2013-01-17 19:23:00 +01:00
|
|
|
fprintf(stderr, _("%s: switched to timeline %u at %X/%X\n"),
|
|
|
|
progname, timeline,
|
|
|
|
(uint32) (prevpos >> 32), (uint32) prevpos);
|
|
|
|
|
|
|
|
prevtimeline = timeline;
|
|
|
|
prevpos = xlogpos;
|
|
|
|
|
2017-09-11 22:30:50 +02:00
|
|
|
if (time_to_stop)
|
2011-10-26 20:13:33 +02:00
|
|
|
{
|
2017-08-16 02:25:37 +02:00
|
|
|
if (verbose)
|
|
|
|
fprintf(stderr, _("%s: received interrupt signal, exiting\n"),
|
|
|
|
progname);
|
2011-10-26 20:13:33 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-06 12:51:37 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get destination directory.
|
|
|
|
*/
|
2015-05-24 03:35:49 +02:00
|
|
|
static DIR *
|
2014-10-06 12:51:37 +02:00
|
|
|
get_destination_dir(char *dest_folder)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
DIR *dir;
|
2014-10-06 12:51:37 +02:00
|
|
|
|
|
|
|
Assert(dest_folder != NULL);
|
|
|
|
dir = opendir(dest_folder);
|
|
|
|
if (dir == NULL)
|
|
|
|
{
|
|
|
|
fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
|
|
|
|
progname, basedir, strerror(errno));
|
|
|
|
disconnect_and_exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Close existing directory.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
close_destination_dir(DIR *dest_dir, char *dest_folder)
|
|
|
|
{
|
|
|
|
Assert(dest_dir != NULL && dest_folder != NULL);
|
|
|
|
if (closedir(dest_dir))
|
|
|
|
{
|
|
|
|
fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
|
|
|
|
progname, dest_folder, strerror(errno));
|
|
|
|
disconnect_and_exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-26 20:13:33 +02: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.
2013-01-17 19:23:00 +01:00
|
|
|
* Determine starting location for streaming, based on any existing xlog
|
|
|
|
* segments in the directory. We start at the end of the last one that is
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
* complete (size matches wal segment size), on the timeline with highest ID.
|
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.
2013-01-17 19:23:00 +01:00
|
|
|
*
|
|
|
|
* If there are no WAL files in the directory, returns InvalidXLogRecPtr.
|
2011-10-26 20:13:33 +02:00
|
|
|
*/
|
|
|
|
static XLogRecPtr
|
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.
2013-01-17 19:23:00 +01:00
|
|
|
FindStreamingStart(uint32 *tli)
|
2011-10-26 20:13:33 +02:00
|
|
|
{
|
|
|
|
DIR *dir;
|
|
|
|
struct dirent *dirent;
|
2012-06-24 17:06:38 +02:00
|
|
|
XLogSegNo high_segno = 0;
|
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.
2013-01-17 19:23:00 +01:00
|
|
|
uint32 high_tli = 0;
|
Fix two timeline handling bugs in pg_receivexlog.
When a timeline history file is fetched from server, it is initially created
with a temporary file name, and renamed to place. However, the temporary
file name was constructed using an uninitialized buffer. Usually that meant
that the file was created in current directory instead of the target, which
usually goes unnoticed, but if the target is on a different filesystem than
the current dir, the rename() would fail. Fix that.
The second issue is that pg_receivexlog would not take .partial files into
account when determining when scanning the target directory for existing
WAL files. If the timeline has switched in the server several times in the
last WAL segment, and pg_receivexlog is restarted, it would choose a too
old starting point. That's not a problem as long as the old WAL segment
exists in the server and can be streamed over, but will cause a failure if
it's not.
Backpatch to 9.3, where this timeline handling code was written.
Analysed by Andrew Gierth, bug #8453, based on a bug report on IRC.
2013-09-23 09:17:52 +02:00
|
|
|
bool high_ispartial = false;
|
2011-10-26 20:13:33 +02:00
|
|
|
|
2014-10-06 12:51:37 +02:00
|
|
|
dir = get_destination_dir(basedir);
|
2011-10-26 20:13:33 +02:00
|
|
|
|
2014-03-21 18:45:11 +01:00
|
|
|
while (errno = 0, (dirent = readdir(dir)) != NULL)
|
2011-10-26 20:13:33 +02:00
|
|
|
{
|
2012-06-24 17:06:38 +02:00
|
|
|
uint32 tli;
|
|
|
|
XLogSegNo segno;
|
Fix two timeline handling bugs in pg_receivexlog.
When a timeline history file is fetched from server, it is initially created
with a temporary file name, and renamed to place. However, the temporary
file name was constructed using an uninitialized buffer. Usually that meant
that the file was created in current directory instead of the target, which
usually goes unnoticed, but if the target is on a different filesystem than
the current dir, the rename() would fail. Fix that.
The second issue is that pg_receivexlog would not take .partial files into
account when determining when scanning the target directory for existing
WAL files. If the timeline has switched in the server several times in the
last WAL segment, and pg_receivexlog is restarted, it would choose a too
old starting point. That's not a problem as long as the old WAL segment
exists in the server and can be streamed over, but will cause a failure if
it's not.
Backpatch to 9.3, where this timeline handling code was written.
Analysed by Andrew Gierth, bug #8453, based on a bug report on IRC.
2013-09-23 09:17:52 +02:00
|
|
|
bool ispartial;
|
2017-01-17 12:10:26 +01:00
|
|
|
bool iscompress;
|
2011-10-26 20:13:33 +02: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.
2013-01-17 19:23:00 +01:00
|
|
|
/*
|
|
|
|
* Check if the filename looks like an xlog file, or a .partial file.
|
|
|
|
*/
|
2015-05-08 20:58:57 +02:00
|
|
|
if (IsXLogFileName(dirent->d_name))
|
2017-01-17 12:10:26 +01:00
|
|
|
{
|
Fix two timeline handling bugs in pg_receivexlog.
When a timeline history file is fetched from server, it is initially created
with a temporary file name, and renamed to place. However, the temporary
file name was constructed using an uninitialized buffer. Usually that meant
that the file was created in current directory instead of the target, which
usually goes unnoticed, but if the target is on a different filesystem than
the current dir, the rename() would fail. Fix that.
The second issue is that pg_receivexlog would not take .partial files into
account when determining when scanning the target directory for existing
WAL files. If the timeline has switched in the server several times in the
last WAL segment, and pg_receivexlog is restarted, it would choose a too
old starting point. That's not a problem as long as the old WAL segment
exists in the server and can be streamed over, but will cause a failure if
it's not.
Backpatch to 9.3, where this timeline handling code was written.
Analysed by Andrew Gierth, bug #8453, based on a bug report on IRC.
2013-09-23 09:17:52 +02:00
|
|
|
ispartial = false;
|
2017-01-17 12:10:26 +01:00
|
|
|
iscompress = false;
|
|
|
|
}
|
2015-05-08 20:58:57 +02:00
|
|
|
else if (IsPartialXLogFileName(dirent->d_name))
|
2017-01-17 12:10:26 +01:00
|
|
|
{
|
|
|
|
ispartial = true;
|
|
|
|
iscompress = false;
|
|
|
|
}
|
|
|
|
else if (IsCompressXLogFileName(dirent->d_name))
|
|
|
|
{
|
|
|
|
ispartial = false;
|
|
|
|
iscompress = true;
|
|
|
|
}
|
|
|
|
else if (IsPartialCompressXLogFileName(dirent->d_name))
|
|
|
|
{
|
Fix two timeline handling bugs in pg_receivexlog.
When a timeline history file is fetched from server, it is initially created
with a temporary file name, and renamed to place. However, the temporary
file name was constructed using an uninitialized buffer. Usually that meant
that the file was created in current directory instead of the target, which
usually goes unnoticed, but if the target is on a different filesystem than
the current dir, the rename() would fail. Fix that.
The second issue is that pg_receivexlog would not take .partial files into
account when determining when scanning the target directory for existing
WAL files. If the timeline has switched in the server several times in the
last WAL segment, and pg_receivexlog is restarted, it would choose a too
old starting point. That's not a problem as long as the old WAL segment
exists in the server and can be streamed over, but will cause a failure if
it's not.
Backpatch to 9.3, where this timeline handling code was written.
Analysed by Andrew Gierth, bug #8453, based on a bug report on IRC.
2013-09-23 09:17:52 +02:00
|
|
|
ispartial = true;
|
2017-01-17 12:10:26 +01:00
|
|
|
iscompress = true;
|
|
|
|
}
|
Fix two timeline handling bugs in pg_receivexlog.
When a timeline history file is fetched from server, it is initially created
with a temporary file name, and renamed to place. However, the temporary
file name was constructed using an uninitialized buffer. Usually that meant
that the file was created in current directory instead of the target, which
usually goes unnoticed, but if the target is on a different filesystem than
the current dir, the rename() would fail. Fix that.
The second issue is that pg_receivexlog would not take .partial files into
account when determining when scanning the target directory for existing
WAL files. If the timeline has switched in the server several times in the
last WAL segment, and pg_receivexlog is restarted, it would choose a too
old starting point. That's not a problem as long as the old WAL segment
exists in the server and can be streamed over, but will cause a failure if
it's not.
Backpatch to 9.3, where this timeline handling code was written.
Analysed by Andrew Gierth, bug #8453, based on a bug report on IRC.
2013-09-23 09:17:52 +02:00
|
|
|
else
|
2011-10-26 20:13:33 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Looks like an xlog file. Parse its position.
|
|
|
|
*/
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
XLogFromFileName(dirent->d_name, &tli, &segno, WalSegSz);
|
2011-10-26 20:13:33 +02:00
|
|
|
|
Fix two timeline handling bugs in pg_receivexlog.
When a timeline history file is fetched from server, it is initially created
with a temporary file name, and renamed to place. However, the temporary
file name was constructed using an uninitialized buffer. Usually that meant
that the file was created in current directory instead of the target, which
usually goes unnoticed, but if the target is on a different filesystem than
the current dir, the rename() would fail. Fix that.
The second issue is that pg_receivexlog would not take .partial files into
account when determining when scanning the target directory for existing
WAL files. If the timeline has switched in the server several times in the
last WAL segment, and pg_receivexlog is restarted, it would choose a too
old starting point. That's not a problem as long as the old WAL segment
exists in the server and can be streamed over, but will cause a failure if
it's not.
Backpatch to 9.3, where this timeline handling code was written.
Analysed by Andrew Gierth, bug #8453, based on a bug report on IRC.
2013-09-23 09:17:52 +02:00
|
|
|
/*
|
|
|
|
* Check that the segment has the right size, if it's supposed to be
|
2017-01-17 12:10:26 +01:00
|
|
|
* completed. For non-compressed segments just check the on-disk size
|
2017-05-17 22:31:56 +02:00
|
|
|
* and see if it matches a completed segment. For compressed segments,
|
|
|
|
* look at the last 4 bytes of the compressed file, which is where the
|
|
|
|
* uncompressed size is located for gz files with a size lower than
|
|
|
|
* 4GB, and then compare it to the size of a completed segment. The 4
|
|
|
|
* last bytes correspond to the ISIZE member according to
|
|
|
|
* http://www.zlib.org/rfc-gzip.html.
|
Fix two timeline handling bugs in pg_receivexlog.
When a timeline history file is fetched from server, it is initially created
with a temporary file name, and renamed to place. However, the temporary
file name was constructed using an uninitialized buffer. Usually that meant
that the file was created in current directory instead of the target, which
usually goes unnoticed, but if the target is on a different filesystem than
the current dir, the rename() would fail. Fix that.
The second issue is that pg_receivexlog would not take .partial files into
account when determining when scanning the target directory for existing
WAL files. If the timeline has switched in the server several times in the
last WAL segment, and pg_receivexlog is restarted, it would choose a too
old starting point. That's not a problem as long as the old WAL segment
exists in the server and can be streamed over, but will cause a failure if
it's not.
Backpatch to 9.3, where this timeline handling code was written.
Analysed by Andrew Gierth, bug #8453, based on a bug report on IRC.
2013-09-23 09:17:52 +02:00
|
|
|
*/
|
2017-01-17 12:10:26 +01:00
|
|
|
if (!ispartial && !iscompress)
|
2011-10-26 20:13:33 +02:00
|
|
|
{
|
Fix two timeline handling bugs in pg_receivexlog.
When a timeline history file is fetched from server, it is initially created
with a temporary file name, and renamed to place. However, the temporary
file name was constructed using an uninitialized buffer. Usually that meant
that the file was created in current directory instead of the target, which
usually goes unnoticed, but if the target is on a different filesystem than
the current dir, the rename() would fail. Fix that.
The second issue is that pg_receivexlog would not take .partial files into
account when determining when scanning the target directory for existing
WAL files. If the timeline has switched in the server several times in the
last WAL segment, and pg_receivexlog is restarted, it would choose a too
old starting point. That's not a problem as long as the old WAL segment
exists in the server and can be streamed over, but will cause a failure if
it's not.
Backpatch to 9.3, where this timeline handling code was written.
Analysed by Andrew Gierth, bug #8453, based on a bug report on IRC.
2013-09-23 09:17:52 +02:00
|
|
|
struct stat statbuf;
|
2017-04-11 20:13:31 +02:00
|
|
|
char fullpath[MAXPGPATH * 2];
|
2011-10-26 20:13:33 +02:00
|
|
|
|
Fix two timeline handling bugs in pg_receivexlog.
When a timeline history file is fetched from server, it is initially created
with a temporary file name, and renamed to place. However, the temporary
file name was constructed using an uninitialized buffer. Usually that meant
that the file was created in current directory instead of the target, which
usually goes unnoticed, but if the target is on a different filesystem than
the current dir, the rename() would fail. Fix that.
The second issue is that pg_receivexlog would not take .partial files into
account when determining when scanning the target directory for existing
WAL files. If the timeline has switched in the server several times in the
last WAL segment, and pg_receivexlog is restarted, it would choose a too
old starting point. That's not a problem as long as the old WAL segment
exists in the server and can be streamed over, but will cause a failure if
it's not.
Backpatch to 9.3, where this timeline handling code was written.
Analysed by Andrew Gierth, bug #8453, based on a bug report on IRC.
2013-09-23 09:17:52 +02:00
|
|
|
snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name);
|
|
|
|
if (stat(fullpath, &statbuf) != 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, _("%s: could not stat file \"%s\": %s\n"),
|
|
|
|
progname, fullpath, strerror(errno));
|
|
|
|
disconnect_and_exit(1);
|
|
|
|
}
|
|
|
|
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
if (statbuf.st_size != WalSegSz)
|
2011-10-26 20:13:33 +02:00
|
|
|
{
|
Fix two timeline handling bugs in pg_receivexlog.
When a timeline history file is fetched from server, it is initially created
with a temporary file name, and renamed to place. However, the temporary
file name was constructed using an uninitialized buffer. Usually that meant
that the file was created in current directory instead of the target, which
usually goes unnoticed, but if the target is on a different filesystem than
the current dir, the rename() would fail. Fix that.
The second issue is that pg_receivexlog would not take .partial files into
account when determining when scanning the target directory for existing
WAL files. If the timeline has switched in the server several times in the
last WAL segment, and pg_receivexlog is restarted, it would choose a too
old starting point. That's not a problem as long as the old WAL segment
exists in the server and can be streamed over, but will cause a failure if
it's not.
Backpatch to 9.3, where this timeline handling code was written.
Analysed by Andrew Gierth, bug #8453, based on a bug report on IRC.
2013-09-23 09:17:52 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
_("%s: segment file \"%s\" has incorrect size %d, skipping\n"),
|
|
|
|
progname, dirent->d_name, (int) statbuf.st_size);
|
2011-10-26 20:13:33 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2017-01-17 12:10:26 +01:00
|
|
|
else if (!ispartial && iscompress)
|
|
|
|
{
|
2017-05-17 22:31:56 +02:00
|
|
|
int fd;
|
|
|
|
char buf[4];
|
|
|
|
int bytes_out;
|
|
|
|
char fullpath[MAXPGPATH * 2];
|
2017-01-17 12:10:26 +01:00
|
|
|
|
|
|
|
snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name);
|
|
|
|
|
|
|
|
fd = open(fullpath, O_RDONLY | PG_BINARY);
|
|
|
|
if (fd < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, _("%s: could not open compressed file \"%s\": %s\n"),
|
|
|
|
progname, fullpath, strerror(errno));
|
|
|
|
disconnect_and_exit(1);
|
|
|
|
}
|
2017-05-17 22:31:56 +02:00
|
|
|
if (lseek(fd, (off_t) (-4), SEEK_END) < 0)
|
2017-01-17 12:10:26 +01:00
|
|
|
{
|
2017-08-05 00:31:01 +02:00
|
|
|
fprintf(stderr, _("%s: could not seek in compressed file \"%s\": %s\n"),
|
2017-01-17 12:10:26 +01:00
|
|
|
progname, fullpath, strerror(errno));
|
|
|
|
disconnect_and_exit(1);
|
|
|
|
}
|
|
|
|
if (read(fd, (char *) buf, sizeof(buf)) != sizeof(buf))
|
|
|
|
{
|
|
|
|
fprintf(stderr, _("%s: could not read compressed file \"%s\": %s\n"),
|
|
|
|
progname, fullpath, strerror(errno));
|
|
|
|
disconnect_and_exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
bytes_out = (buf[3] << 24) | (buf[2] << 16) |
|
2017-05-17 22:31:56 +02:00
|
|
|
(buf[1] << 8) | buf[0];
|
2017-01-17 12:10:26 +01:00
|
|
|
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
if (bytes_out != WalSegSz)
|
2017-01-17 12:10:26 +01:00
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
_("%s: compressed segment file \"%s\" has incorrect uncompressed size %d, skipping\n"),
|
|
|
|
progname, dirent->d_name, bytes_out);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
Fix two timeline handling bugs in pg_receivexlog.
When a timeline history file is fetched from server, it is initially created
with a temporary file name, and renamed to place. However, the temporary
file name was constructed using an uninitialized buffer. Usually that meant
that the file was created in current directory instead of the target, which
usually goes unnoticed, but if the target is on a different filesystem than
the current dir, the rename() would fail. Fix that.
The second issue is that pg_receivexlog would not take .partial files into
account when determining when scanning the target directory for existing
WAL files. If the timeline has switched in the server several times in the
last WAL segment, and pg_receivexlog is restarted, it would choose a too
old starting point. That's not a problem as long as the old WAL segment
exists in the server and can be streamed over, but will cause a failure if
it's not.
Backpatch to 9.3, where this timeline handling code was written.
Analysed by Andrew Gierth, bug #8453, based on a bug report on IRC.
2013-09-23 09:17:52 +02:00
|
|
|
|
|
|
|
/* Looks like a valid segment. Remember that we saw it. */
|
|
|
|
if ((segno > high_segno) ||
|
|
|
|
(segno == high_segno && tli > high_tli) ||
|
|
|
|
(segno == high_segno && tli == high_tli && high_ispartial && !ispartial))
|
2011-10-26 20:13:33 +02:00
|
|
|
{
|
Fix two timeline handling bugs in pg_receivexlog.
When a timeline history file is fetched from server, it is initially created
with a temporary file name, and renamed to place. However, the temporary
file name was constructed using an uninitialized buffer. Usually that meant
that the file was created in current directory instead of the target, which
usually goes unnoticed, but if the target is on a different filesystem than
the current dir, the rename() would fail. Fix that.
The second issue is that pg_receivexlog would not take .partial files into
account when determining when scanning the target directory for existing
WAL files. If the timeline has switched in the server several times in the
last WAL segment, and pg_receivexlog is restarted, it would choose a too
old starting point. That's not a problem as long as the old WAL segment
exists in the server and can be streamed over, but will cause a failure if
it's not.
Backpatch to 9.3, where this timeline handling code was written.
Analysed by Andrew Gierth, bug #8453, based on a bug report on IRC.
2013-09-23 09:17:52 +02:00
|
|
|
high_segno = segno;
|
|
|
|
high_tli = tli;
|
|
|
|
high_ispartial = ispartial;
|
2011-10-26 20:13:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-21 18:45:11 +01:00
|
|
|
if (errno)
|
|
|
|
{
|
|
|
|
fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
|
|
|
|
progname, basedir, strerror(errno));
|
|
|
|
disconnect_and_exit(1);
|
|
|
|
}
|
|
|
|
|
2014-10-06 12:51:37 +02:00
|
|
|
close_destination_dir(dir, basedir);
|
2011-10-26 20:13:33 +02:00
|
|
|
|
2012-06-24 17:06:38 +02:00
|
|
|
if (high_segno > 0)
|
2011-10-26 20:13:33 +02:00
|
|
|
{
|
|
|
|
XLogRecPtr high_ptr;
|
2012-06-10 21:20:04 +02:00
|
|
|
|
2011-11-03 15:37:08 +01:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Move the starting pointer to the start of the next segment, if the
|
|
|
|
* highest one we saw was completed. Otherwise start streaming from
|
|
|
|
* the beginning of the .partial segment.
|
2011-11-03 15:37:08 +01:00
|
|
|
*/
|
Fix two timeline handling bugs in pg_receivexlog.
When a timeline history file is fetched from server, it is initially created
with a temporary file name, and renamed to place. However, the temporary
file name was constructed using an uninitialized buffer. Usually that meant
that the file was created in current directory instead of the target, which
usually goes unnoticed, but if the target is on a different filesystem than
the current dir, the rename() would fail. Fix that.
The second issue is that pg_receivexlog would not take .partial files into
account when determining when scanning the target directory for existing
WAL files. If the timeline has switched in the server several times in the
last WAL segment, and pg_receivexlog is restarted, it would choose a too
old starting point. That's not a problem as long as the old WAL segment
exists in the server and can be streamed over, but will cause a failure if
it's not.
Backpatch to 9.3, where this timeline handling code was written.
Analysed by Andrew Gierth, bug #8453, based on a bug report on IRC.
2013-09-23 09:17:52 +02:00
|
|
|
if (!high_ispartial)
|
|
|
|
high_segno++;
|
2011-10-26 20:13:33 +02:00
|
|
|
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
XLogSegNoOffsetToRecPtr(high_segno, 0, high_ptr, WalSegSz);
|
2011-10-26 20:13:33 +02: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.
2013-01-17 19:23:00 +01:00
|
|
|
*tli = high_tli;
|
2011-10-26 20:13:33 +02:00
|
|
|
return high_ptr;
|
|
|
|
}
|
|
|
|
else
|
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.
2013-01-17 19:23:00 +01:00
|
|
|
return InvalidXLogRecPtr;
|
2011-10-26 20:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start the log streaming
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
StreamLog(void)
|
|
|
|
{
|
2016-03-11 11:08:01 +01:00
|
|
|
XLogRecPtr serverpos;
|
|
|
|
TimeLineID servertli;
|
|
|
|
StreamCtl stream;
|
|
|
|
|
|
|
|
MemSet(&stream, 0, sizeof(stream));
|
2011-10-26 20:13:33 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Connect in replication mode to the server
|
|
|
|
*/
|
2014-10-17 20:06:34 +02:00
|
|
|
if (conn == NULL)
|
|
|
|
conn = GetConnection();
|
2012-05-27 11:05:24 +02:00
|
|
|
if (!conn)
|
|
|
|
/* Error message already written in GetConnection() */
|
|
|
|
return;
|
2011-10-26 20:13:33 +02: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.
2013-03-22 12:02:59 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-10-26 20:13:33 +02:00
|
|
|
/*
|
2014-10-01 17:22:21 +02:00
|
|
|
* Identify server, obtaining start LSN position and current timeline ID
|
|
|
|
* at the same time, necessary if not valid data can be found in the
|
|
|
|
* existing output directory.
|
2011-10-26 20:13:33 +02:00
|
|
|
*/
|
2014-10-01 17:22:21 +02:00
|
|
|
if (!RunIdentifySystem(conn, NULL, &servertli, &serverpos, NULL))
|
2011-10-26 20:13:33 +02:00
|
|
|
disconnect_and_exit(1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Figure out where to start streaming.
|
|
|
|
*/
|
2016-03-11 11:08:01 +01:00
|
|
|
stream.startpos = FindStreamingStart(&stream.timeline);
|
|
|
|
if (stream.startpos == InvalidXLogRecPtr)
|
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.
2013-01-17 19:23:00 +01:00
|
|
|
{
|
2016-03-11 11:08:01 +01:00
|
|
|
stream.startpos = serverpos;
|
|
|
|
stream.timeline = servertli;
|
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.
2013-01-17 19:23:00 +01:00
|
|
|
}
|
2011-10-26 20:13:33 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Always start streaming at the beginning of a segment
|
|
|
|
*/
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
stream.startpos -= XLogSegmentOffset(stream.startpos, WalSegSz);
|
2011-10-26 20:13:33 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Start the replication
|
|
|
|
*/
|
|
|
|
if (verbose)
|
2012-07-31 16:11:11 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
_("%s: starting log streaming at %X/%X (timeline %u)\n"),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
progname, (uint32) (stream.startpos >> 32), (uint32) stream.startpos,
|
2016-03-11 11:08:01 +01:00
|
|
|
stream.timeline);
|
|
|
|
|
|
|
|
stream.stream_stop = stop_streaming;
|
2017-04-28 00:27:02 +02:00
|
|
|
stream.stop_socket = PGINVALID_SOCKET;
|
2016-03-11 11:08:01 +01:00
|
|
|
stream.standby_message_timeout = standby_message_timeout;
|
|
|
|
stream.synchronous = synchronous;
|
2017-10-29 08:16:55 +01:00
|
|
|
stream.do_sync = do_sync;
|
2016-03-11 11:08:01 +01:00
|
|
|
stream.mark_done = false;
|
2017-01-17 12:10:26 +01:00
|
|
|
stream.walmethod = CreateWalDirectoryMethod(basedir, compresslevel,
|
|
|
|
stream.do_sync);
|
2016-03-11 11:08:01 +01:00
|
|
|
stream.partial_suffix = ".partial";
|
2017-01-16 13:56:43 +01:00
|
|
|
stream.replication_slot = replication_slot;
|
2011-10-26 20:13:33 +02:00
|
|
|
|
2016-03-11 11:08:01 +01:00
|
|
|
ReceiveXlogStream(conn, &stream);
|
2011-11-03 15:43:25 +01:00
|
|
|
|
2016-10-23 15:16:31 +02:00
|
|
|
if (!stream.walmethod->finish())
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
_("%s: could not finish writing WAL files: %s\n"),
|
|
|
|
progname, strerror(errno));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-11-03 15:43:25 +01:00
|
|
|
PQfinish(conn);
|
2016-10-25 18:57:56 +02:00
|
|
|
|
|
|
|
FreeWalDirectoryMethod();
|
|
|
|
pg_free(stream.walmethod);
|
|
|
|
|
2014-10-17 20:06:34 +02:00
|
|
|
conn = NULL;
|
2011-10-26 20:13:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When sigint is called, just tell the system to exit at the next possible
|
|
|
|
* moment.
|
|
|
|
*/
|
2011-12-11 00:15:15 +01:00
|
|
|
#ifndef WIN32
|
|
|
|
|
2011-10-26 20:13:33 +02:00
|
|
|
static void
|
|
|
|
sigint_handler(int signum)
|
|
|
|
{
|
2017-09-11 22:30:50 +02:00
|
|
|
time_to_stop = true;
|
2011-10-26 20:13:33 +02:00
|
|
|
}
|
2011-12-11 00:15:15 +01:00
|
|
|
#endif
|
|
|
|
|
2011-10-26 20:13:33 +02:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
static struct option long_options[] = {
|
|
|
|
{"help", no_argument, NULL, '?'},
|
|
|
|
{"version", no_argument, NULL, 'V'},
|
2012-06-11 23:55:27 +02:00
|
|
|
{"directory", required_argument, NULL, 'D'},
|
2013-02-25 13:48:27 +01:00
|
|
|
{"dbname", required_argument, NULL, 'd'},
|
2017-09-11 22:30:50 +02:00
|
|
|
{"endpos", required_argument, NULL, 'E'},
|
2011-10-26 20:13:33 +02:00
|
|
|
{"host", required_argument, NULL, 'h'},
|
|
|
|
{"port", required_argument, NULL, 'p'},
|
|
|
|
{"username", required_argument, NULL, 'U'},
|
2012-07-31 16:11:11 +02:00
|
|
|
{"no-loop", no_argument, NULL, 'n'},
|
2011-10-26 20:13:33 +02:00
|
|
|
{"no-password", no_argument, NULL, 'w'},
|
|
|
|
{"password", no_argument, NULL, 'W'},
|
2012-07-31 16:11:11 +02:00
|
|
|
{"status-interval", required_argument, NULL, 's'},
|
2014-02-01 04:45:17 +01:00
|
|
|
{"slot", required_argument, NULL, 'S'},
|
2011-10-26 20:13:33 +02:00
|
|
|
{"verbose", no_argument, NULL, 'v'},
|
2017-01-17 12:10:26 +01:00
|
|
|
{"compress", required_argument, NULL, 'Z'},
|
2014-10-06 12:51:37 +02:00
|
|
|
/* action */
|
|
|
|
{"create-slot", no_argument, NULL, 1},
|
|
|
|
{"drop-slot", no_argument, NULL, 2},
|
2015-07-12 22:06:27 +02:00
|
|
|
{"if-not-exists", no_argument, NULL, 3},
|
|
|
|
{"synchronous", no_argument, NULL, 4},
|
2017-10-29 08:16:55 +01:00
|
|
|
{"no-sync", no_argument, NULL, 5},
|
2011-10-26 20:13:33 +02:00
|
|
|
{NULL, 0, NULL, 0}
|
|
|
|
};
|
2012-11-30 20:49:55 +01:00
|
|
|
|
2011-10-26 20:13:33 +02:00
|
|
|
int c;
|
|
|
|
int option_index;
|
2014-10-06 12:51:37 +02:00
|
|
|
char *db_name;
|
2017-09-11 22:30:50 +02:00
|
|
|
uint32 hi, lo;
|
2011-10-26 20:13:33 +02:00
|
|
|
|
|
|
|
progname = get_progname(argv[0]);
|
2015-12-28 14:50:35 +01:00
|
|
|
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_basebackup"));
|
2011-10-26 20:13:33 +02:00
|
|
|
|
|
|
|
if (argc > 1)
|
|
|
|
{
|
|
|
|
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
|
|
|
|
{
|
|
|
|
usage();
|
|
|
|
exit(0);
|
|
|
|
}
|
2012-07-31 16:11:11 +02:00
|
|
|
else if (strcmp(argv[1], "-V") == 0 ||
|
|
|
|
strcmp(argv[1], "--version") == 0)
|
2011-10-26 20:13:33 +02:00
|
|
|
{
|
2017-02-09 22:23:46 +01:00
|
|
|
puts("pg_receivewal (PostgreSQL) " PG_VERSION);
|
2011-10-26 20:13:33 +02:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-11 22:30:50 +02:00
|
|
|
while ((c = getopt_long(argc, argv, "D:d:E:h:p:U:s:S:nwWvZ:",
|
2011-10-26 20:13:33 +02:00
|
|
|
long_options, &option_index)) != -1)
|
|
|
|
{
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case 'D':
|
2012-10-02 21:35:10 +02:00
|
|
|
basedir = pg_strdup(optarg);
|
2011-10-26 20:13:33 +02:00
|
|
|
break;
|
2013-02-25 13:48:27 +01:00
|
|
|
case 'd':
|
|
|
|
connection_string = pg_strdup(optarg);
|
|
|
|
break;
|
2011-10-26 20:13:33 +02:00
|
|
|
case 'h':
|
2012-10-02 21:35:10 +02:00
|
|
|
dbhost = pg_strdup(optarg);
|
2011-10-26 20:13:33 +02:00
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
if (atoi(optarg) <= 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, _("%s: invalid port number \"%s\"\n"),
|
|
|
|
progname, optarg);
|
|
|
|
exit(1);
|
|
|
|
}
|
2012-10-02 21:35:10 +02:00
|
|
|
dbport = pg_strdup(optarg);
|
2011-10-26 20:13:33 +02:00
|
|
|
break;
|
|
|
|
case 'U':
|
2012-10-02 21:35:10 +02:00
|
|
|
dbuser = pg_strdup(optarg);
|
2011-10-26 20:13:33 +02:00
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
dbgetpassword = -1;
|
|
|
|
break;
|
|
|
|
case 'W':
|
|
|
|
dbgetpassword = 1;
|
|
|
|
break;
|
|
|
|
case 's':
|
2012-06-10 12:12:36 +02:00
|
|
|
standby_message_timeout = atoi(optarg) * 1000;
|
2011-10-26 20:13:33 +02:00
|
|
|
if (standby_message_timeout < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, _("%s: invalid status interval \"%s\"\n"),
|
|
|
|
progname, optarg);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
2014-02-01 04:45:17 +01:00
|
|
|
case 'S':
|
|
|
|
replication_slot = pg_strdup(optarg);
|
|
|
|
break;
|
2017-09-11 22:30:50 +02:00
|
|
|
case 'E':
|
|
|
|
if (sscanf(optarg, "%X/%X", &hi, &lo) != 2)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
_("%s: could not parse end position \"%s\"\n"),
|
|
|
|
progname, optarg);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
endpos = ((uint64) hi) << 32 | lo;
|
|
|
|
break;
|
2012-05-27 11:05:24 +02:00
|
|
|
case 'n':
|
|
|
|
noloop = 1;
|
|
|
|
break;
|
2011-10-26 20:13:33 +02:00
|
|
|
case 'v':
|
|
|
|
verbose++;
|
|
|
|
break;
|
2017-01-17 12:10:26 +01:00
|
|
|
case 'Z':
|
|
|
|
compresslevel = atoi(optarg);
|
|
|
|
if (compresslevel < 0 || compresslevel > 9)
|
|
|
|
{
|
|
|
|
fprintf(stderr, _("%s: invalid compression level \"%s\"\n"),
|
|
|
|
progname, optarg);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
2014-10-06 12:51:37 +02:00
|
|
|
/* action */
|
|
|
|
case 1:
|
|
|
|
do_create_slot = true;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
do_drop_slot = true;
|
|
|
|
break;
|
2014-11-17 18:32:48 +01:00
|
|
|
case 3:
|
2015-07-12 22:06:27 +02:00
|
|
|
slot_exists_ok = true;
|
|
|
|
break;
|
|
|
|
case 4:
|
2014-11-17 18:32:48 +01:00
|
|
|
synchronous = true;
|
|
|
|
break;
|
2017-10-29 08:16:55 +01:00
|
|
|
case 5:
|
|
|
|
do_sync = false;
|
|
|
|
break;
|
2011-10-26 20:13:33 +02:00
|
|
|
default:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* getopt_long already emitted a complaint
|
|
|
|
*/
|
|
|
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
|
|
|
progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Any non-option arguments?
|
|
|
|
*/
|
|
|
|
if (optind < argc)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
_("%s: too many command-line arguments (first is \"%s\")\n"),
|
|
|
|
progname, argv[optind]);
|
|
|
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
|
|
|
progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2015-05-19 05:01:48 +02:00
|
|
|
if (do_drop_slot && do_create_slot)
|
2014-10-06 12:51:37 +02:00
|
|
|
{
|
2015-05-19 05:01:48 +02:00
|
|
|
fprintf(stderr, _("%s: cannot use --create-slot together with --drop-slot\n"), progname);
|
2014-10-06 12:51:37 +02:00
|
|
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
|
|
|
progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2015-05-19 05:01:48 +02:00
|
|
|
if (replication_slot == NULL && (do_drop_slot || do_create_slot))
|
2014-10-06 12:51:37 +02:00
|
|
|
{
|
2015-05-19 05:01:48 +02:00
|
|
|
/* translator: second %s is an option name */
|
|
|
|
fprintf(stderr, _("%s: %s needs a slot to be specified using --slot\n"), progname,
|
|
|
|
do_drop_slot ? "--drop-slot" : "--create-slot");
|
2014-10-06 12:51:37 +02:00
|
|
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
|
|
|
progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2017-10-29 08:16:55 +01:00
|
|
|
if (synchronous && !do_sync)
|
|
|
|
{
|
|
|
|
fprintf(stderr, _("%s: cannot use --synchronous together with --no-sync\n"), progname);
|
|
|
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
|
|
|
progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2011-10-26 20:13:33 +02:00
|
|
|
/*
|
|
|
|
* Required arguments
|
|
|
|
*/
|
2015-08-10 13:28:18 +02:00
|
|
|
if (basedir == NULL && !do_drop_slot && !do_create_slot)
|
2011-10-26 20:13:33 +02:00
|
|
|
{
|
|
|
|
fprintf(stderr, _("%s: no target directory specified\n"), progname);
|
|
|
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
|
|
|
progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2017-01-17 12:10:26 +01:00
|
|
|
#ifndef HAVE_LIBZ
|
|
|
|
if (compresslevel != 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
_("%s: this build does not support compression\n"),
|
|
|
|
progname);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-10-06 12:51:37 +02:00
|
|
|
/*
|
|
|
|
* Check existence of destination folder.
|
|
|
|
*/
|
2015-08-10 13:28:18 +02:00
|
|
|
if (!do_drop_slot && !do_create_slot)
|
2014-10-06 12:51:37 +02:00
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
DIR *dir = get_destination_dir(basedir);
|
|
|
|
|
2014-10-06 12:51:37 +02:00
|
|
|
close_destination_dir(dir, basedir);
|
|
|
|
}
|
|
|
|
|
2011-10-26 20:13:33 +02:00
|
|
|
#ifndef WIN32
|
|
|
|
pqsignal(SIGINT, sigint_handler);
|
|
|
|
#endif
|
|
|
|
|
2014-10-06 12:51:37 +02:00
|
|
|
/*
|
|
|
|
* Obtain a connection before doing anything.
|
|
|
|
*/
|
|
|
|
conn = GetConnection();
|
|
|
|
if (!conn)
|
|
|
|
/* error message already written in GetConnection() */
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run IDENTIFY_SYSTEM to make sure we've successfully have established a
|
|
|
|
* replication connection and haven't connected using a database specific
|
|
|
|
* connection.
|
|
|
|
*/
|
|
|
|
if (!RunIdentifySystem(conn, NULL, NULL, NULL, &db_name))
|
|
|
|
disconnect_and_exit(1);
|
|
|
|
|
Make WAL segment size configurable at initdb time.
For performance reasons a larger segment size than the default 16MB
can be useful. A larger segment size has two main benefits: Firstly,
in setups using archiving, it makes it easier to write scripts that
can keep up with higher amounts of WAL, secondly, the WAL has to be
written and synced to disk less frequently.
But at the same time large segment size are disadvantageous for
smaller databases. So far the segment size had to be configured at
compile time, often making it unrealistic to choose one fitting to a
particularly load. Therefore change it to a initdb time setting.
This includes a breaking changes to the xlogreader.h API, which now
requires the current segment size to be configured. For that and
similar reasons a number of binaries had to be taught how to recognize
the current segment size.
Author: Beena Emerson, editorialized by Andres Freund
Reviewed-By: Andres Freund, David Steele, Kuntal Ghosh, Michael
Paquier, Peter Eisentraut, Robert Hass, Tushar Ahuja
Discussion: https://postgr.es/m/CAOG9ApEAcQ--1ieKbhFzXSQPw_YLmepaa4hNdnY5+ZULpt81Mw@mail.gmail.com
2017-09-20 07:03:48 +02:00
|
|
|
/* determine remote server's xlog segment size */
|
|
|
|
if (!RetrieveWalSegSize(conn))
|
|
|
|
disconnect_and_exit(1);
|
|
|
|
|
2014-10-06 12:51:37 +02:00
|
|
|
/*
|
2015-05-24 03:35:49 +02:00
|
|
|
* Check that there is a database associated with connection, none should
|
|
|
|
* be defined in this context.
|
2014-10-06 12:51:37 +02:00
|
|
|
*/
|
|
|
|
if (db_name)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
_("%s: replication connection using slot \"%s\" is unexpectedly database specific\n"),
|
|
|
|
progname, replication_slot);
|
|
|
|
disconnect_and_exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Drop a replication slot.
|
|
|
|
*/
|
|
|
|
if (do_drop_slot)
|
|
|
|
{
|
|
|
|
if (verbose)
|
|
|
|
fprintf(stderr,
|
|
|
|
_("%s: dropping replication slot \"%s\"\n"),
|
|
|
|
progname, replication_slot);
|
|
|
|
|
|
|
|
if (!DropReplicationSlot(conn, replication_slot))
|
|
|
|
disconnect_and_exit(1);
|
|
|
|
disconnect_and_exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a replication slot */
|
|
|
|
if (do_create_slot)
|
|
|
|
{
|
|
|
|
if (verbose)
|
|
|
|
fprintf(stderr,
|
|
|
|
_("%s: creating replication slot \"%s\"\n"),
|
|
|
|
progname, replication_slot);
|
|
|
|
|
2017-09-26 22:07:52 +02:00
|
|
|
if (!CreateReplicationSlot(conn, replication_slot, NULL, false, true, false,
|
2015-07-12 22:06:27 +02:00
|
|
|
slot_exists_ok))
|
2014-10-06 12:51:37 +02:00
|
|
|
disconnect_and_exit(1);
|
2015-08-10 13:28:18 +02:00
|
|
|
disconnect_and_exit(0);
|
2014-10-06 12:51:37 +02:00
|
|
|
}
|
|
|
|
|
2014-10-17 20:06:34 +02:00
|
|
|
/*
|
2015-05-24 03:35:49 +02:00
|
|
|
* Don't close the connection here so that subsequent StreamLog() can
|
|
|
|
* reuse it.
|
2014-10-17 20:06:34 +02:00
|
|
|
*/
|
|
|
|
|
2012-05-27 11:05:24 +02:00
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
StreamLog();
|
2017-09-11 22:30:50 +02:00
|
|
|
if (time_to_stop)
|
2012-07-31 16:11:11 +02:00
|
|
|
{
|
2012-05-27 11:05:24 +02:00
|
|
|
/*
|
2017-09-11 22:30:50 +02:00
|
|
|
* We've been Ctrl-C'ed or end of streaming position has been
|
|
|
|
* willingly reached, so exit without an error code.
|
2012-05-27 11:05:24 +02:00
|
|
|
*/
|
|
|
|
exit(0);
|
2012-07-31 16:11:11 +02:00
|
|
|
}
|
2012-05-27 11:05:24 +02:00
|
|
|
else if (noloop)
|
|
|
|
{
|
2012-12-19 13:01:11 +01:00
|
|
|
fprintf(stderr, _("%s: disconnected\n"), progname);
|
2012-05-27 11:05:24 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-07-31 16:11:11 +02:00
|
|
|
fprintf(stderr,
|
2013-05-29 22:58:43 +02:00
|
|
|
/* translator: check source for value for %d */
|
2012-12-19 13:01:11 +01:00
|
|
|
_("%s: disconnected; waiting %d seconds to try again\n"),
|
2012-05-27 11:05:24 +02:00
|
|
|
progname, RECONNECT_SLEEP_TIME);
|
|
|
|
pg_usleep(RECONNECT_SLEEP_TIME * 1000000);
|
|
|
|
}
|
|
|
|
}
|
2011-10-26 20:13:33 +02:00
|
|
|
}
|