From afcb7662e45f2f52cc62a4b06e05604ac97f70b5 Mon Sep 17 00:00:00 2001 From: Ajin Cherian Date: Tue, 30 Mar 2021 00:16:35 -0400 Subject: [PATCH v3] Make sure a prepare is sent when decoder detects a concurrent abort. While decoding a prepared transaction, and a concurrent abort of the transaction being decoded is detected, the decoding is stopped. But this fix makes sure that even if the decoding is aborted, the PREPARE is sent out. This ensures that when the ROLLBACK PREPARED is eventually sent downstream, there is a corresponding prepared transaction to rollback. --- doc/src/sgml/logicaldecoding.sgml | 12 ++++++++---- src/backend/replication/logical/reorderbuffer.c | 7 +++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/doc/src/sgml/logicaldecoding.sgml b/doc/src/sgml/logicaldecoding.sgml index 80eb96d..e3f6008 100644 --- a/doc/src/sgml/logicaldecoding.sgml +++ b/doc/src/sgml/logicaldecoding.sgml @@ -545,12 +545,16 @@ 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 PREPARE TRANSACTION will also be decoded if the output plugin callbacks needed for decoding - them are provided. It is possible that the current transaction which + them are provided. It is possible that the current prepared transaction which is being decoded is aborted concurrently via a ROLLBACK PREPARED 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 - ROLLBACK PREPARED. + be aborted too. All the changes of such a transaction are skipped once + the abort is detected and the prepare_cb callback is invoked. + This could result in a prepared transaction with incomplete changes, in which case + the concurrent_abort field of the passed + ReorderBufferTXN struct is set. + This is done so that eventually when the ROLLBACK PREPARED + is decoded, there is a corresponding prepared transaction with a matching gid. diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index 127f2c4..1442af1 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -2664,6 +2664,13 @@ ReorderBufferPrepare(ReorderBuffer *rb, TransactionId xid, ReorderBufferReplay(txn, rb, xid, txn->final_lsn, txn->end_lsn, txn->commit_time, txn->origin_id, txn->origin_lsn); + + /* + * If the transaction has been concurrently aborted, make sure we send + * prepare here. + */ + if (txn->concurrent_abort) + rb->prepare(rb, txn, txn->final_lsn); } /* -- 1.8.3.1