From b4e067f3ba003cf88e8390406601328443b43a7e Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Tue, 25 Nov 2025 15:59:06 -0800 Subject: [PATCH v30 3/3] PoC: Ensure XLogLogicalInfoActive() returns consistent result. --- src/backend/access/transam/xact.c | 3 ++ src/backend/replication/logical/logicalctl.c | 44 ++++++++++++++++++++ src/include/access/xlog.h | 21 ++++++---- src/include/replication/logicalctl.h | 2 + 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index d2d3c9b6ed6..02b4328b011 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -2489,6 +2489,7 @@ CommitTransaction(void) AtEOXact_Snapshot(true, false); AtEOXact_ApplyLauncher(true); AtEOXact_LogicalRepWorkers(true); + AtEOXact_LogicalCtl(); pgstat_report_xact_timestamp(0); ResourceOwnerDelete(TopTransactionResourceOwner); @@ -2784,6 +2785,7 @@ PrepareTransaction(void) /* we treat PREPARE as ROLLBACK so far as waking workers goes */ AtEOXact_ApplyLauncher(false); AtEOXact_LogicalRepWorkers(false); + AtEOXact_LogicalCtl(); pgstat_report_xact_timestamp(0); CurrentResourceOwner = NULL; @@ -3011,6 +3013,7 @@ AbortTransaction(void) AtEOXact_PgStat(false, is_parallel_worker); AtEOXact_ApplyLauncher(false); AtEOXact_LogicalRepWorkers(false); + AtEOXact_LogicalCtl(); pgstat_report_xact_timestamp(0); } diff --git a/src/backend/replication/logical/logicalctl.c b/src/backend/replication/logical/logicalctl.c index aee45c790d9..738afae04da 100644 --- a/src/backend/replication/logical/logicalctl.c +++ b/src/backend/replication/logical/logicalctl.c @@ -108,6 +108,17 @@ static LogicalDecodingCtlData *LogicalDecodingCtl = NULL; */ bool XLogLogicalInfo = false; +/* + * A transaction local cache of XLogLogicalInfo: + * -1: not cached yet, need to check XLogLogicalInfo. + * 0: cached, XLogLogicalInfo is disabled. + * 1: cached, XLogLogicalInfo is enabled. + * The cache is set when checking XLogLogicalInfoActive() for the first time + * in the transaction and kept until the transaction end. Once the flag value + * is cached, this cache is used simply by casting to an boolean. + */ +int XLogLogicalInfoXactCache = -1; + static void update_xlog_logical_info(void); static void abort_logical_decoding_activation(int code, Datum arg); static void write_logical_decoding_status_update_record(bool status); @@ -213,6 +224,39 @@ IsXLogLogicalInfoEnabled(void) return xlog_logical_info; } +/* + * Reset the local cache at end of the transaction. + */ +void +AtEOXact_LogicalCtl(void) +{ + XLogLogicalInfoXactCache = -1; +} + +/* + * Sub-routine for XLogLogicalInfoActive() to check if logical WAL logging + * is enabled. To save function call overheads, the caller must check + * the XLogLogicalInfoXactCache first, and use this function only when it's + * not set. + */ +bool +CheckXLogLogicalInfoSlow(void) +{ + /* Returns the current state if we're out of the transaction */ + if (!IsTransactionState()) + return XLogLogicalInfo; + + Assert(XLogLogicalInfoXactCache == -1); + + /* + * Cache the current state so as to return the same result within the same + * transaction. + */ + XLogLogicalInfoXactCache = (int) XLogLogicalInfo; + + return XLogLogicalInfoXactCache; +} + /* * Enable or disable both the status of logical info WAL logging and logical * decoding in shmem. diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 58655d91db7..fded25aba3d 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -13,6 +13,7 @@ #include "access/xlogbackup.h" #include "access/xlogdefs.h" +#include "replication/logicalctl.h" #include "datatype/timestamp.h" #include "lib/stringinfo.h" #include "nodes/pg_list.h" @@ -97,6 +98,7 @@ extern PGDLLIMPORT int wal_level; extern PGDLLEXPORT int effective_wal_level; extern PGDLLEXPORT bool XLogLogicalInfo; +extern PGDLLEXPORT int XLogLogicalInfoXactCache; /* Is WAL archiving enabled (always or only while server is running normally)? */ #define XLogArchivingActive() \ @@ -128,14 +130,19 @@ extern PGDLLEXPORT bool XLogLogicalInfo; /* * Do we need to WAL-log information required only for logical replication? * - * When XLogLogicalInfo is true, it enables logical-decoding-related WAL logging - * as if wal_level were set to 'logical', even if it's actually set to 'replica'. - * XLogLogicalInfo is a process-local variable, so the value returned by this - * macro might not reflect the latest state, but is sufficient for process-local - * WAL-logging decisions. See comments atop logicalctl.c for details on controlling - * the effective_wal_level. + * When XLogLogicalInfoActive() returns true, it enables logical-decoding-related + * WAL logging as if wal_level were set to 'logical', even if it's actually set + * to 'replica'. The XLogLogicalInfoXactCache is a transaction-local cache so + * that this macro ensures to return the same result within the same transaction. + * Also, it might not reflect the latest state as it's a process local cache, + * but it is sufficient for process-local WAL-logging decisions. See comments + * atop logicalctl.c for details on controlling the effective_wal_level. */ -#define XLogLogicalInfoActive() (wal_level >= WAL_LEVEL_LOGICAL || XLogLogicalInfo) +#define XLogLogicalInfoActive() \ + (wal_level >= WAL_LEVEL_LOGICAL || \ + (unlikely(XLogLogicalInfoXactCache < 0) ? \ + CheckXLogLogicalInfoSlow() : \ + (bool) XLogLogicalInfoXactCache)) #ifdef WAL_DEBUG extern PGDLLIMPORT bool XLOG_DEBUG; diff --git a/src/include/replication/logicalctl.h b/src/include/replication/logicalctl.h index 77ded671473..06423b2ee75 100644 --- a/src/include/replication/logicalctl.h +++ b/src/include/replication/logicalctl.h @@ -21,6 +21,8 @@ extern void InitializeProcessXLogLogicalInfo(void); extern bool ProcessBarrierUpdateXLogLogicalInfo(void); extern bool IsLogicalDecodingEnabled(void); extern bool IsXLogLogicalInfoEnabled(void); +extern bool CheckXLogLogicalInfoSlow(void); +extern void AtEOXact_LogicalCtl(void); extern void EnsureLogicalDecodingEnabled(void); extern void RequestDisableLogicalDecoding(void); extern void DisableLogicalDecodingIfNecessary(void); -- 2.47.3