Thread

  1. [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.

    Antonin Houska <ah@cybertec.at> — 2026-05-06T07:38:11Z

    Currently, decoding session that relies on database-specific xl_running_xacts
    WAL records can also use some information of cluster-wide records and vice
    versa. Although this approach might reduce the total number of
    xl_running_xacts records, it's simply not correct.
    
    SnapBuildProcessRunningXacts() now decides at the very beginning whether
    particular record can be used or not.
    ---
     src/backend/replication/logical/snapbuild.c | 55 +++++++++++++--------
     1 file changed, 34 insertions(+), 21 deletions(-)
    
    diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
    index c8309b96ed4..b9661b7d70a 100644
    --- a/src/backend/replication/logical/snapbuild.c
    +++ b/src/backend/replication/logical/snapbuild.c
    @@ -1157,6 +1157,39 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
     	ReorderBufferTXN *txn;
     	TransactionId xmin;
     
    +	/*
    +	 * Each decoding session should use either cluster-wide snapshots or
    +	 * database-specific ones, but not both. Since the latter can have more
    +	 * recent value of oldestRunningXid, builder->xmin could go backwards if
    +	 * it was followed by cluster-wide snapshot - see the ->xmin adjustment
    +	 * below.
    +	 */
    +	if (!db_specific && OidIsValid(running->dbid))
    +		return;
    +
    +	if (db_specific)
    +	{
    +		/*
    +		 * Make sure that we have the snapshots needed for startup, as well as
    +		 * those for regular cleanup: each time the cluster-wide snapshot is
    +		 * created (typically on slot creation or by checkpointer), the
    +		 * database-specific snapshot is requested here if the current session
    +		 * needs it.
    +		 */
    +		if (!OidIsValid(running->dbid))
    +		{
    +			LogStandbySnapshot(MyDatabaseId);
    +
    +			return;
    +		}
    +		/*
    +		 * Snapshots issued for other databases do not contain the information
    +		 * about transactions in our database.
    +		 */
    +		else if (running->dbid != MyDatabaseId)
    +			return;
    +	}
    +
     	/*
     	 * If we're not consistent yet, inspect the record to see whether it
     	 * allows to get closer to being consistent. If we are consistent, dump
    @@ -1171,17 +1204,7 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
     		 */
     		if (db_specific)
     		{
    -			/*
    -			 * If we must only keep track of transactions running in the
    -			 * current database, we need transaction info from exactly that
    -			 * database.
    -			 */
    -			if (running->dbid != MyDatabaseId)
    -			{
    -				LogStandbySnapshot(MyDatabaseId);
    -
    -				return;
    -			}
    +			Assert(running->dbid == MyDatabaseId);
     
     			/*
     			 * We'd better be able to check during scan if the plugin does not
    @@ -1198,16 +1221,6 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact
     	else
     		SnapBuildSerialize(builder, lsn);
     
    -	/*
    -	 * Database specific transaction info may exist to reach CONSISTENT state
    -	 * faster, however the code below makes no use of it. Moreover, such
    -	 * record might cause problems because the following normal (cluster-wide)
    -	 * record can have lower value of oldestRunningXid. In that case, let's
    -	 * wait with the cleanup for the next regular cluster-wide record.
    -	 */
    -	if (OidIsValid(running->dbid))
    -		return;
    -
     	/*
     	 * Update range of interesting xids based on the running xacts
     	 * information. We don't increase ->xmax using it, because once we are in
    -- 
    2.47.3
    
    
    --tbdehtstrqwksfdh--