diff options
author | Masahiko Sawada | 2025-02-24 22:03:04 +0000 |
---|---|---|
committer | Masahiko Sawada | 2025-02-24 22:03:04 +0000 |
commit | 48796a98d5aed68e349118d4e05ac26b76c765b0 (patch) | |
tree | a3ddf904c411f6d7c9e0d3bda4f4484cd852ba74 /src/backend/replication | |
parent | d1146dc2a72e96294045f7feb6d0f29082e1c71c (diff) |
Fix assertion when decoding XLOG_PARAMETER_CHANGE on promoted primary.
When a standby replays an XLOG_PARAMETER_CHANGE record that lowers
wal_level below logical, we invalidate all logical slots in hot
standby mode. However, if this record was replayed while not in hot
standby mode, logical slots could remain valid even after promotion,
potentially causing an assertion failure during WAL record decoding.
To fix this issue, this commit adds a check for hot_standby status
when restoring a logical replication slot on standbys. This check
ensures that logical slots are invalidated when they become
incompatible due to insufficient wal_level during recovery.
Backpatch to v16 where logical decoding on standby was introduced.
Reviewed-by: Amit Kapila <[email protected]>
Reviewed-by: Bertrand Drouvot <[email protected]>
Discussion: https://postgr.es/m/CAD21AoABoFwGY_Rh2aeE6tEq3HkJxf0c6UeOXn4VV9v6BAQPSw%40mail.gmail.com
Backpatch-through: 16
Diffstat (limited to 'src/backend/replication')
-rw-r--r-- | src/backend/replication/slot.c | 29 |
1 files changed, 23 insertions, 6 deletions
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c index 84270c493a5..d089085b491 100644 --- a/src/backend/replication/slot.c +++ b/src/backend/replication/slot.c @@ -2521,12 +2521,29 @@ RestoreSlotFromDisk(const char *name) * NB: Changing the requirements here also requires adapting * CheckSlotRequirements() and CheckLogicalDecodingRequirements(). */ - if (cp.slotdata.database != InvalidOid && wal_level < WAL_LEVEL_LOGICAL) - ereport(FATAL, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("logical replication slot \"%s\" exists, but \"wal_level\" < \"logical\"", - NameStr(cp.slotdata.name)), - errhint("Change \"wal_level\" to be \"logical\" or higher."))); + if (cp.slotdata.database != InvalidOid) + { + if (wal_level < WAL_LEVEL_LOGICAL) + ereport(FATAL, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("logical replication slot \"%s\" exists, but \"wal_level\" < \"logical\"", + NameStr(cp.slotdata.name)), + errhint("Change \"wal_level\" to be \"logical\" or higher."))); + + /* + * In standby mode, the hot standby must be enabled. This check is + * necessary to ensure logical slots are invalidated when they become + * incompatible due to insufficient wal_level. Otherwise, if the + * primary reduces wal_level < logical while hot standby is disabled, + * logical slots would remain valid even after promotion. + */ + if (StandbyMode && !EnableHotStandby) + ereport(FATAL, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("logical replication slot \"%s\" exists on the standby, but \"hot_standby\" = \"off\"", + NameStr(cp.slotdata.name)), + errhint("Change \"hot_standby\" to be \"on\"."))); + } else if (wal_level < WAL_LEVEL_REPLICA) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), |