pg_basebackup: Avoid unclean failure with server-compression and -D -.

Fail with a suitable error message instead. We can't inject the backup
manifest into the output tarfile without decompressing it, and if
we did that, we'd have to recompress the tarfile afterwards to produce
the result the user is expecting. While we have enough infrastructure
in pg_basebackup now to accomplish that whole series of steps without
much additional code, it seems like excessively surprising behavior.
The user probably did not select server-side compression with the idea
that the client was going to end up decompressing it and then
recompressing.

Report from Justin Pryzby. Fix by me.

Discussion: http://postgr.es/m/CA+Tgmob6Rnjz-Qv32h3yJn8nnUkLhrtQDAS4y5AtsgtorAFHRA@mail.gmail.com
This commit is contained in:
Robert Haas 2022-03-11 12:22:02 -05:00
parent e94bb1473e
commit b2de45f920
1 changed files with 21 additions and 3 deletions

View File

@ -1208,7 +1208,8 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
bool is_tar,
is_tar_gz,
is_tar_lz4,
is_tar_zstd;
is_tar_zstd,
is_compressed_tar;
bool must_parse_archive;
int archive_name_len = strlen(archive_name);
@ -1235,6 +1236,24 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
is_tar_zstd = (archive_name_len > 8 &&
strcmp(archive_name + archive_name_len - 4, ".zst") == 0);
/* Is this any kind of compressed tar? */
is_compressed_tar = is_tar_gz || is_tar_lz4 || is_tar_zstd;
/*
* Injecting the manifest into a compressed tar file would be possible if
* we decompressed it, parsed the tarfile, generated a new tarfile, and
* recompressed it, but compressing and decompressing multiple times just
* to inject the manifest seems inefficient enough that it's probably not
* what the user wants. So, instead, reject the request and tell the user
* to specify something more reasonable.
*/
if (inject_manifest && is_compressed_tar)
{
pg_log_error("cannot inject manifest into a compressed tarfile");
pg_log_info("use client-side compression, send the output to a directory rather than standard output, or use --no-manifest");
exit(1);
}
/*
* 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.
@ -1244,8 +1263,7 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
(spclocation == NULL && writerecoveryconf));
/* At present, we only know how to parse tar archives. */
if (must_parse_archive && !is_tar && !is_tar_gz && !is_tar_lz4
&& !is_tar_zstd)
if (must_parse_archive && !is_tar && !is_compressed_tar)
{
pg_log_error("unable to parse archive: %s", archive_name);
pg_log_info("only tar archives can be parsed");