From 39c2969eb0e504d20ab9fd418775d36f1ff3045b Mon Sep 17 00:00:00 2001 From: Daniel Gustafsson Date: Thu, 8 Oct 2026 21:54:44 +0200 Subject: [PATCH] Handle concatenated gzip members in astreamer decompressor With WAL streaming, pg_basebackup -Ft -z writes pg_wal.tar.gz as a series of gzip members. The decompressor did not reset the inflate state when one ended, so inflate consumed nothing more and the loop never finished. This caused pg_waldump to hang on such backups and as a consequence pg_verifybackup (which use pg_waldump) would hang. A test is added to pg_verifybackup for checking a gzip-compressed tar backup, which in turn will verify that pg_waldump works. Author: Shihao Zhong Reviewed-by: Daniel Gustafsson Reviewed-by: Chao Li Reviewed-by: Andrew Dunstan Discussion: https://postgr.es/m/CAGRkXqTcyuog_MzKqQm+am2xMefLFJTSKaRevnfypDWirCFvdA@mail.gmail.com Backpatch-through: 19 --- src/bin/pg_verifybackup/t/007_wal.pl | 22 ++++++++++++++++++++++ src/fe_utils/astreamer_gzip.c | 8 ++++++++ 2 files changed, 30 insertions(+) diff --git a/src/bin/pg_verifybackup/t/007_wal.pl b/src/bin/pg_verifybackup/t/007_wal.pl index 12ca30139c5..10da5ca5041 100644 --- a/src/bin/pg_verifybackup/t/007_wal.pl +++ b/src/bin/pg_verifybackup/t/007_wal.pl @@ -105,4 +105,26 @@ $primary->command_ok( command_ok([ 'pg_verifybackup', $backup_path3 ], 'WAL verification succeeds with separate pg_wal.tar'); +# Same with client-side gzip compression. pg_basebackup writes pg_wal.tar.gz +# as several concatenated gzip members. +SKIP: +{ + skip "gzip compression not supported by this build", 2 + if !check_pg_config("#define HAVE_LIBZ 1"); + + my $backup_path4 = $primary->backup_dir . '/test_tar_gz_wal'; + $primary->command_ok( + [ + 'pg_basebackup', + '--pgdata' => $backup_path4, + '--no-sync', + '--format' => 'tar', + '--gzip', + '--checkpoint' => 'fast' + ], + "tar backup with separate pg_wal.tar.gz"); + command_ok([ 'pg_verifybackup', $backup_path4 ], + 'WAL verification succeeds with separate pg_wal.tar.gz'); +} + done_testing(); diff --git a/src/fe_utils/astreamer_gzip.c b/src/fe_utils/astreamer_gzip.c index bc3d53076e1..5fdf0e27872 100644 --- a/src/fe_utils/astreamer_gzip.c +++ b/src/fe_utils/astreamer_gzip.c @@ -333,6 +333,14 @@ astreamer_gzip_decompressor_content(astreamer *streamer, mystreamer->base.bbs_buffer.maxlen, context); mystreamer->bytes_written = 0; } + + /* + * The input can be several gzip members one after another, which is + * what pg_basebackup writes for pg_wal.tar.gz. Get ready for the + * next one. + */ + if (res == Z_STREAM_END && inflateReset(zs) != Z_OK) + pg_fatal("could not reset compression stream"); } }