From d223ac6d8ac3cc96bbae2d193148c3c6876c7e4c Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@2ndquadrant.com>
Date: Mon, 27 Nov 2023 01:39:13 +0100
Subject: [PATCH v20231128 2/4] tweak ReorderBufferSequenceIsTransactional

---
 src/backend/replication/logical/decode.c      |  2 +-
 .../replication/logical/reorderbuffer.c       | 66 +++++++++----------
 src/include/replication/reorderbuffer.h       |  3 +-
 3 files changed, 35 insertions(+), 36 deletions(-)

diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index d48d88081f4..78f7870324c 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -1435,7 +1435,7 @@ seq_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
 	 */
 	transactional = ReorderBufferSequenceIsTransactional(ctx->reorder,
 														 target_locator,
-														 NULL);
+														 xid, NULL);
 
 	/* Skip the change if already processed (per the snapshot). */
 	if (transactional &&
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index ab0ef3c0667..5ff829e8555 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -1013,50 +1013,48 @@ ReorderBufferQueueMessage(ReorderBuffer *rb, TransactionId xid,
 bool
 ReorderBufferSequenceIsTransactional(ReorderBuffer *rb,
 									 RelFileLocator rlocator,
-									 TransactionId *xid)
+									 TransactionId xidin,
+									 TransactionId *xidout)
 {
 	bool		found = false;
-	dlist_iter	iter;
+	ReorderBufferTXN   *txn;
+	ReorderBufferSequenceEnt *entry;
 
 	AssertCheckSequences(rb);
 
 	/*
-	 * Walk all top-level transactions (some of which may be subxacts, except
-	 * that we haven't processed the assignments yet), and check if any of
-	 * them created the relfilenode.
+	 * Try to lookup transaction with the XID of the change. If it exists, the
+	 * relfilenode would have to be either in it or the top-level transaction
+	 * (if it was created in some earlier subtransaction).
+	 *
+	 * If this is a subxact, we'll search just the top-level hash table. That's
+	 * simpler and likely faster than having to search two hash tables.
 	 */
-	dlist_foreach(iter, &rb->toplevel_by_lsn)
-	{
-		ReorderBufferSequenceEnt *entry;
-		ReorderBufferTXN *txn = dlist_container(ReorderBufferTXN, node,
-												iter.cur);
+	txn = ReorderBufferTXNByXid(rb, xidin, false, NULL, InvalidXLogRecPtr,
+								false);
 
-		/* transaction has no relfilenodes at all */
-		if (!txn->sequences_hash)
-			continue;
+	if (!txn)
+		return false;
 
-		entry = hash_search(txn->sequences_hash,
-							(void *) &rlocator,
-							HASH_FIND,
-							&found);
+	/* If there's top-level transaction, search that one. */
+	txn = (txn->toptxn) ? txn->toptxn : txn;
 
-		/*
-		 * If we found an entry with matching relfilenode, we're done - we
-		 * have to treat the sequence change as transactional, and replay it
-		 * in the same (sub)transaction just like any other change.
-		 *
-		 * Optionally set XID of the (sub)xact that created the relfilenode.
-		 */
-		if (found)
-		{
-			if (xid)
-				*xid = entry->txn->xid;
+	/* transaction has no relfilenodes, can't be transactional */
+	if (!txn->sequences_hash)
+		return false;
 
-			break;
-		}
-	}
+	entry = hash_search(txn->sequences_hash,
+						(void *) &rlocator,
+						HASH_FIND,
+						&found);
 
-	return found;
+	if (!found)
+		return false;
+
+	if (xidout)
+		*xidout = entry->txn->xid;
+
+	return true;
 }
 
 /*
@@ -1146,7 +1144,7 @@ ReorderBufferQueueSequence(ReorderBuffer *rb, TransactionId xid,
 		change->data.sequence.tuple = tuplebuf;
 
 		/* lookup the XID for transaction that created the relfilenode */
-		ReorderBufferSequenceIsTransactional(rb, rlocator, &xid);
+		ReorderBufferSequenceIsTransactional(rb, rlocator, xid, &xid);
 
 		/* the XID should be valid for a transactional change */
 		Assert(TransactionIdIsValid(xid));
@@ -1172,7 +1170,7 @@ ReorderBufferQueueSequence(ReorderBuffer *rb, TransactionId xid,
 		Assert(TransactionIdIsValid(xid));
 
 		/* Make sure the sequence is not in any of the hash tables */
-		Assert(!ReorderBufferSequenceIsTransactional(rb, rlocator, NULL));
+		Assert(!ReorderBufferSequenceIsTransactional(rb, rlocator, xid, NULL));
 
 		txn = ReorderBufferTXNByXid(rb, xid, true, NULL, lsn, true);
 
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index 58a99b74060..a44a0f4dfb9 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -790,6 +790,7 @@ extern void ReorderBufferAddRelFileLocator(ReorderBuffer *rb, TransactionId xid,
 										   XLogRecPtr lsn, RelFileLocator rlocator);
 extern bool ReorderBufferSequenceIsTransactional(ReorderBuffer *rb,
 												 RelFileLocator locator,
-												 TransactionId *xid);
+												 TransactionId xidin,
+												 TransactionId *xidout);
 
 #endif
-- 
2.42.0

