aboutsummaryrefslogtreecommitdiff
path: root/src/bin/pg_basebackup/pg_basebackup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/pg_basebackup/pg_basebackup.c')
-rw-r--r--src/bin/pg_basebackup/pg_basebackup.c136
1 files changed, 120 insertions, 16 deletions
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 221cc4caf23..72c27c78d05 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -111,6 +111,16 @@ typedef enum
STREAM_WAL
} IncludeWal;
+/*
+ * Different places to perform compression
+ */
+typedef enum
+{
+ COMPRESS_LOCATION_UNSPECIFIED,
+ COMPRESS_LOCATION_CLIENT,
+ COMPRESS_LOCATION_SERVER
+} CompressionLocation;
+
/* Global options */
static char *basedir = NULL;
static TablespaceList tablespace_dirs = {NULL, NULL};
@@ -124,6 +134,7 @@ static bool estimatesize = true;
static int verbose = 0;
static int compresslevel = 0;
static WalCompressionMethod compressmethod = COMPRESSION_NONE;
+static CompressionLocation compressloc = COMPRESS_LOCATION_UNSPECIFIED;
static IncludeWal includewal = STREAM_WAL;
static bool fastcheckpoint = false;
static bool writerecoveryconf = false;
@@ -544,6 +555,11 @@ LogStreamerMain(logstreamer_param *param)
stream.walmethod = CreateWalDirectoryMethod(param->xlog,
COMPRESSION_NONE, 0,
stream.do_sync);
+ else if (compressloc != COMPRESS_LOCATION_CLIENT)
+ stream.walmethod = CreateWalTarMethod(param->xlog,
+ COMPRESSION_NONE,
+ compresslevel,
+ stream.do_sync);
else
stream.walmethod = CreateWalTarMethod(param->xlog,
compressmethod,
@@ -944,7 +960,7 @@ parse_max_rate(char *src)
*/
static void
parse_compress_options(char *src, WalCompressionMethod *methodres,
- int *levelres)
+ CompressionLocation *locationres, int *levelres)
{
char *sep;
int firstlen;
@@ -967,9 +983,25 @@ parse_compress_options(char *src, WalCompressionMethod *methodres,
* compression method.
*/
if (pg_strcasecmp(firstpart, "gzip") == 0)
+ {
+ *methodres = COMPRESSION_GZIP;
+ *locationres = COMPRESS_LOCATION_UNSPECIFIED;
+ }
+ else if (pg_strcasecmp(firstpart, "client-gzip") == 0)
+ {
+ *methodres = COMPRESSION_GZIP;
+ *locationres = COMPRESS_LOCATION_CLIENT;
+ }
+ else if (pg_strcasecmp(firstpart, "server-gzip") == 0)
+ {
*methodres = COMPRESSION_GZIP;
+ *locationres = COMPRESS_LOCATION_SERVER;
+ }
else if (pg_strcasecmp(firstpart, "none") == 0)
+ {
*methodres = COMPRESSION_NONE;
+ *locationres = COMPRESS_LOCATION_UNSPECIFIED;
+ }
else
{
/*
@@ -983,6 +1015,7 @@ parse_compress_options(char *src, WalCompressionMethod *methodres,
*methodres = (*levelres > 0) ?
COMPRESSION_GZIP : COMPRESSION_NONE;
+ *locationres = COMPRESS_LOCATION_UNSPECIFIED;
free(firstpart);
return;
@@ -1080,7 +1113,9 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
bbstreamer *streamer = NULL;
bbstreamer *manifest_inject_streamer = NULL;
bool inject_manifest;
+ bool is_tar;
bool must_parse_archive;
+ int archive_name_len = strlen(archive_name);
/*
* Normally, we emit the backup manifest as a separate file, but when
@@ -1089,13 +1124,32 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
*/
inject_manifest = (format == 't' && strcmp(basedir, "-") == 0 && manifest);
+ /* Is this a tar archive? */
+ is_tar = (archive_name_len > 4 &&
+ strcmp(archive_name + archive_name_len - 4, ".tar") == 0);
+
/*
* We have to parse the archive if (1) we're suppose to extract it, or if
* (2) we need to inject backup_manifest or recovery configuration into it.
+ * However, we only know how to parse tar archives.
*/
must_parse_archive = (format == 'p' || inject_manifest ||
(spclocation == NULL && writerecoveryconf));
+ /* At present, we only know how to parse tar archives. */
+ if (must_parse_archive && !is_tar)
+ {
+ pg_log_error("unable to parse archive: %s", archive_name);
+ pg_log_info("only tar archives can be parsed");
+ if (format == 'p')
+ pg_log_info("plain format requires pg_basebackup to parse the archive");
+ if (inject_manifest)
+ pg_log_info("using - as the output directory requires pg_basebackup to parse the archive");
+ if (writerecoveryconf)
+ pg_log_info("the -R option requires pg_basebackup to parse the archive");
+ exit(1);
+ }
+
if (format == 'p')
{
const char *directory;
@@ -1136,7 +1190,8 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
archive_file = NULL;
}
- if (compressmethod == COMPRESSION_NONE)
+ if (compressmethod == COMPRESSION_NONE ||
+ compressloc != COMPRESS_LOCATION_CLIENT)
streamer = bbstreamer_plain_writer_new(archive_filename,
archive_file);
#ifdef HAVE_LIBZ
@@ -1838,6 +1893,31 @@ BaseBackup(void)
AppendStringCommandOption(&buf, use_new_option_syntax,
"TARGET", "client");
+ if (compressloc == COMPRESS_LOCATION_SERVER)
+ {
+ char *compressmethodstr = NULL;
+
+ if (!use_new_option_syntax)
+ {
+ pg_log_error("server does not support server-side compression");
+ exit(1);
+ }
+ switch (compressmethod)
+ {
+ case COMPRESSION_GZIP:
+ compressmethodstr = "gzip";
+ break;
+ default:
+ Assert(false);
+ break;
+ }
+ AppendStringCommandOption(&buf, use_new_option_syntax,
+ "COMPRESSION", compressmethodstr);
+ if (compresslevel != 0)
+ AppendIntegerCommandOption(&buf, use_new_option_syntax,
+ "COMPRESSION_LEVEL", compresslevel);
+ }
+
if (verbose)
pg_log_info("initiating base backup, waiting for checkpoint to complete");
@@ -2376,10 +2456,11 @@ main(int argc, char **argv)
compresslevel = 1; /* will be rejected below */
#endif
compressmethod = COMPRESSION_GZIP;
+ compressloc = COMPRESS_LOCATION_UNSPECIFIED;
break;
case 'Z':
parse_compress_options(optarg, &compressmethod,
- &compresslevel);
+ &compressloc, &compresslevel);
break;
case 'c':
if (pg_strcasecmp(optarg, "fast") == 0)
@@ -2506,14 +2587,37 @@ main(int argc, char **argv)
}
/*
- * Compression doesn't make sense unless tar format is in use.
+ * If we're compressing the backup and the user has not said where to
+ * perform the compression, do it on the client, unless they specified
+ * --target, in which case the server is the only choice.
*/
- if (format == 'p' && compressmethod != COMPRESSION_NONE)
+ if (compressmethod != COMPRESSION_NONE &&
+ compressloc == COMPRESS_LOCATION_UNSPECIFIED)
{
if (backup_target == NULL)
- pg_log_error("only tar mode backups can be compressed");
+ compressloc = COMPRESS_LOCATION_CLIENT;
else
- pg_log_error("client-side compression is not possible when a backup target is specfied");
+ compressloc = COMPRESS_LOCATION_SERVER;
+ }
+
+ /*
+ * Can't perform client-side compression if the backup is not being
+ * sent to the client.
+ */
+ if (backup_target != NULL && compressloc == COMPRESS_LOCATION_CLIENT)
+ {
+ pg_log_error("client-side compression is not possible when a backup target is specified");
+ fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+ progname);
+ exit(1);
+ }
+
+ /*
+ * Compression doesn't make sense unless tar format is in use.
+ */
+ if (format == 'p' && compressloc == COMPRESS_LOCATION_CLIENT)
+ {
+ pg_log_error("only tar mode backups can be compressed");
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
progname);
exit(1);
@@ -2626,23 +2730,23 @@ main(int argc, char **argv)
}
break;
case COMPRESSION_GZIP:
-#ifdef HAVE_LIBZ
- if (compresslevel == 0)
- {
- pg_log_info("no value specified for compression level, switching to default");
- compresslevel = Z_DEFAULT_COMPRESSION;
- }
if (compresslevel > 9)
{
pg_log_error("compression level %d of method %s higher than maximum of 9",
compresslevel, "gzip");
exit(1);
}
+ if (compressloc == COMPRESS_LOCATION_CLIENT)
+ {
+#ifdef HAVE_LIBZ
+ if (compresslevel == 0)
+ compresslevel = Z_DEFAULT_COMPRESSION;
#else
- pg_log_error("this build does not support compression with %s",
- "gzip");
- exit(1);
+ pg_log_error("this build does not support compression with %s",
+ "gzip");
+ exit(1);
#endif
+ }
break;
case COMPRESSION_LZ4:
/* option not supported */