Commit 6ed2d858 authored by Peter Eisentraut's avatar Peter Eisentraut

pg_basebackup: Add --nosync option

This is useful for testing, similar to initdb's --nosync.

From: Michael Paquier <michael.paquier@gmail.com>
parent bc34223b
...@@ -438,6 +438,21 @@ PostgreSQL documentation ...@@ -438,6 +438,21 @@ PostgreSQL documentation
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>-N</option></term>
<term><option>--nosync</option></term>
<listitem>
<para>
By default, <command>pg_basebackup</command> will wait for all files
to be written safely to disk. This option causes
<command>pg_basebackup</command> to return without waiting, which is
faster, but means that a subsequent operating system crash can leave
the base backup corrupt. Generally, this option is useful for testing
but should not be used when creating a production installation.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>-v</option></term> <term><option>-v</option></term>
<term><option>--verbose</option></term> <term><option>--verbose</option></term>
......
...@@ -69,6 +69,7 @@ static bool includewal = false; ...@@ -69,6 +69,7 @@ static bool includewal = false;
static bool streamwal = false; static bool streamwal = false;
static bool fastcheckpoint = false; static bool fastcheckpoint = false;
static bool writerecoveryconf = false; static bool writerecoveryconf = false;
static bool do_sync = true;
static int standby_message_timeout = 10 * 1000; /* 10 sec = default */ static int standby_message_timeout = 10 * 1000; /* 10 sec = default */
static pg_time_t last_progress_report = 0; static pg_time_t last_progress_report = 0;
static int32 maxrate = 0; /* no limit by default */ static int32 maxrate = 0; /* no limit by default */
...@@ -329,6 +330,7 @@ usage(void) ...@@ -329,6 +330,7 @@ usage(void)
" set fast or spread checkpointing\n")); " set fast or spread checkpointing\n"));
printf(_(" -l, --label=LABEL set backup label\n")); printf(_(" -l, --label=LABEL set backup label\n"));
printf(_(" -n, --noclean do not clean up after errors\n")); printf(_(" -n, --noclean do not clean up after errors\n"));
printf(_(" -N, --nosync do not wait for changes to be written safely to disk\n"));
printf(_(" -P, --progress show progress information\n")); printf(_(" -P, --progress show progress information\n"));
printf(_(" -v, --verbose output verbose messages\n")); printf(_(" -v, --verbose output verbose messages\n"));
printf(_(" -V, --version output version information, then exit\n")); printf(_(" -V, --version output version information, then exit\n"));
...@@ -460,6 +462,7 @@ LogStreamerMain(logstreamer_param *param) ...@@ -460,6 +462,7 @@ LogStreamerMain(logstreamer_param *param)
stream.stream_stop = reached_end_position; stream.stream_stop = reached_end_position;
stream.standby_message_timeout = standby_message_timeout; stream.standby_message_timeout = standby_message_timeout;
stream.synchronous = false; stream.synchronous = false;
stream.do_sync = do_sync;
stream.mark_done = true; stream.mark_done = true;
stream.basedir = param->xlogdir; stream.basedir = param->xlogdir;
stream.partial_suffix = NULL; stream.partial_suffix = NULL;
...@@ -1199,7 +1202,7 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum) ...@@ -1199,7 +1202,7 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
PQfreemem(copybuf); PQfreemem(copybuf);
/* sync the resulting tar file, errors are not considered fatal */ /* sync the resulting tar file, errors are not considered fatal */
if (strcmp(basedir, "-") != 0) if (do_sync && strcmp(basedir, "-") != 0)
(void) fsync_fname(filename, false, progname); (void) fsync_fname(filename, false, progname);
} }
...@@ -1967,6 +1970,8 @@ BaseBackup(void) ...@@ -1967,6 +1970,8 @@ BaseBackup(void)
* all the data of the base directory is synced, taking into account * all the data of the base directory is synced, taking into account
* all the tablespaces. Errors are not considered fatal. * all the tablespaces. Errors are not considered fatal.
*/ */
if (do_sync)
{
if (format == 't') if (format == 't')
{ {
if (strcmp(basedir, "-") != 0) if (strcmp(basedir, "-") != 0)
...@@ -1976,6 +1981,7 @@ BaseBackup(void) ...@@ -1976,6 +1981,7 @@ BaseBackup(void)
{ {
(void) fsync_pgdata(basedir, progname); (void) fsync_pgdata(basedir, progname);
} }
}
if (verbose) if (verbose)
fprintf(stderr, "%s: base backup completed\n", progname); fprintf(stderr, "%s: base backup completed\n", progname);
...@@ -2001,6 +2007,7 @@ main(int argc, char **argv) ...@@ -2001,6 +2007,7 @@ main(int argc, char **argv)
{"compress", required_argument, NULL, 'Z'}, {"compress", required_argument, NULL, 'Z'},
{"label", required_argument, NULL, 'l'}, {"label", required_argument, NULL, 'l'},
{"noclean", no_argument, NULL, 'n'}, {"noclean", no_argument, NULL, 'n'},
{"nosync", no_argument, NULL, 'N'},
{"dbname", required_argument, NULL, 'd'}, {"dbname", required_argument, NULL, 'd'},
{"host", required_argument, NULL, 'h'}, {"host", required_argument, NULL, 'h'},
{"port", required_argument, NULL, 'p'}, {"port", required_argument, NULL, 'p'},
...@@ -2037,7 +2044,7 @@ main(int argc, char **argv) ...@@ -2037,7 +2044,7 @@ main(int argc, char **argv)
atexit(cleanup_directories_atexit); atexit(cleanup_directories_atexit);
while ((c = getopt_long(argc, argv, "D:F:r:RT:xX:l:nzZ:d:c:h:p:U:s:S:wWvP", while ((c = getopt_long(argc, argv, "D:F:r:RT:xX:l:nNzZ:d:c:h:p:U:s:S:wWvP",
long_options, &option_index)) != -1) long_options, &option_index)) != -1)
{ {
switch (c) switch (c)
...@@ -2115,6 +2122,9 @@ main(int argc, char **argv) ...@@ -2115,6 +2122,9 @@ main(int argc, char **argv)
case 'n': case 'n':
noclean = true; noclean = true;
break; break;
case 'N':
do_sync = false;
break;
case 'z': case 'z':
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
compresslevel = Z_DEFAULT_COMPRESSION; compresslevel = Z_DEFAULT_COMPRESSION;
......
...@@ -336,6 +336,7 @@ StreamLog(void) ...@@ -336,6 +336,7 @@ StreamLog(void)
stream.stream_stop = stop_streaming; stream.stream_stop = stop_streaming;
stream.standby_message_timeout = standby_message_timeout; stream.standby_message_timeout = standby_message_timeout;
stream.synchronous = synchronous; stream.synchronous = synchronous;
stream.do_sync = true;
stream.mark_done = false; stream.mark_done = false;
stream.basedir = basedir; stream.basedir = basedir;
stream.partial_suffix = ".partial"; stream.partial_suffix = ".partial";
......
...@@ -41,8 +41,8 @@ static PGresult *HandleCopyStream(PGconn *conn, StreamCtl *stream, ...@@ -41,8 +41,8 @@ static PGresult *HandleCopyStream(PGconn *conn, StreamCtl *stream,
XLogRecPtr *stoppos); XLogRecPtr *stoppos);
static int CopyStreamPoll(PGconn *conn, long timeout_ms); static int CopyStreamPoll(PGconn *conn, long timeout_ms);
static int CopyStreamReceive(PGconn *conn, long timeout, char **buffer); static int CopyStreamReceive(PGconn *conn, long timeout, char **buffer);
static bool ProcessKeepaliveMsg(PGconn *conn, char *copybuf, int len, static bool ProcessKeepaliveMsg(PGconn *conn, StreamCtl *stream, char *copybuf,
XLogRecPtr blockpos, int64 *last_status); int len, XLogRecPtr blockpos, int64 *last_status);
static bool ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len, static bool ProcessXLogDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
XLogRecPtr *blockpos); XLogRecPtr *blockpos);
static PGresult *HandleEndOfCopyStream(PGconn *conn, StreamCtl *stream, char *copybuf, static PGresult *HandleEndOfCopyStream(PGconn *conn, StreamCtl *stream, char *copybuf,
...@@ -56,7 +56,7 @@ static bool ReadEndOfStreamingResult(PGresult *res, XLogRecPtr *startpos, ...@@ -56,7 +56,7 @@ static bool ReadEndOfStreamingResult(PGresult *res, XLogRecPtr *startpos,
uint32 *timeline); uint32 *timeline);
static bool static bool
mark_file_as_archived(const char *basedir, const char *fname) mark_file_as_archived(const char *basedir, const char *fname, bool do_sync)
{ {
int fd; int fd;
static char tmppath[MAXPGPATH]; static char tmppath[MAXPGPATH];
...@@ -74,10 +74,10 @@ mark_file_as_archived(const char *basedir, const char *fname) ...@@ -74,10 +74,10 @@ mark_file_as_archived(const char *basedir, const char *fname)
close(fd); close(fd);
if (fsync_fname(tmppath, false, progname) != 0) if (do_sync && fsync_fname(tmppath, false, progname) != 0)
return false; return false;
if (fsync_parent_path(tmppath, progname) != 0) if (do_sync && fsync_parent_path(tmppath, progname) != 0)
return false; return false;
return true; return true;
...@@ -134,9 +134,9 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint) ...@@ -134,9 +134,9 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint)
* fsync, in case of a previous crash between padding and fsyncing the * fsync, in case of a previous crash between padding and fsyncing the
* file. * file.
*/ */
if (fsync_fname(fn, false, progname) != 0) if (stream->do_sync && fsync_fname(fn, false, progname) != 0)
return false; return false;
if (fsync_parent_path(fn, progname) != 0) if (stream->do_sync && fsync_parent_path(fn, progname) != 0)
return false; return false;
return true; return true;
...@@ -173,9 +173,9 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint) ...@@ -173,9 +173,9 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint)
* using synchronous mode, where the file is modified and fsynced * using synchronous mode, where the file is modified and fsynced
* in-place, without a directory fsync. * in-place, without a directory fsync.
*/ */
if (fsync_fname(fn, false, progname) != 0) if (stream->do_sync && fsync_fname(fn, false, progname) != 0)
return false; return false;
if (fsync_parent_path(fn, progname) != 0) if (stream->do_sync && fsync_parent_path(fn, progname) != 0)
return false; return false;
if (lseek(f, SEEK_SET, 0) != 0) if (lseek(f, SEEK_SET, 0) != 0)
...@@ -212,7 +212,7 @@ close_walfile(StreamCtl *stream, XLogRecPtr pos) ...@@ -212,7 +212,7 @@ close_walfile(StreamCtl *stream, XLogRecPtr pos)
return false; return false;
} }
if (fsync(walfile) != 0) if (stream->do_sync && fsync(walfile) != 0)
{ {
fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"), fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"),
progname, current_walfile_name, strerror(errno)); progname, current_walfile_name, strerror(errno));
...@@ -258,7 +258,8 @@ close_walfile(StreamCtl *stream, XLogRecPtr pos) ...@@ -258,7 +258,8 @@ close_walfile(StreamCtl *stream, XLogRecPtr pos)
if (currpos == XLOG_SEG_SIZE && stream->mark_done) if (currpos == XLOG_SEG_SIZE && stream->mark_done)
{ {
/* writes error message if failed */ /* writes error message if failed */
if (!mark_file_as_archived(stream->basedir, current_walfile_name)) if (!mark_file_as_archived(stream->basedir, current_walfile_name,
stream->do_sync))
return false; return false;
} }
...@@ -378,7 +379,8 @@ writeTimeLineHistoryFile(StreamCtl *stream, char *filename, char *content) ...@@ -378,7 +379,8 @@ writeTimeLineHistoryFile(StreamCtl *stream, char *filename, char *content)
if (stream->mark_done) if (stream->mark_done)
{ {
/* writes error message if failed */ /* writes error message if failed */
if (!mark_file_as_archived(stream->basedir, histfname)) if (!mark_file_as_archived(stream->basedir, histfname,
stream->do_sync))
return false; return false;
} }
...@@ -836,7 +838,7 @@ HandleCopyStream(PGconn *conn, StreamCtl *stream, ...@@ -836,7 +838,7 @@ HandleCopyStream(PGconn *conn, StreamCtl *stream,
*/ */
if (stream->synchronous && lastFlushPosition < blockpos && walfile != -1) if (stream->synchronous && lastFlushPosition < blockpos && walfile != -1)
{ {
if (fsync(walfile) != 0) if (stream->do_sync && fsync(walfile) != 0)
{ {
fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"), fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"),
progname, current_walfile_name, strerror(errno)); progname, current_walfile_name, strerror(errno));
...@@ -890,7 +892,7 @@ HandleCopyStream(PGconn *conn, StreamCtl *stream, ...@@ -890,7 +892,7 @@ HandleCopyStream(PGconn *conn, StreamCtl *stream,
/* Check the message type. */ /* Check the message type. */
if (copybuf[0] == 'k') if (copybuf[0] == 'k')
{ {
if (!ProcessKeepaliveMsg(conn, copybuf, r, blockpos, if (!ProcessKeepaliveMsg(conn, stream, copybuf, r, blockpos,
&last_status)) &last_status))
goto error; goto error;
} }
...@@ -1043,7 +1045,7 @@ CopyStreamReceive(PGconn *conn, long timeout, char **buffer) ...@@ -1043,7 +1045,7 @@ CopyStreamReceive(PGconn *conn, long timeout, char **buffer)
* Process the keepalive message. * Process the keepalive message.
*/ */
static bool static bool
ProcessKeepaliveMsg(PGconn *conn, char *copybuf, int len, ProcessKeepaliveMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
XLogRecPtr blockpos, int64 *last_status) XLogRecPtr blockpos, int64 *last_status)
{ {
int pos; int pos;
...@@ -1079,7 +1081,7 @@ ProcessKeepaliveMsg(PGconn *conn, char *copybuf, int len, ...@@ -1079,7 +1081,7 @@ ProcessKeepaliveMsg(PGconn *conn, char *copybuf, int len,
* data has been successfully replicated or not, at the normal * data has been successfully replicated or not, at the normal
* shutdown of the server. * shutdown of the server.
*/ */
if (fsync(walfile) != 0) if (stream->do_sync && fsync(walfile) != 0)
{ {
fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"), fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"),
progname, current_walfile_name, strerror(errno)); progname, current_walfile_name, strerror(errno));
......
...@@ -34,8 +34,10 @@ typedef struct StreamCtl ...@@ -34,8 +34,10 @@ typedef struct StreamCtl
* timeline */ * timeline */
int standby_message_timeout; /* Send status messages this int standby_message_timeout; /* Send status messages this
* often */ * often */
bool synchronous; /* Flush data on write */ bool synchronous; /* Flush immediately WAL data on write */
bool mark_done; /* Mark segment as done in generated archive */ bool mark_done; /* Mark segment as done in generated archive */
bool do_sync; /* Flush to disk to ensure consistent state
* of data */
stream_stop_callback stream_stop; /* Stop streaming when returns true */ stream_stop_callback stream_stop; /* Stop streaming when returns true */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment