=== Applying patches on top of PostgreSQL commit ID 10b6e2a3d66098bf26b236c880bab5b3fafc42bd === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Tue Oct 6 18:44:30 UTC 2026 On branch cf/7220 nothing to commit, working tree clean === using 'git am' to apply patch ./v1-0001-pg_rewind-scan-an-unclean-target-s-WAL-instead-of-fo.patch === Applying: pg_rewind: scan an unclean target's WAL instead of forcing crash recovery .git/rebase-apply/patch:123: trailing whitespace. XLogRecPtr *lastchkptredo, const char *restoreCommand, .git/rebase-apply/patch:124: indent with spaces. XLogRecPtr cntrlfilechkptrec) .git/rebase-apply/patch:142: trailing whitespace. /* .git/rebase-apply/patch:143: trailing whitespace, indent with spaces. * Attempt the standard backward scan first. .git/rebase-apply/patch:144: indent with spaces. */ warning: squelched 7 whitespace errors warning: 12 lines add whitespace errors. Using index info to reconstruct a base tree... M src/bin/pg_rewind/parsexlog.c M src/bin/pg_rewind/pg_rewind.c M src/bin/pg_rewind/pg_rewind.h Falling back to patching base and 3-way merge... Auto-merging src/bin/pg_rewind/pg_rewind.h CONFLICT (content): Merge conflict in src/bin/pg_rewind/pg_rewind.h Auto-merging src/bin/pg_rewind/pg_rewind.c CONFLICT (content): Merge conflict in src/bin/pg_rewind/pg_rewind.c Auto-merging src/bin/pg_rewind/parsexlog.c CONFLICT (content): Merge conflict in src/bin/pg_rewind/parsexlog.c error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 pg_rewind: scan an unclean target's WAL instead of forcing crash recovery When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". === using patch(1) to apply patch ./v1-0001-pg_rewind-scan-an-unclean-target-s-WAL-instead-of-fo.patch === patching file src/bin/pg_rewind/parsexlog.c Hunk #3 FAILED at 110. Hunk #4 succeeded at 121 (offset 1 line). Hunk #5 FAILED at 144. 2 out of 5 hunks FAILED -- saving rejects to file src/bin/pg_rewind/parsexlog.c.rej patching file src/bin/pg_rewind/pg_rewind.c Hunk #2 succeeded at 55 (offset 1 line). Hunk #3 succeeded at 108 (offset 1 line). Hunk #4 succeeded at 127 (offset 1 line). Hunk #5 succeeded at 151 (offset 2 lines). Hunk #6 succeeded at 215 (offset 2 lines). Hunk #7 succeeded at 319 (offset 2 lines). Hunk #8 succeeded at 364 (offset 2 lines). Hunk #9 succeeded at 394 (offset 2 lines). Hunk #10 FAILED at 409. Hunk #11 succeeded at 477 (offset 43 lines). Hunk #12 succeeded at 838 with fuzz 1 (offset 120 lines). Hunk #13 succeeded at 1192 (offset 120 lines). 1 out of 13 hunks FAILED -- saving rejects to file src/bin/pg_rewind/pg_rewind.c.rej patching file src/bin/pg_rewind/pg_rewind.h Hunk #1 FAILED at 32. 1 out of 1 hunk FAILED -- saving rejects to file src/bin/pg_rewind/pg_rewind.h.rej patching file src/bin/pg_rewind/t/001_basic.pl patching file src/bin/pg_rewind/t/RewindTest.pm Unstaged changes after reset: M src/bin/pg_rewind/parsexlog.c M src/bin/pg_rewind/pg_rewind.c M src/bin/pg_rewind/t/001_basic.pl M src/bin/pg_rewind/t/RewindTest.pm Removing src/bin/pg_rewind/parsexlog.c.rej Removing src/bin/pg_rewind/pg_rewind.c.rej Removing src/bin/pg_rewind/pg_rewind.h.rej === using 'git apply' to apply patch ./v1-0001-pg_rewind-scan-an-unclean-target-s-WAL-instead-of-fo.patch === /work/patches/./v1-0001-pg_rewind-scan-an-unclean-target-s-WAL-instead-of-fo.patch:155: trailing whitespace. XLogRecPtr *lastchkptredo, const char *restoreCommand, /work/patches/./v1-0001-pg_rewind-scan-an-unclean-target-s-WAL-instead-of-fo.patch:156: indent with spaces. XLogRecPtr cntrlfilechkptrec) /work/patches/./v1-0001-pg_rewind-scan-an-unclean-target-s-WAL-instead-of-fo.patch:174: trailing whitespace. /* /work/patches/./v1-0001-pg_rewind-scan-an-unclean-target-s-WAL-instead-of-fo.patch:175: trailing whitespace, indent with spaces. * Attempt the standard backward scan first. /work/patches/./v1-0001-pg_rewind-scan-an-unclean-target-s-WAL-instead-of-fo.patch:176: indent with spaces. */ Applied patch to 'src/bin/pg_rewind/parsexlog.c' with conflicts. Applied patch to 'src/bin/pg_rewind/pg_rewind.c' with conflicts. Applied patch to 'src/bin/pg_rewind/pg_rewind.h' with conflicts. Applied patch to 'src/bin/pg_rewind/t/001_basic.pl' cleanly. Applied patch to 'src/bin/pg_rewind/t/RewindTest.pm' cleanly. U src/bin/pg_rewind/parsexlog.c U src/bin/pg_rewind/pg_rewind.c U src/bin/pg_rewind/pg_rewind.h warning: squelched 7 whitespace errors warning: 12 lines add whitespace errors. diff --cc src/bin/pg_rewind/parsexlog.c index 6e87b00f8c2,eee1547c84c..00000000000 --- a/src/bin/pg_rewind/parsexlog.c +++ b/src/bin/pg_rewind/parsexlog.c @@@ -167,10 -110,9 +110,14 @@@ extractPageMap(const char *datadir, XLo void findLastCheckpoint(const char *datadir, XLogRecPtr forkptr, int tliIndex, XLogRecPtr *lastchkptrec, TimeLineID *lastchkpttli, ++<<<<<<< ours + XLogRecPtr *lastchkptredo, uint32 *lastchkptdatachecksums, + const char *restoreCommand) ++======= + XLogRecPtr *lastchkptredo, const char *restoreCommand, + XLogRecPtr cntrlfilechkptrec) ++>>>>>>> theirs { - /* Walk backwards, starting from the given record */ XLogRecord *record; XLogRecPtr searchptr; XLogReaderState *xlogreader; @@@ -201,67 -144,137 +149,147 @@@ if (xlogreader == NULL) pg_fatal("out of memory while allocating a WAL reading processor"); + /* + * Attempt the standard backward scan first. + */ searchptr = forkptr; - for (;;) - { - uint8 info; - - XLogBeginRead(xlogreader, searchptr); - record = XLogReadRecord(xlogreader, &errormsg); + XLogBeginRead(xlogreader, searchptr); + record = XLogReadRecord(xlogreader, &errormsg); - if (record == NULL) - { - if (errormsg) - pg_fatal("could not find previous WAL record at %X/%08X: %s", - LSN_FORMAT_ARGS(searchptr), - errormsg); - else - pg_fatal("could not find previous WAL record at %X/%08X", - LSN_FORMAT_ARGS(searchptr)); - } + if (record == NULL) + { + /* + * If we fail to read exactly at the forkptr, we assume the target crashed + * exactly at a record boundary and the WAL is padded with zeroes. + * Instead of crashing pg_rewind, we fallback to a forward scan. + */ + fallback_to_forward = true; + } - /* Detect if a new WAL file has been opened */ - if (xlogreader->seg.ws_tli != current_tli || - xlogreader->seg.ws_segno != current_segno) + if (!fallback_to_forward) + { + /* We successfully read the first record; proceed with backward scan */ + for (;;) { - char xlogfname[MAXFNAMELEN]; - - snprintf(xlogfname, MAXFNAMELEN, XLOGDIR "/"); - - /* update current values */ - current_tli = xlogreader->seg.ws_tli; - current_segno = xlogreader->seg.ws_segno; - - XLogFileName(xlogfname + sizeof(XLOGDIR), - current_tli, current_segno, WalSegSz); - - /* Track this filename as one to not remove */ - keepwal_add_entry(xlogfname); + uint8 info; + + if (record == NULL) + { + /* A failure mid-scan means real corruption, so we error out */ + if (errormsg) + pg_fatal("could not find previous WAL record at %X/%08X: %s", + LSN_FORMAT_ARGS(searchptr), errormsg); + else + pg_fatal("could not find previous WAL record at %X/%08X", + LSN_FORMAT_ARGS(searchptr)); + } + + /* Detect if a new WAL file has been opened */ + if (xlogreader->seg.ws_tli != current_tli || + xlogreader->seg.ws_segno != current_segno) + { + char xlogfname[MAXFNAMELEN]; + + snprintf(xlogfname, MAXFNAMELEN, XLOGDIR "/"); + current_tli = xlogreader->seg.ws_tli; + current_segno = xlogreader->seg.ws_segno; + XLogFileName(xlogfname + sizeof(XLOGDIR), + current_tli, current_segno, WalSegSz); + keepwal_add_entry(xlogfname); + } + + /* Check if it is a valid checkpoint record. */ + info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK; + if (searchptr < forkptr && + XLogRecGetRmid(xlogreader) == RM_XLOG_ID && + (info == XLOG_CHECKPOINT_SHUTDOWN || + info == XLOG_CHECKPOINT_ONLINE)) + { + CheckPoint checkPoint; + + memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint)); + *lastchkptrec = searchptr; + *lastchkpttli = checkPoint.ThisTimeLineID; + *lastchkptredo = checkPoint.redo; + break; + } + + /* Walk backwards to previous record. */ + searchptr = record->xl_prev; + XLogBeginRead(xlogreader, searchptr); + record = XLogReadRecord(xlogreader, &errormsg); } + } + else + { + /* + * Fallback. Scan forward from the control file's last checkpoint. + */ + searchptr = cntrlfilechkptrec; + XLogBeginRead(xlogreader, searchptr); - /* - * Check if it is a checkpoint record. This checkpoint record needs to - * be the latest checkpoint before WAL forked and not the checkpoint - * where the primary has been stopped to be rewound. - */ - info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK; - if (searchptr < forkptr && - XLogRecGetRmid(xlogreader) == RM_XLOG_ID && - (info == XLOG_CHECKPOINT_SHUTDOWN || - info == XLOG_CHECKPOINT_ONLINE)) + for (;;) { - CheckPoint checkPoint; + uint8 info; ++<<<<<<< ours + memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint)); + *lastchkptrec = searchptr; + *lastchkpttli = checkPoint.ThisTimeLineID; + *lastchkptredo = checkPoint.redo; + *lastchkptdatachecksums = checkPoint.dataChecksumState; + break; + } - - /* Walk backwards to previous record. */ - searchptr = record->xl_prev; ++======= + record = XLogReadRecord(xlogreader, &errormsg); + + if (record == NULL) + { + if (errormsg) + pg_fatal("could not read WAL record during forward scan at %X/%08X: %s", + LSN_FORMAT_ARGS(searchptr), errormsg); + else + pg_fatal("could not read WAL record during forward scan at %X/%08X", + LSN_FORMAT_ARGS(searchptr)); + } + + /* Update searchptr to the start of the record we just read */ + searchptr = xlogreader->ReadRecPtr; + + /* Detect if a new WAL file has been opened */ + if (xlogreader->seg.ws_tli != current_tli || + xlogreader->seg.ws_segno != current_segno) + { + char xlogfname[MAXFNAMELEN]; + + snprintf(xlogfname, MAXFNAMELEN, XLOGDIR "/"); + current_tli = xlogreader->seg.ws_tli; + current_segno = xlogreader->seg.ws_segno; + XLogFileName(xlogfname + sizeof(XLOGDIR), + current_tli, current_segno, WalSegSz); + keepwal_add_entry(xlogfname); + } ++>>>>>>> theirs + + /* Check if it is a checkpoint record. Update pointers iteratively. */ + info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK; + if (searchptr < forkptr && + XLogRecGetRmid(xlogreader) == RM_XLOG_ID && + (info == XLOG_CHECKPOINT_SHUTDOWN || + info == XLOG_CHECKPOINT_ONLINE)) + { + CheckPoint checkPoint; + + memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint)); + *lastchkptrec = searchptr; + *lastchkpttli = checkPoint.ThisTimeLineID; + *lastchkptredo = checkPoint.redo; + } + + /* If we've reached or passed the divergence point, we are done */ + if (xlogreader->EndRecPtr >= forkptr) + break; + } } XLogReaderFree(xlogreader); diff --cc src/bin/pg_rewind/pg_rewind.c index d2521dab333,0e77c41b17c..00000000000 --- a/src/bin/pg_rewind/pg_rewind.c +++ b/src/bin/pg_rewind/pg_rewind.c @@@ -473,8 -409,7 +411,12 @@@ main(int argc, char **argv keepwal_init(); findLastCheckpoint(datadir_target, divergerec, lastcommontliIndex, ++<<<<<<< ours + &chkptrec, &chkpttli, &chkptredo, &chkptdatachecksums, + restore_command); ++======= + &chkptrec, &chkpttli, &chkptredo, restore_command, ControlFile_target.checkPoint); ++>>>>>>> theirs pg_log_info("rewinding from last common checkpoint at %X/%08X on timeline %u", LSN_FORMAT_ARGS(chkptrec), chkpttli); @@@ -842,65 -719,6 +794,68 @@@ sanityChecks(void } /* ++<<<<<<< ours + * The rewound target keeps its control file fields from the source, but + * every block the rewind does not copy keeps the target's content. If + * checksums are enabled on the target and disabled on the source, the + * result would claim enabled checksums while the blocks copied from the + * source have none, and the target would fail checksum verification as + * soon as it reads them. Refuse that combination, and refuse an + * interrupted online transition on either side, same as pg_checksums. + * + * The opposite mismatch is allowed: recovery under the backup label + * written by pg_rewind adopts the checksum state as of the divergence + * point, so a target whose own checkpoints carry no checksums stays + * without them, or converges through the replayed WAL if the source + * enabled them online. Only warn about it, so that an offline change on + * the source is not overlooked. + * + * That reasoning does not hold when the target is a standby, whose + * checkpoints were written by its upstream primary; see the checks after + * findLastCheckpoint(). + */ + if (ControlFile_target.data_checksum_version == PG_DATA_CHECKSUM_INPROGRESS_ON || + ControlFile_target.data_checksum_version == PG_DATA_CHECKSUM_INPROGRESS_OFF) + { + pg_log_error("an online data checksum state transition was interrupted on the target server"); + pg_log_error_hint("Start the server and shut it down cleanly to reset the state, then retry; on a standby, let replication complete the transition first."); + exit(1); + } + if (ControlFile_source.data_checksum_version == PG_DATA_CHECKSUM_INPROGRESS_ON || + ControlFile_source.data_checksum_version == PG_DATA_CHECKSUM_INPROGRESS_OFF) + { + pg_log_error("an online data checksum state transition is incomplete on the source server"); + pg_log_error_hint("Let the transition complete, or reset the state with a clean restart, then retry."); + exit(1); + } + if (ControlFile_target.data_checksum_version == PG_DATA_CHECKSUM_VERSION && + ControlFile_source.data_checksum_version == PG_DATA_CHECKSUM_OFF) + { + pg_log_error("data checksums are enabled on the target server but disabled on the source server"); + pg_log_error_detail("Blocks copied from the source would have no checksums, and the target would fail checksum verification after the rewind."); + pg_log_error_hint("Either disable data checksums on the target server or enable them on the source server, then retry."); + exit(1); + } + if (ControlFile_target.data_checksum_version == PG_DATA_CHECKSUM_OFF && + ControlFile_source.data_checksum_version == PG_DATA_CHECKSUM_VERSION) + { + pg_log_warning("data checksums are disabled on the target server but enabled on the source server"); + pg_log_warning_detail("The rewound server will keep data checksums disabled unless the source server enabled them online after the point of divergence."); + } + + /* + * Target cluster better not be running. This doesn't guard against + * someone starting the cluster concurrently. Also, this is probably more + * strict than necessary; it's OK if the target node was not shut down + * cleanly, as long as it isn't running at the moment. + */ + if (ControlFile_target.state != DB_SHUTDOWNED && + ControlFile_target.state != DB_SHUTDOWNED_IN_RECOVERY) + pg_fatal("target server must be shut down cleanly"); + + /* ++======= ++>>>>>>> theirs * When the source is a data directory, also require that the source * server is shut down. There isn't any very strong reason for this * limitation, but better safe than sorry. diff --cc src/bin/pg_rewind/pg_rewind.h index 9187c3bf72f,b01fd3f0c1d..00000000000 --- a/src/bin/pg_rewind/pg_rewind.h +++ b/src/bin/pg_rewind/pg_rewind.h @@@ -39,10 -39,7 +39,14 @@@ extern void findLastCheckpoint(const ch int tliIndex, XLogRecPtr *lastchkptrec, TimeLineID *lastchkpttli, XLogRecPtr *lastchkptredo, ++<<<<<<< ours + uint32 *lastchkptdatachecksums, + const char *restoreCommand); +extern XLogRecPtr readOneRecord(const char *datadir, XLogRecPtr ptr, + int tliIndex, const char *restoreCommand); ++======= + const char *restoreCommand, XLogRecPtr cntrlfilechkptrec); ++>>>>>>> theirs /* in pg_rewind.c */ extern void progress_report(bool finished);