Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w3nKx-001YOT-1w for pgsql-hackers@arkaria.postgresql.org; Sat, 21 Mar 2026 03:49:19 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1w3nKv-008njM-0M for pgsql-hackers@arkaria.postgresql.org; Sat, 21 Mar 2026 03:49:17 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w3nKu-008njD-2D for pgsql-hackers@lists.postgresql.org; Sat, 21 Mar 2026 03:49:17 +0000 Received: from sss.pgh.pa.us ([68.162.161.243]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1w3nKs-00000000Gel-3rwX for pgsql-hackers@lists.postgresql.org; Sat, 21 Mar 2026 03:49:16 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.15.2/8.15.2) with ESMTP id 62L3n26Z2178518; Fri, 20 Mar 2026 23:49:02 -0400 From: Tom Lane To: Andrew Dunstan cc: Amul Sul , Zsolt Parragi , Robert Haas , Chao Li , Jakub Wartak , PostgreSQL Hackers Subject: Re: pg_waldump: support decoding of WAL inside tarfile In-reply-to: <9a2be101-42c9-40dd-9860-aa12f06bf0e0@dunslane.net> References: <72973471-8946-40c7-8b2d-8f95540d90e2@dunslane.net> <401bf08a-c8f1-48e2-9a30-78deaa9fa7c5@dunslane.net> <9a2be101-! 42c9-40dd-9860-aa12f06bf0e0@dunslane.net> Comments: In-reply-to Andrew Dunstan message dated "Fri, 20 Mar 2026 15:33:18 -0400" MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <2178516.1774064942.1@sss.pgh.pa.us> Content-Transfer-Encoding: quoted-printable Date: Fri, 20 Mar 2026 23:49:02 -0400 Message-ID: <2178517.1774064942@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Andrew Dunstan writes: > Thanks, committed with very minor tweaks. Buildfarm members batta and hachi don't like this very much. They fail the pg_verifybackup tests like so: # Running: pg_verifybackup --exit-on-error /home/admin/batta/buildroot/HEA= D/pgsql.build/src/bin/pg_verifybackup/tmp_check/t_008_untar_primary_data/b= ackup/server-backup pg_waldump: error: could not find WAL in archive "base.tar.zst" pg_verifybackup: error: WAL parsing failed for timeline 1 Only the zstd-compression case fails. I've spent several hours trying to reproduce this, without any luck, although I can get a similar failure in only the gzip case if I build with --with-wal-blocksize=3D64. I do not have an explanation for the seeming cross-platform difference. However after adding a lot of debug tracing, I believe I see the bug, or at least a related bug. This bit in archive_waldump.c's init_archive_reader is where the error comes from: /* * Read until we have at least one full WAL page (XLOG_BLCKSZ bytes) f= rom * the first WAL segment in the archive so we can extract the WAL segm= ent * size from the long page header. */ while (entry =3D=3D NULL || entry->buf->len < XLOG_BLCKSZ) { if (read_archive_file(privateInfo, XLOG_BLCKSZ) =3D=3D 0) pg_fatal("could not find WAL in archive \"%s\"", privateInfo->archive_name); entry =3D privateInfo->cur_file; } That looks plausible but is in fact utterly broken when there's not a lot of WAL data in the archive, as there is not in this test case. There are at least two problems: 1. read_archive_file reads some data from the source WAL archive and shoves it into the astreamer decompression pipeline. However, once it runs out of source data, it just returns zero and we fail immediately. This does not account for the possibility --- nay, certainty --- that there is data queued inside the decompression pipeline. So this doesn't work if the data we need has been compressed into less than XLOG_BLCKSZ worth of compressed data. (I suppose that the seeming cross-platform differences have to do with the effectiveness of the compression algorithm, but I don't really understand why it'd not be the same everywhere.) We need to do astreamer_finalize once we run out of source data. I think the cleanest place to handle that would be inside read_archive_file, but its return convention will need some rework if we want to put it there (because rc =3D=3D 0 shouldn't cause an immediate failure if we were able to finalize some more data). As an ugly experiment I put an astreamer_finalize call into the rc =3D=3D 0 path of the above loop, but it still didn't work, because: 2. If the decompression pipeline reaches the end of the WAL file that we want, the ASTREAMER_MEMBER_TRAILER case in astreamer_waldump_content instantly resets privateInfo->cur_file to NULL. Then the loop in init_archive_reader cannot exit successfully, and it will just read till the end of the archive and fail. I see that of the three callers of read_archive_file, only get_archive_wal_entry is aware of this possibility; but init_archive_reader certainly needs to deal with it and I bet read_archive_wal_page does too. Moreover, get_archive_wal_entry's solution looks to me like a fragile kluge that probably doesn't work reliably either, the reason being that privateInfo->cur_file can change multiple times during a single call to read_archive_file, if the WAL data has been compressed sufficiently. That whole API seems to need some rethinking, not to mention better documentation than the zero it has now. While I'm bitching: this error message "could not find WAL in archive \"%s\"" seems to me to be completely misleading and off-point. regards, tom lane