v4-0001-Ensure-to-send-a-prepare-after-we-detect-concurre.patch

application/octet-stream

Filename: v4-0001-Ensure-to-send-a-prepare-after-we-detect-concurre.patch
Type: application/octet-stream
Part: 0
Message: Re: [PATCH] add concurrent_abort callback for output plugin

Patch

Format: format-patch
Series: patch v4-0001
Subject: Ensure to send a prepare after we detect concurrent abort during decoding.
File+
doc/src/sgml/logicaldecoding.sgml 11 6
src/backend/replication/logical/reorderbuffer.c 8 0
From f6e973a6d79b867b1e6d23a9de945685200f1fa8 Mon Sep 17 00:00:00 2001
From: Amit Kapila <akapila@postgresql.org>
Date: Wed, 31 Mar 2021 09:49:03 +0530
Subject: [PATCH v4] Ensure to send a prepare after we detect concurrent abort
 during decoding.

It is possible that while decoding a prepared transaction, it gets aborted
concurrently via a ROLLBACK PREPARED command. In that case, we were
skipping all the changes and directly sending Rollback Prepared when we
find the same in WAL. However, the downstream has no idea of the GID of
such a transaction. So, ensure to send prepare even when a concurrent
abort is detected.

Author: Ajin Cherian
Reviewed-by: Markus Wanner, Amit Kapila
Discussion: https://postgr.es/m/f82133c6-6055-b400-7922-97dae9f2b50b@enterprisedb.com
---
 doc/src/sgml/logicaldecoding.sgml               | 17 +++++++++++------
 src/backend/replication/logical/reorderbuffer.c |  8 ++++++++
 2 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/doc/src/sgml/logicaldecoding.sgml b/doc/src/sgml/logicaldecoding.sgml
index da23f89ca32..f11d8aff13d 100644
--- a/doc/src/sgml/logicaldecoding.sgml
+++ b/doc/src/sgml/logicaldecoding.sgml
@@ -545,12 +545,17 @@ CREATE TABLE another_catalog_table(data text) WITH (user_catalog_table = true);
      executed within that transaction. A transaction that is prepared for
      a two-phase commit using <command>PREPARE TRANSACTION</command> will
      also be decoded if the output plugin callbacks needed for decoding
-     them are provided. It is possible that the current transaction which
-     is being decoded is aborted concurrently via a <command>ROLLBACK PREPARED</command>
-     command. In that case, the logical decoding of this transaction will
-     be aborted too. We will skip all the changes of such a transaction once
-     the abort is detected and abort the transaction when we read WAL for
-     <command>ROLLBACK PREPARED</command>.
+     them are provided. It is possible that the current prepared transaction
+     which is being decoded is aborted concurrently via a
+     <command>ROLLBACK PREPARED</command> command. In that case, the logical
+     decoding of this transaction will be aborted too. All the changes of such
+     a transaction are skipped once the abort is detected and the
+     <function>prepare_cb</function> callback is invoked. This could result in
+     a prepared transaction with incomplete changes, in which case the
+     <literal>concurrent_abort</literal> field of the passed
+     <literal>ReorderBufferTXN</literal> struct is set. This is done so that
+     eventually when the <command>ROLLBACK PREPARED</command> is decoded, there
+     is a corresponding prepared transaction with a matching gid.
     </para>
 
     <note>
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 127f2c4b168..52d06285a21 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -2664,6 +2664,14 @@ ReorderBufferPrepare(ReorderBuffer *rb, TransactionId xid,
 
 	ReorderBufferReplay(txn, rb, xid, txn->final_lsn, txn->end_lsn,
 						txn->commit_time, txn->origin_id, txn->origin_lsn);
+
+	/*
+	 * We send the prepare for the concurrently aborted xacts so that later
+	 * when rollback prepared is decoded and sent, the downstream should be
+	 * able to rollback such a xact. See comments atop DecodePrepare.
+	 */
+	if (txn->concurrent_abort)
+		rb->prepare(rb, txn, txn->final_lsn);
 }
 
 /*
-- 
2.28.0.windows.1