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 1vncdl-009Z7U-2A for pgsql-hackers@arkaria.postgresql.org; Wed, 04 Feb 2026 13:09:53 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vncdk-00BJxi-1y for pgsql-hackers@arkaria.postgresql.org; Wed, 04 Feb 2026 13:09:52 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vncdk-00BJxY-0r for pgsql-hackers@lists.postgresql.org; Wed, 04 Feb 2026 13:09:52 +0000 Received: from mail-pj1-x1034.google.com ([2607:f8b0:4864:20::1034]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1vncdh-000000011sr-2U7m for pgsql-hackers@lists.postgresql.org; Wed, 04 Feb 2026 13:09:51 +0000 Received: by mail-pj1-x1034.google.com with SMTP id 98e67ed59e1d1-34c708702dfso3761511a91.1 for ; Wed, 04 Feb 2026 05:09:49 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1770210587; cv=none; d=google.com; s=arc-20240605; b=iaeJ51UZfzqgIoKYaVSZF6xage6hUdtmszwLY2au2DX3SEzX12+EioQZKRi66HEJTh 9Hbja+4/APaB4pjg+Kirv1eZ1qQROpomzJLKfxbbs6F58pGGJEzS6hsVz7VH3gEfCk6P C4X/jZPgA+E01Ka/nqjNTxH31SYBa6uRa/+8OoIDpuNgyc/0jT/0VlsaddJSM4RQw50X KEdpGSBpOSzLExSp+81QBd48l3p+vbfCMPoH2VYZXj974V/8nL2W6tnHRbBJ2K9Z2uiN //CUqipBrngW0X33wbDPG3lc7QqSSYHiaO5ubMmWueVcBbL+35Pq4EF/sv7L+nWtApzX JrCw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=o+4JQoS7yZDwgOUFh8icPsHy0fHbFrv+RHYeoaD6NZY=; fh=0gi7pH0cvR0sSGN5bi87gnBmWpwpyfJtGTYb5FSFLmg=; b=QBOhHVy4eD0urZfZ7UH2MUy6gm9mBsan1O0DgZTmfGAK0dUCXMd+xi+1X3U4hIhfLP hiptLBNE9PP+VkUxjig6U5nh708RxgQXK9ZDa5JfeqBB2Lf6ewFBOm5+2S1PYKIKU30k u8QO8j/KDrhZUafudimPavDOTR5pV0ZbKGkPC3UUkZXWd2TET/LxwXHsKXyqNscCKBm0 EWF0maX6HWRpPCILNqcAiz/nJp2b9DPCYJLLk0AwYrrirKOScwwDmLeUw6heEq82dnrv Z1NGl+XtBlJqA+BqPo4NF10pLLswJhQybLbYOHVuCBgODF18FA6HMcpBiuATFGvM0pRh R5eA==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770210587; x=1770815387; darn=lists.postgresql.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=o+4JQoS7yZDwgOUFh8icPsHy0fHbFrv+RHYeoaD6NZY=; b=a2pJcpZVd35cY2KrlWrNyDBcpyFEdr8i1y83GIyaVOLvIDIhQ2NFwWk1Cr7xdrjyKt k8542UGrzzbe8eyY5RCr0QAgOUf3ezpWnzFPscZaJVJfRCsdJWnI6iTXbLMS03NNI7WS 8Pw3ZIuPBNsX8nySHTfkojlK5AyYuNaRMkes8TLCtiudHyOjyifdr92Ljq0kdq+BLEQQ WQGBiEJczexJ+OU0zhTDjHh2WCGLccvTfiVFYh6ieBf5Y6smvn+wuAVfsB5oyGhhr6bD YUeiws+0MrgVuay+KhBXlsPHQMzsYZlCiLvq+2eN5jedgrkcoWHbiVHv2lSTjey6GV76 UItQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770210587; x=1770815387; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=o+4JQoS7yZDwgOUFh8icPsHy0fHbFrv+RHYeoaD6NZY=; b=FgVG2t0nm9FL5M6krlC5y960FnpjszrxEBnkAi0lAr7DJG/WcjiW9gYtT1URrrImPQ X0yFeNeet4KAJj3EyNZMlqABqNxdn1yLSIm47AqlAKiq44R7br721K5xDLNF7kCTNAtK 5B2yLQa8lOFdnugA907/TR5u48dlTEWyG0zgwAtE0Nm/jtlNMYlNxLg3xGS8wc/VG0pF DD8AYHj5Z6DS/iF+lV8p/FPReLfAojTZ/MmkY22AgC7A1n3Cw+pmACLnbMz3ZNNEjYvO 8+SSFfdY8B7vtPmQzWbb+qwbiQni2maMVx5mgXiayN/sW94K1rhVaX0/MJ1uMpZGpz+N qUPQ== X-Forwarded-Encrypted: i=1; AJvYcCWoknuQInofH7eW0zUdKAhjmUR6O1wM5B+ruthMiBt8u6r9FeIJhu7SB0WZXvsTv4ZEqKJzHUpO/gLdbwmt@lists.postgresql.org X-Gm-Message-State: AOJu0YwbKHXmdBNjoCB2+GuU8zoSqpqLlWJY8gz0gwXJVuynI3XAxEJK BIgTl8jqFO2WE7arqBnJkBBDCKQXjzAkp4jxTcGVRSBzfCT1ZoMmT/RjhHStPfB9JnMw+hL4AsN BeUmm/qYyrVZMehdU8GbAXe1+FXocPdY= X-Gm-Gg: AZuq6aIwxhNxC4XcZ+GZqYEySNhyA/hUkhlskCFm4pWwV/T+PZdNfQaEGu9blLS3L+y e1/PZEh/8CkKAw0pQyeAMd/GXaZ4sdUti9uGKZdjDDBClJkMUTLtmqPM9K6WMP2ppxFpspDmprV 7iuaXaex7FW9UKX1Sp0SfxHcr3yeZVFRitcVU5jb5LuFtzIm0nCEMXXfZH0TNyTw8vOO7EU7xAC FXNbsOl95iw7oNR4Un3igGtIHtpMhdkYmiUVh5/6KROo6ECU10ETI8pjpUlJGUppKIwcK0AMA== X-Received: by 2002:a17:90b:57c5:b0:353:38c8:b612 with SMTP id 98e67ed59e1d1-354870db3d6mr2588743a91.12.1770210587396; Wed, 04 Feb 2026 05:09:47 -0800 (PST) MIME-Version: 1.0 References: <731ADE6F-01C5-4996-BAEE-5851DFC3F502@gmail.com> In-Reply-To: From: Amul Sul Date: Wed, 4 Feb 2026 18:39:10 +0530 X-Gm-Features: AZwV_QiFBQIgTWJJITq-m6e5hI8kT_yk9I22nyDTV26EIBc0JqAepBeBOmwNIIQ Message-ID: Subject: Re: pg_waldump: support decoding of WAL inside tarfile To: Robert Haas Cc: Chao Li , Jakub Wartak , PostgreSQL Hackers Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Wed, Jan 28, 2026 at 2:41=E2=80=AFAM Robert Haas = wrote: > > On Tue, Jan 27, 2026 at 7:07=E2=80=AFAM Amul Sul wrot= e: > > In the attached version, I am using the WAL segment name as the hash > > key, which is much more straightforward. I have rewritten > > read_archive_wal_page(), and it looks much cleaner than before. The > > logic to discard irrelevant WAL files is still within > > get_archive_wal_entry. I added an explanation for setting cur_wal to > > NULL, which is now handled in the separate function I mentioned > > previously. > > > > Kindly have a look at the attached version; let me know if you are > > still not happy with the current approach for filtering/discarding > > irrelevant WAL segments. It isn't much different from the previous > > version, but I have tried to keep it in a separate routine for better > > code readability, with comments to make it easier to understand. I > > also added a comment for ArchivedWALFile. > > I feel like the division of labor between get_archive_wal_entry() and > read_archive_wal_page() is odd. I noticed this in the last version, > too, and it still seems to be the case. get_archive_wal_entry() first > calls ArchivedWAL_lookup(). If that finds an entry, it just returns. > If it doesn't, it loops until an entry for the requested file shows up > and then returns it. Then control returns to read_archive_wal_page() > which loops some more until we have all the data we need for the > requested file. But it seems odd to me to have two separate loops > here. I think that the first loop is going to call read_archive_file() > until we find the beginning of the file that we care about and then > the second one is going to call read_archive_file() some more until we > have read enough of it to satisfy the request. It feels odd to me to > do it that way, as if we told somebody to first wait until 9 o'clock > and then wait another 30 minutes, instead of just telling them to wait > until 9:30. I realize it's not quite the same thing, because apart > from calling read_archive_file(), the two loops do different things, > but I still think it looks odd. > > + /* > + * Ignore if the timeline is different or the current segment is not > + * the desired one. > + */ > + XLogFromFileName(entry->fname, &curSegTimeline, &curSegNo, WalSegSz); > + if (privateInfo->timeline !=3D curSegTimeline || > + privateInfo->startSegNo > curSegNo || > + privateInfo->endSegNo < curSegNo || > + segno > curSegNo) > + { > + free_archive_wal_entry(entry->fname, privateInfo); > + continue; > + } > > The comment doesn't match the code. If it did, the test would be > (privateInfo->timeline !=3D curSegTimeline || segno !=3D curSegno). But > instead the segno test is > rather than !=3D, and the checks against > startSegNo and endSegNo aren't explained at all. I think I understand > why the segno test uses > rather than !=3D, but it's the point of the > comment to explain things like that, rather than leaving the reader to > guess. And I don't know why we also need to test startSegNo and > endSegNo. > > I also wonder what the point is of doing XLogFromFileName() on the > fname provided by the caller and then again on entry->fname. Couldn't > you just compare the strings? > > Again, the division of labor is really odd here. It's the job of > astreamer_waldump_content() to skip things that aren't WAL files at > all, but it's the job of get_archive_wal_entry() to skip things that > are WAL files but not the one we want. I disagree with putting those > checks in completely separate parts of the code. > Keeping the timeline and segment start-end range checks inside the archive streamer creates a circular dependency that cannot be resolved without a 'dirty hack'. We must read the first available WAL file page to determine the wal_segment_size before it can calculate the target segment range. Moving the checks inside the streamer would make it impossible to process that initial file, as the necessary filtering parameters -- would still be unknown which would need to be skipped for the first read somehow. What if later we realized that the first WAL file which was allowed to be streamed by skipping that check is irrelevant and doesn't fall under the start-end segment range? > +static bool > +member_is_wal_file(astreamer_waldump *mystreamer, astreamer_member *memb= er, > + char **fname) > +{ > + int pathlen; > + char *filename; > + > + /* We are only interested in normal files. */ > + if (member->is_directory || member->is_link) > + return false; > + > + pathlen =3D strlen(member->pathname); > + if (pathlen < XLOG_FNAME_LEN) > + return false; > + > + /* WAL files from the top-level or pg_wal directory will be decoded */ > + if (pathlen > XLOG_FNAME_LEN && > + strncmp(member->pathname, XLOGDIR, strlen(XLOGDIR)) !=3D 0) > + return false; > + > + /* WAL file could be with full path */ > + filename =3D member->pathname + (pathlen - XLOG_FNAME_LEN); > + if (!IsXLogFileName(filename)) > + return false; > + > + *fname =3D pnstrdup(filename, XLOG_FNAME_LEN); > + > + return true; > +} > > I don't think this code is fully correct. Note that pg_verifybackup's > member_verify_header() prepends "./" and then applies > canonicalize_path(). I think the same considerations apply here. > Consider: > Understood, will fix that. Regards, Amul