diff options
author | Andres Freund <andres@anarazel.de> | 2015-01-03 20:51:52 +0100 |
---|---|---|
committer | Andres Freund <andres@anarazel.de> | 2015-01-03 20:54:12 +0100 |
commit | 2c0a4858965f1375dadb45df9f3a054bfcb283f5 (patch) | |
tree | 554010c06211d68cfe87377cc599385c29355019 /src/bin/pg_basebackup/pg_basebackup.c | |
parent | ccb161b66addc9d0ede31359c05f7e9df61ab8d4 (diff) | |
download | postgresql-2c0a4858965f1375dadb45df9f3a054bfcb283f5.tar.gz |
Prevent WAL files created by pg_basebackup -x/X from being archived again.
WAL (and timeline history) files created by pg_basebackup did not
maintain the new base backup's archive status. That's currently not a
problem if the new node is used as a standby - but if that node is
promoted all still existing files can get archived again. With a high
wal_keep_segment settings that can happen a significant time later -
which is quite confusing.
Change both the backend (for the -x/-X fetch case) and pg_basebackup
(for -X stream) itself to always mark WAL/timeline files included in
the base backup as .done. That's in line with walreceiver.c doing so.
The verbosity of the pg_basebackup changes show pretty clearly that it
needs some refactoring, but that'd result in not be backpatchable
changes.
Backpatch to 9.1 where pg_basebackup was introduced.
Discussion: 20141205002854.GE21964@awork2.anarazel.de
Diffstat (limited to 'src/bin/pg_basebackup/pg_basebackup.c')
-rw-r--r-- | src/bin/pg_basebackup/pg_basebackup.c | 33 |
1 files changed, 23 insertions, 10 deletions
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c index 0470401aea..ed2f3021d0 100644 --- a/src/bin/pg_basebackup/pg_basebackup.c +++ b/src/bin/pg_basebackup/pg_basebackup.c @@ -25,6 +25,7 @@ #include <zlib.h> #endif +#include "common/string.h" #include "getopt_long.h" #include "libpq-fe.h" #include "pqexpbuffer.h" @@ -370,7 +371,7 @@ LogStreamerMain(logstreamer_param *param) if (!ReceiveXlogStream(param->bgconn, param->startptr, param->timeline, param->sysidentifier, param->xlogdir, reached_end_position, standby_message_timeout, - NULL, false)) + NULL, false, true)) /* * Any errors will already have been reported in the function process, @@ -394,6 +395,7 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier) logstreamer_param *param; uint32 hi, lo; + char statusdir[MAXPGPATH]; param = pg_malloc0(sizeof(logstreamer_param)); param->timeline = timeline; @@ -428,13 +430,23 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier) /* Error message already written in GetConnection() */ exit(1); + snprintf(param->xlogdir, sizeof(param->xlogdir), "%s/pg_xlog", basedir); + /* - * Always in plain format, so we can write to basedir/pg_xlog. But the - * directory entry in the tar file may arrive later, so make sure it's - * created before we start. + * Create pg_xlog/archive_status (and thus pg_xlog) so we can can write to + * basedir/pg_xlog as the directory entry in the tar file may arrive + * later. */ - snprintf(param->xlogdir, sizeof(param->xlogdir), "%s/pg_xlog", basedir); - verify_dir_is_empty_or_create(param->xlogdir); + snprintf(statusdir, sizeof(statusdir), "%s/pg_xlog/archive_status", + basedir); + + if (pg_mkdir_p(statusdir, S_IRWXU) != 0 && errno != EEXIST) + { + fprintf(stderr, + _("%s: could not create directory \"%s\": %s\n"), + progname, statusdir, strerror(errno)); + disconnect_and_exit(1); + } /* * Start a child process and tell it to start streaming. On Unix, this is @@ -1236,11 +1248,12 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum) * by the wal receiver process. Also, when transaction * log directory location was specified, pg_xlog has * already been created as a symbolic link before - * starting the actual backup. So just ignore failure - * on them. + * starting the actual backup. So just ignore creation + * failures on related directories. */ - if ((!streamwal && (strcmp(xlog_dir, "") == 0)) - || strcmp(filename + strlen(filename) - 8, "/pg_xlog") != 0) + if (!((pg_str_endswith(filename, "/pg_xlog") || + pg_str_endswith(filename, "/archive_status")) && + errno == EEXIST)) { fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"), |