agora inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH v26 3/9] Row pattern recognition patch (rewriter).
1915+ messages / 2 participants
[nested] [flat]

* [PATCH v26 3/9] Row pattern recognition patch (rewriter).
@ 2024-12-30 12:44  Tatsuo Ishii <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Tatsuo Ishii @ 2024-12-30 12:44 UTC (permalink / raw)

---
 src/backend/utils/adt/ruleutils.c | 103 ++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index be1f1f50b7..f58392f0aa 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -435,6 +435,10 @@ static void get_rule_groupingset(GroupingSet *gset, List *targetlist,
 								 bool omit_parens, deparse_context *context);
 static void get_rule_orderby(List *orderList, List *targetList,
 							 bool force_colno, deparse_context *context);
+static void get_rule_pattern(List *patternVariable, List *patternRegexp,
+							 bool force_colno, deparse_context *context);
+static void get_rule_define(List *defineClause, List *patternVariables,
+							bool force_colno, deparse_context *context);
 static void get_rule_windowclause(Query *query, deparse_context *context);
 static void get_rule_windowspec(WindowClause *wc, List *targetList,
 								deparse_context *context);
@@ -6667,6 +6671,67 @@ get_rule_orderby(List *orderList, List *targetList,
 	}
 }
 
+/*
+ * Display a PATTERN clause.
+ */
+static void
+get_rule_pattern(List *patternVariable, List *patternRegexp,
+				 bool force_colno, deparse_context *context)
+{
+	StringInfo	buf = context->buf;
+	const char *sep;
+	ListCell   *lc_var,
+			   *lc_reg = list_head(patternRegexp);
+
+	sep = "";
+	appendStringInfoChar(buf, '(');
+	foreach(lc_var, patternVariable)
+	{
+		char	   *variable = strVal((String *) lfirst(lc_var));
+		char	   *regexp = NULL;
+
+		if (lc_reg != NULL)
+		{
+			regexp = strVal((String *) lfirst(lc_reg));
+
+			lc_reg = lnext(patternRegexp, lc_reg);
+		}
+
+		appendStringInfo(buf, "%s%s", sep, variable);
+		if (regexp !=NULL)
+			appendStringInfoString(buf, regexp);
+
+		sep = " ";
+	}
+	appendStringInfoChar(buf, ')');
+}
+
+/*
+ * Display a DEFINE clause.
+ */
+static void
+get_rule_define(List *defineClause, List *patternVariables,
+				bool force_colno, deparse_context *context)
+{
+	StringInfo	buf = context->buf;
+	const char *sep;
+	ListCell   *lc_var,
+			   *lc_def;
+
+	sep = "  ";
+	Assert(list_length(patternVariables) == list_length(defineClause));
+
+	forboth(lc_var, patternVariables, lc_def, defineClause)
+	{
+		char	   *varName = strVal(lfirst(lc_var));
+		TargetEntry *te = (TargetEntry *) lfirst(lc_def);
+
+		appendStringInfo(buf, "%s%s AS ", sep, varName);
+		get_rule_expr((Node *) te->expr, context, false);
+		sep = ",\n  ";
+	}
+}
+
 /*
  * Display a WINDOW clause.
  *
@@ -6804,6 +6869,44 @@ get_rule_windowspec(WindowClause *wc, List *targetList,
 			appendStringInfoString(buf, "EXCLUDE GROUP ");
 		else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_TIES)
 			appendStringInfoString(buf, "EXCLUDE TIES ");
+		/* RPR */
+		if (wc->rpSkipTo == ST_NEXT_ROW)
+			appendStringInfoString(buf,
+								   "\n  AFTER MATCH SKIP TO NEXT ROW ");
+		else if (wc->rpSkipTo == ST_PAST_LAST_ROW)
+			appendStringInfoString(buf,
+								   "\n  AFTER MATCH SKIP PAST LAST ROW ");
+		else if (wc->rpSkipTo == ST_FIRST_VARIABLE)
+			appendStringInfo(buf,
+							 "\n  AFTER MATCH SKIP TO FIRST %s ",
+							 wc->rpSkipVariable);
+		else if (wc->rpSkipTo == ST_LAST_VARIABLE)
+			appendStringInfo(buf,
+							 "\n  AFTER MATCH SKIP TO LAST %s ",
+							 wc->rpSkipVariable);
+		else if (wc->rpSkipTo == ST_VARIABLE)
+			appendStringInfo(buf,
+							 "\n  AFTER MATCH SKIP TO %s ",
+							 wc->rpSkipVariable);
+
+		if (wc->initial)
+			appendStringInfoString(buf, "\n  INITIAL");
+
+		if (wc->patternVariable)
+		{
+			appendStringInfoString(buf, "\n  PATTERN ");
+			get_rule_pattern(wc->patternVariable, wc->patternRegexp,
+							 false, context);
+		}
+
+		if (wc->defineClause)
+		{
+			appendStringInfoString(buf, "\n  DEFINE\n");
+			get_rule_define(wc->defineClause, wc->patternVariable,
+							false, context);
+			appendStringInfoChar(buf, ' ');
+		}
+
 		/* we will now have a trailing space; remove it */
 		buf->len--;
 	}
-- 
2.25.1


----Next_Part(Mon_Dec_30_22_37_18_2024_171)--
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="v26-0004-Row-pattern-recognition-patch-planner.patch"



^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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


--=-=-=--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread

* [PATCH 3/3] Distinguish properly when database-specific transaction list should be used.
@ 2026-05-06 07:38  Antonin Houska <[email protected]>
  0 siblings, 0 replies; 1915+ messages in thread

From: Antonin Houska @ 2026-05-06 07:38 UTC (permalink / raw)

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--





^ permalink  raw  reply  [nested|flat] 1915+ messages in thread


end of thread, other threads:[~2026-05-06 07:38 UTC | newest]

Thread overview: 1915+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2024-12-30 12:44 [PATCH v26 3/9] Row pattern recognition patch (rewriter). Tatsuo Ishii <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>
2026-05-06 07:38 [PATCH 3/3] Distinguish properly when database-specific transaction list should be used. Antonin Houska <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox