From: Andrew Dunstan Date: Fri, 20 Mar 2026 19:31:35 +0000 (-0400) Subject: pg_waldump: Preparatory refactoring for tar archive WAL decoding. X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f8a0cd26717063b99d846b693b416187ab56d67b;p=thirdparty%2Fpostgresql.git pg_waldump: Preparatory refactoring for tar archive WAL decoding. Several refactoring steps in preparation for adding tar archive WAL decoding support to pg_waldump: - Move XLogDumpPrivate and related declarations into a new pg_waldump.h header, allowing a second source file to share them. - Factor out required_read_len() so the read-size calculation can be reused for both regular WAL files and tar-archived WAL. - Move the WAL segment size variable into XLogDumpPrivate and rename it to segsize, making it accessible to the archive streamer code. Author: Amul Sul Reviewed-by: Robert Haas Reviewed-by: Jakub Wartak Reviewed-by: Chao Li Reviewed-by: Euler Taveira Reviewed-by: Andrew Dunstan discussion: https://postgr.es/m/CAAJ_b94bqdWN3h2J-PzzzQ2Npbwct5ZQHggn_QoYGhC2rn-=WQ@mail.gmail.com --- diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c index f3446385d6a..5d31b15dbd8 100644 --- a/src/bin/pg_waldump/pg_waldump.c +++ b/src/bin/pg_waldump/pg_waldump.c @@ -29,6 +29,7 @@ #include "common/logging.h" #include "common/relpath.h" #include "getopt_long.h" +#include "pg_waldump.h" #include "rmgrdesc.h" #include "storage/bufpage.h" @@ -43,14 +44,6 @@ static volatile sig_atomic_t time_to_stop = false; static const RelFileLocator emptyRelFileLocator = {0, 0, 0}; -typedef struct XLogDumpPrivate -{ - TimeLineID timeline; - XLogRecPtr startptr; - XLogRecPtr endptr; - bool endptr_reached; -} XLogDumpPrivate; - typedef struct XLogDumpConfig { /* display options */ @@ -333,6 +326,32 @@ identify_target_directory(char *directory, char *fname, int *WalSegSz) return NULL; /* not reached */ } +/* + * Returns the size in bytes of the data to be read. Returns -1 if the end + * point has already been reached. + */ +static inline int +required_read_len(XLogDumpPrivate *private, XLogRecPtr targetPagePtr, + int reqLen) +{ + int count = XLOG_BLCKSZ; + + if (XLogRecPtrIsValid(private->endptr)) + { + if (targetPagePtr + XLOG_BLCKSZ <= private->endptr) + count = XLOG_BLCKSZ; + else if (targetPagePtr + reqLen <= private->endptr) + count = private->endptr - targetPagePtr; + else + { + private->endptr_reached = true; + return -1; + } + } + + return count; +} + /* pg_waldump's XLogReaderRoutine->segment_open callback */ static void WALDumpOpenSegment(XLogReaderState *state, XLogSegNo nextSegNo, @@ -390,21 +409,12 @@ WALDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetPtr, char *readBuff) { XLogDumpPrivate *private = state->private_data; - int count = XLOG_BLCKSZ; + int count = required_read_len(private, targetPagePtr, reqLen); WALReadError errinfo; - if (XLogRecPtrIsValid(private->endptr)) - { - if (targetPagePtr + XLOG_BLCKSZ <= private->endptr) - count = XLOG_BLCKSZ; - else if (targetPagePtr + reqLen <= private->endptr) - count = private->endptr - targetPagePtr; - else - { - private->endptr_reached = true; - return -1; - } - } + /* Bail out if the count to be read is not valid */ + if (count < 0) + return -1; if (!WALRead(state, readBuff, targetPagePtr, count, private->timeline, &errinfo)) @@ -801,7 +811,6 @@ main(int argc, char **argv) XLogRecPtr first_record; char *waldir = NULL; char *errormsg; - int WalSegSz; static struct option long_options[] = { {"bkp-details", no_argument, NULL, 'b'}, @@ -855,6 +864,7 @@ main(int argc, char **argv) memset(&stats, 0, sizeof(XLogStats)); private.timeline = 1; + private.segsize = 0; private.startptr = InvalidXLogRecPtr; private.endptr = InvalidXLogRecPtr; private.endptr_reached = false; @@ -1128,18 +1138,18 @@ main(int argc, char **argv) pg_fatal("could not open directory \"%s\": %m", waldir); } - waldir = identify_target_directory(waldir, fname, &WalSegSz); + waldir = identify_target_directory(waldir, fname, &private.segsize); fd = open_file_in_directory(waldir, fname); if (fd < 0) pg_fatal("could not open file \"%s\"", fname); close(fd); /* parse position from file */ - XLogFromFileName(fname, &private.timeline, &segno, WalSegSz); + XLogFromFileName(fname, &private.timeline, &segno, private.segsize); if (!XLogRecPtrIsValid(private.startptr)) - XLogSegNoOffsetToRecPtr(segno, 0, WalSegSz, private.startptr); - else if (!XLByteInSeg(private.startptr, segno, WalSegSz)) + XLogSegNoOffsetToRecPtr(segno, 0, private.segsize, private.startptr); + else if (!XLByteInSeg(private.startptr, segno, private.segsize)) { pg_log_error("start WAL location %X/%08X is not inside file \"%s\"", LSN_FORMAT_ARGS(private.startptr), @@ -1149,7 +1159,7 @@ main(int argc, char **argv) /* no second file specified, set end position */ if (!(optind + 1 < argc) && !XLogRecPtrIsValid(private.endptr)) - XLogSegNoOffsetToRecPtr(segno + 1, 0, WalSegSz, private.endptr); + XLogSegNoOffsetToRecPtr(segno + 1, 0, private.segsize, private.endptr); /* parse ENDSEG if passed */ if (optind + 1 < argc) @@ -1165,14 +1175,14 @@ main(int argc, char **argv) close(fd); /* parse position from file */ - XLogFromFileName(fname, &private.timeline, &endsegno, WalSegSz); + XLogFromFileName(fname, &private.timeline, &endsegno, private.segsize); if (endsegno < segno) pg_fatal("ENDSEG %s is before STARTSEG %s", argv[optind + 1], argv[optind]); if (!XLogRecPtrIsValid(private.endptr)) - XLogSegNoOffsetToRecPtr(endsegno + 1, 0, WalSegSz, + XLogSegNoOffsetToRecPtr(endsegno + 1, 0, private.segsize, private.endptr); /* set segno to endsegno for check of --end */ @@ -1180,8 +1190,8 @@ main(int argc, char **argv) } - if (!XLByteInSeg(private.endptr, segno, WalSegSz) && - private.endptr != (segno + 1) * WalSegSz) + if (!XLByteInSeg(private.endptr, segno, private.segsize) && + private.endptr != (segno + 1) * private.segsize) { pg_log_error("end WAL location %X/%08X is not inside file \"%s\"", LSN_FORMAT_ARGS(private.endptr), @@ -1190,7 +1200,7 @@ main(int argc, char **argv) } } else - waldir = identify_target_directory(waldir, NULL, &WalSegSz); + waldir = identify_target_directory(waldir, NULL, &private.segsize); /* we don't know what to print */ if (!XLogRecPtrIsValid(private.startptr)) @@ -1203,7 +1213,7 @@ main(int argc, char **argv) /* we have everything we need, start reading */ xlogreader_state = - XLogReaderAllocate(WalSegSz, waldir, + XLogReaderAllocate(private.segsize, waldir, XL_ROUTINE(.page_read = WALDumpReadPage, .segment_open = WALDumpOpenSegment, .segment_close = WALDumpCloseSegment), @@ -1224,7 +1234,7 @@ main(int argc, char **argv) * a segment (e.g. we were used in file mode). */ if (first_record != private.startptr && - XLogSegmentOffset(private.startptr, WalSegSz) != 0) + XLogSegmentOffset(private.startptr, private.segsize) != 0) pg_log_info(ngettext("first record is after %X/%08X, at %X/%08X, skipping over %u byte", "first record is after %X/%08X, at %X/%08X, skipping over %u bytes", (first_record - private.startptr)), diff --git a/src/bin/pg_waldump/pg_waldump.h b/src/bin/pg_waldump/pg_waldump.h new file mode 100644 index 00000000000..013b051506f --- /dev/null +++ b/src/bin/pg_waldump/pg_waldump.h @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- + * + * pg_waldump.h - decode and display WAL + * + * Copyright (c) 2026, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/bin/pg_waldump/pg_waldump.h + *------------------------------------------------------------------------- + */ +#ifndef PG_WALDUMP_H +#define PG_WALDUMP_H + +#include "access/xlogdefs.h" + +/* Contains the necessary information to drive WAL decoding */ +typedef struct XLogDumpPrivate +{ + TimeLineID timeline; + int segsize; + XLogRecPtr startptr; + XLogRecPtr endptr; + bool endptr_reached; +} XLogDumpPrivate; + +#endif /* PG_WALDUMP_H */