postgres.git / summary / log / commit / refs

commit    fa9f2e31756225f4e17103d22d9e651bf8d41941
Author:   Fujii Masao <fujii@postgresql.org>
Date:     Mon Mar 16 23:10:20 2026 +0000

    Fix WAL flush LSN used by logical walsender during shutdown
    
    Commit 6eedb2a5fd8 made the logical walsender call
    XLogFlush(GetXLogInsertRecPtr()) to ensure that all pending WAL is flushed,
    fixing a publisher shutdown hang. However, if the last WAL record ends at
    a page boundary, GetXLogInsertRecPtr() can return an LSN pointing past
    the page header, which can cause XLogFlush() to report an error.
    
    A similar issue previously existed in the GiST code. Commit b1f14c96720
    introduced GetXLogInsertEndRecPtr(), which returns a safe WAL insertion end
    location (returning the start of the page when the last record ends at a page
    boundary), and updated the GiST code to use it with XLogFlush().
    
    This commit fixes the issue by making the logical walsender use
    XLogFlush(GetXLogInsertEndRecPtr()) when flushing pending WAL during shutdown.
    
    Backpatch to all supported versions.
    
    Reported-by: Andres Freund <andres@anarazel.de>
    Author: Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com>
    Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
    Discussion: https://postgr.es/m/vzguaguldbcyfbyuq76qj7hx5qdr5kmh67gqkncyb2yhsygrdt@dfhcpteqifux
    Backpatch-through: 14


src/backend/replication/walsender.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 566f8a232e4..eadc800c9ca 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -1602,9 +1602,15 @@ WalSndWaitForWal(XLogRecPtr loc) * If we're shutting down, trigger pending WAL to be written out, * otherwise we'd possibly end up waiting for WAL that never gets * written, because walwriter has shut down already. + * + * Note that GetXLogInsertEndRecPtr() is used to obtain the WAL flush + * request location instead of GetXLogInsertRecPtr(). Because if the + * last WAL record ends at a page boundary, GetXLogInsertRecPtr() can + * return an LSN pointing past the page header, which may cause + * XLogFlush() to report an error. */ if (got_STOPPING && !RecoveryInProgress()) - XLogFlush(GetXLogInsertRecPtr()); + XLogFlush(GetXLogInsertEndRecPtr()); /* Update our idea of the currently flushed position. */ if (!RecoveryInProgress()) [parent: 34baa313e317]