On Tue, May 25, 2021 at 2:34 PM Dilip Kumar <dilipbal...@gmail.com> wrote:
>
> > When the transaction is streamed, I see:
> > ```
> > + opening a streamed block for transaction
> > + table public.toasted: INSERT: id[integer]:9001 other[text]:'bbb' 
> > data[text]:'ccc'
> > + table public.toasted: INSERT: id[integer]:9002 other[text]:'ddd' 
> > data[text]:'eee'
> > + table public.toasted: INSERT: id[integer]:9003 other[text]:'bar' 
> > data[text]:unchanged-toast-datum
> > <snipped>
> > ```
> >
> > For a non-streamed case, the `data[text]` column shows the actual data. 
> > That probably manifests into NULL data when downstream handles it.
>
> Yes, I am able to reproduce this, basically, until we get the last
> tuple of the multi insert we can not clear the toast data otherwise we
> can never form a complete tuple.  So the only possible fix I can think
> of is to consider the multi-insert WAL without the final multi-insert
> tuple as partial data then we will avoid streaming until we get the
> complete WAL of one multi-insert.  I am working on the patch to fix
> this, I will share that in some time.

The attached patch should fix the issue, now the output is like below

===
opening a streamed block for transaction
table public.toasted: INSERT: id[integer]:9001 other[text]:'bbb'
data[text]:'ccc'
 table public.toasted: INSERT: id[integer]:9002 other[text]:'ddd'
data[text]:'eee'
 table public.toasted: INSERT: id[integer]:9003 other[text]:'bar'
data[text]:'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
<repeat >
===

-- 
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com
From fc58da41802f966dd269679921a5daa33d21a291 Mon Sep 17 00:00:00 2001
From: Dilip Kumar <dilipkumar@localhost.localdomain>
Date: Tue, 25 May 2021 14:51:45 +0530
Subject: [PATCH v1] Fix bug while streaming the multi-insert toast changes

While processing the multi-insert we can not clean the toast untill
we get the last insert of the multi-insert.  So mark the transaction
incomplete for streaming if we get any multi-insert change, and keep
it set until we get the last tuple of the multi-insert.
---
 src/backend/replication/logical/reorderbuffer.c | 11 +++++++++++
 src/include/replication/reorderbuffer.h         | 11 ++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index b0ab91c..b715992 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -732,6 +732,17 @@ ReorderBufferProcessPartialChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	}
 
 	/*
+	 * Set the multi insert bit whenever we get the clear_toast_afterwards
+	 * as false otherwise reset it if this is set.
+	 */
+	if (!change->data.tp.clear_toast_afterwards)
+	{
+		toptxn->txn_flags |= RBTXN_HAS_MULTI_INSERT;
+	}
+	else if rbtxn_has_multi_insert(toptxn)
+		toptxn->txn_flags &= ~RBTXN_HAS_MULTI_INSERT;
+
+	/*
 	 * Stream the transaction if it is serialized before and the changes are
 	 * now complete in the top-level transaction.
 	 *
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index 53cdfa5..cd36a8d 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -176,6 +176,7 @@ typedef struct ReorderBufferChange
 #define RBTXN_HAS_SPEC_INSERT     0x0040
 #define RBTXN_PREPARE             0x0080
 #define RBTXN_SKIPPED_PREPARE	  0x0100
+#define RBTXN_HAS_MULTI_INSERT    0x0200
 
 /* Does the transaction have catalog changes? */
 #define rbtxn_has_catalog_changes(txn) \
@@ -214,11 +215,19 @@ typedef struct ReorderBufferChange
 ( \
 	((txn)->txn_flags & RBTXN_HAS_SPEC_INSERT) != 0 \
 )
+/*
+ * This transaction's changes has multi insert, without last
+ * multi insert tuple.
+ */
+#define rbtxn_has_multi_insert(txn) \
+( \
+	((txn)->txn_flags & RBTXN_HAS_MULTI_INSERT) != 0 \
+)
 
 /* Check whether this transaction has an incomplete change. */
 #define rbtxn_has_incomplete_tuple(txn) \
 ( \
-	rbtxn_has_toast_insert(txn) || rbtxn_has_spec_insert(txn) \
+	rbtxn_has_toast_insert(txn) || rbtxn_has_spec_insert(txn) || rbtxn_has_multi_insert(txn) \
 )
 
 /*
-- 
1.8.3.1

Reply via email to