Thread

  1. Re: [BUG] Take a long time to reach consistent after pg_rewind

    surya poondla <suryapoondla4@gmail.com> — 2026-05-19T21:20:56Z

    Subject: Re: [BUG] Take a long time to reach consistent after pg_rewind
    
    Hi ChangAo,
    
    Thanks for the careful diagnosis, I reproduced the hang on macOS on the
    latest postgres code (It took a lot of iterations to reproduce it)
    The LSN trace matches your description and I saw the below:
        minRecoveryPoint = 0/08000028
        consistent recovery state reached at = 0/08000060
    
    In my run the standby was stuck for ~9 s; consistency was eventually
    declared at 0/08000060 because a small upstream record (most likely
    a RUNNING_XACTS snapshot from bgwriter) landed at 0/08000028 and let
    lastReplayedEndRecPtr leap past the bad finish line.
    With the new primary stopped after pg_rewind, the wait was unbounded as
    expected.
    
    Regarding the fix: the underlying issue is that minRecoveryPoint is
    implicitly expected to be the end-LSN of a real WAL record, because
    lastReplayedEndRecPtr (the value it gets compared against)
    can only ever take such values.  All current writers respect this
    expectation except pg_rewind: pg_basebackup uses the backup-end record's
    EndRecPtr, and the in-running UpdateMinRecoveryPoint path
    uses buffer LSNs, both of which are record-end LSNs by construction.
    pg_rewind alone uses pg_current_wal_insert_lsn(), which can return a
    position just past a page header when the source is idle.
    That's why I'd lean toward fixing the producer (pg_rewind).
    
    Concretely, your original suggestion having pg_rewind use
    GetXLogInsertEndRecPtr() instead of GetXLogInsertRecPtr(), restores
    the invariant globally, and doesn't require future call sites that compare
    against minRecoveryPoint to know about page-header adjustments.
    
    If we still want a defense-in-depth guard in CheckRecoveryConsistency() to
    handle older pg_rewind binaries running against a newer server,
    the v1 patch is on the right track, but I'd suggest:
      - documenting in the helper comment why exactly SizeOfXLogShortPHD /
        SizeOfXLogLongPHD past a page boundary are the only legal
        "non-record-end" minRecoveryPoint values (i.e. who can produce
        them and under what conditions);
    
      - auditing the other call sites that compare against
        minRecoveryPoint to confirm none of them needs the same
        adjustment, with a comment recording the conclusion.
    
    I can put together a TAP test under src/bin/pg_rewind/t/ that forces a WAL
    switch on the source, runs pg_rewind against an
    otherwise-idle primary, and asserts that the rewound node reaches
    consistency without further upstream activity.
    Happy to send a v2 with that test if useful.
    
    This is a liveness bug with potentially unbounded wait on idle promoted
    primaries, so it does seem worth back-patching.
    
    Regards,
    Surya Poondla