Remove unused fields in ReorderBufferTupleBuf

Started by Masahiko Sawadaover 2 years ago18 messages
#1Masahiko Sawada
sawada.mshk@gmail.com
1 attachment(s)

Hi,

ReorderBufferTupleBuf is defined as follow:

/* an individual tuple, stored in one chunk of memory */
typedef struct ReorderBufferTupleBuf
{
/* position in preallocated list */
slist_node node;

/* tuple header, the interesting bit for users of logical decoding */
HeapTupleData tuple;

/* pre-allocated size of tuple buffer, different from tuple size */
Size alloc_tuple_size;

/* actual tuple data follows */
} ReorderBufferTupleBuf;

However, node and alloc_tuple_size are not used at all. It seems an
oversight in commit a4ccc1cef5a, which introduced the generation
context and used it in logical decoding. I think we can remove them
(only on HEAD). I've attached the patch.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

Attachments:

v1-0001-Remove-unused-fields-in-ReorderBufferTupleBuf.patchapplication/octet-stream; name=v1-0001-Remove-unused-fields-in-ReorderBufferTupleBuf.patchDownload
From 8cf53ec4ff52a240efd99fb4b56f99a6111f4168 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Wed, 26 Jul 2023 10:44:51 +0900
Subject: [PATCH v1] Remove unused fields in ReorderBufferTupleBuf.

The fields node and alloc_tuple_size are no longer used. It's an
oversight in commit a4ccc1cef.

Not backpatched because of ABI compatibility.

Reviewed-by:
Discussion: https://postgr.es/m/
---
 src/include/replication/reorderbuffer.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index 1b9db22acb..baa3442a35 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -31,15 +31,9 @@ typedef enum
 /* an individual tuple, stored in one chunk of memory */
 typedef struct ReorderBufferTupleBuf
 {
-	/* position in preallocated list */
-	slist_node	node;
-
 	/* tuple header, the interesting bit for users of logical decoding */
 	HeapTupleData tuple;
 
-	/* pre-allocated size of tuple buffer, different from tuple size */
-	Size		alloc_tuple_size;
-
 	/* actual tuple data follows */
 } ReorderBufferTupleBuf;
 
-- 
2.31.1

#2Aleksander Alekseev
aleksander@timescale.com
In reply to: Masahiko Sawada (#1)
Re: Remove unused fields in ReorderBufferTupleBuf

Hi,

Thanks for the patch.

However, node and alloc_tuple_size are not used at all. It seems an
oversight in commit a4ccc1cef5a, which introduced the generation
context and used it in logical decoding. I think we can remove them
(only on HEAD). I've attached the patch.

I'm afraid it's a bit incomplete:

```
../src/backend/replication/logical/reorderbuffer.c: In function
‘ReorderBufferGetTupleBuf’:
../src/backend/replication/logical/reorderbuffer.c:565:14: error:
‘ReorderBufferTupleBuf’ has no member named ‘alloc_tuple_size’
565 | tuple->alloc_tuple_size = alloc_len;
| ^~
[829/1882] Compiling C object contrib/xml2/pgxml.so.p/xpath.c.o
```

On top of that IMO it doesn't make much sense to keep a one-field
wrapper structure. Perhaps we should get rid of it entirely and just
use HeapTupleData instead.

Thoughts?

--
Best regards,
Aleksander Alekseev

#3Aleksander Alekseev
aleksander@timescale.com
In reply to: Aleksander Alekseev (#2)
1 attachment(s)
Re: Remove unused fields in ReorderBufferTupleBuf

Hi,

I'm afraid it's a bit incomplete:

```
../src/backend/replication/logical/reorderbuffer.c: In function
‘ReorderBufferGetTupleBuf’:
../src/backend/replication/logical/reorderbuffer.c:565:14: error:
‘ReorderBufferTupleBuf’ has no member named ‘alloc_tuple_size’
565 | tuple->alloc_tuple_size = alloc_len;
| ^~
[829/1882] Compiling C object contrib/xml2/pgxml.so.p/xpath.c.o
```

Here is the corrected patch. I added it to the nearest CF [1]https://commitfest.postgresql.org/44/4461/.

On top of that IMO it doesn't make much sense to keep a one-field
wrapper structure. Perhaps we should get rid of it entirely and just
use HeapTupleData instead.

Thoughts?

Alternatively we could convert ReorderBufferTupleBufData macro to an
inlined function. At least it will add some type safety.

I didn't change anything in this respect in v2. Feedback from the
community would be much appreciated.

[1]: https://commitfest.postgresql.org/44/4461/

--
Best regards,
Aleksander Alekseev

Attachments:

v2-0001-Remove-unused-fields-in-ReorderBufferTupleBuf.patchapplication/octet-stream; name=v2-0001-Remove-unused-fields-in-ReorderBufferTupleBuf.patchDownload
From caff7965709b3c672265ca51613e1dac285c2497 Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <aleksander@timescale.com>
Date: Wed, 26 Jul 2023 16:15:38 +0300
Subject: [PATCH v2] Remove unused fields in ReorderBufferTupleBuf.

The fields node and alloc_tuple_size are no longer used. It's an
oversight in commit a4ccc1cef.

Not backpatched because of ABI compatibility.

Masahiko Sawada, reviewed by Aleksander Alekseev
Discussion: https://postgr.es/m/CAD21AoCvnuxiXXfRecp7g9+CeC35POQfhuQeJFr7_9u_Q5jc_Q@mail.gmail.com
---
 src/backend/replication/logical/reorderbuffer.c | 1 -
 src/include/replication/reorderbuffer.h         | 6 ------
 2 files changed, 7 deletions(-)

diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 26d252bd87..47913184e1 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -562,7 +562,6 @@ ReorderBufferGetTupleBuf(ReorderBuffer *rb, Size tuple_len)
 		MemoryContextAlloc(rb->tup_context,
 						   sizeof(ReorderBufferTupleBuf) +
 						   MAXIMUM_ALIGNOF + alloc_len);
-	tuple->alloc_tuple_size = alloc_len;
 	tuple->tuple.t_data = ReorderBufferTupleBufData(tuple);
 
 	return tuple;
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index 1b9db22acb..baa3442a35 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -31,15 +31,9 @@ typedef enum
 /* an individual tuple, stored in one chunk of memory */
 typedef struct ReorderBufferTupleBuf
 {
-	/* position in preallocated list */
-	slist_node	node;
-
 	/* tuple header, the interesting bit for users of logical decoding */
 	HeapTupleData tuple;
 
-	/* pre-allocated size of tuple buffer, different from tuple size */
-	Size		alloc_tuple_size;
-
 	/* actual tuple data follows */
 } ReorderBufferTupleBuf;
 
-- 
2.41.0

#4Aleksander Alekseev
aleksander@timescale.com
In reply to: Aleksander Alekseev (#3)
2 attachment(s)
Re: Remove unused fields in ReorderBufferTupleBuf

Hi,

Here is the corrected patch. I added it to the nearest CF [1].

I played a bit more with the patch. There was an idea to make
ReorderBufferTupleBufData an opaque structure known only within
reorderbyffer.c but it turned out that replication/logical/decode.c
accesses it directly so I abandoned that idea for now.

Alternatively we could convert ReorderBufferTupleBufData macro to an
inlined function. At least it will add some type safety.

Here is v3 that implements it too as a separate patch.

Apologies for the noise.

--
Best regards,
Aleksander Alekseev

Attachments:

v3-0001-Remove-unused-fields-in-ReorderBufferTupleBuf.patchapplication/octet-stream; name=v3-0001-Remove-unused-fields-in-ReorderBufferTupleBuf.patchDownload
From 5bc9a64da7a12a22c4783217ae19a11edf2d64bc Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <aleksander@timescale.com>
Date: Wed, 26 Jul 2023 16:15:38 +0300
Subject: [PATCH v3 1/2] Remove unused fields in ReorderBufferTupleBuf.

The fields node and alloc_tuple_size are no longer used. It's an
oversight in commit a4ccc1cef.

Not backpatched because of ABI compatibility.

Masahiko Sawada, reviewed by Aleksander Alekseev
Discussion: https://postgr.es/m/CAD21AoCvnuxiXXfRecp7g9+CeC35POQfhuQeJFr7_9u_Q5jc_Q@mail.gmail.com
---
 src/backend/replication/logical/reorderbuffer.c | 1 -
 src/include/replication/reorderbuffer.h         | 6 ------
 2 files changed, 7 deletions(-)

diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 26d252bd87..47913184e1 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -562,7 +562,6 @@ ReorderBufferGetTupleBuf(ReorderBuffer *rb, Size tuple_len)
 		MemoryContextAlloc(rb->tup_context,
 						   sizeof(ReorderBufferTupleBuf) +
 						   MAXIMUM_ALIGNOF + alloc_len);
-	tuple->alloc_tuple_size = alloc_len;
 	tuple->tuple.t_data = ReorderBufferTupleBufData(tuple);
 
 	return tuple;
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index 1b9db22acb..baa3442a35 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -31,15 +31,9 @@ typedef enum
 /* an individual tuple, stored in one chunk of memory */
 typedef struct ReorderBufferTupleBuf
 {
-	/* position in preallocated list */
-	slist_node	node;
-
 	/* tuple header, the interesting bit for users of logical decoding */
 	HeapTupleData tuple;
 
-	/* pre-allocated size of tuple buffer, different from tuple size */
-	Size		alloc_tuple_size;
-
 	/* actual tuple data follows */
 } ReorderBufferTupleBuf;
 
-- 
2.41.0

v3-0002-Replace-ReorderBufferTupleBufData-macro-with-a-fu.patchapplication/octet-stream; name=v3-0002-Replace-ReorderBufferTupleBufData-macro-with-a-fu.patchDownload
From a8ff4aba915a2f99a51883405589b3160264e622 Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <aleksander@timescale.com>
Date: Wed, 26 Jul 2023 16:26:33 +0300
Subject: [PATCH v3 2/2] Replace ReorderBufferTupleBufData() macro with a
 function

This adds a bit more type sefety without any likely impact to the performance.

Aleksander Alekseev, reviewed by TODO FIXME
Discussion: https://postgr.es/m/CAD21AoCvnuxiXXfRecp7g9+CeC35POQfhuQeJFr7_9u_Q5jc_Q@mail.gmail.com
---
 src/backend/replication/logical/reorderbuffer.c | 10 ++++++++++
 src/include/replication/reorderbuffer.h         |  4 ----
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 47913184e1..70796ad4f3 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -462,6 +462,16 @@ ReorderBufferReturnTXN(ReorderBuffer *rb, ReorderBufferTXN *txn)
 	pfree(txn);
 }
 
+/*
+ * Pointer to the data stored in a TupleBuf.
+ * Implemented as an inlined function for type safety.
+ */
+inline static HeapTupleHeader
+ReorderBufferTupleBufData(ReorderBufferTupleBuf* p)
+{
+	return (HeapTupleHeader) MAXALIGN(((char *) p) + sizeof(ReorderBufferTupleBuf));
+}
+
 /*
  * Get a fresh ReorderBufferChange.
  */
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index baa3442a35..c97c18109a 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -37,10 +37,6 @@ typedef struct ReorderBufferTupleBuf
 	/* actual tuple data follows */
 } ReorderBufferTupleBuf;
 
-/* pointer to the data stored in a TupleBuf */
-#define ReorderBufferTupleBufData(p) \
-	((HeapTupleHeader) MAXALIGN(((char *) p) + sizeof(ReorderBufferTupleBuf)))
-
 /*
  * Types of the change passed to a 'change' callback.
  *
-- 
2.41.0

#5Peter Smith
smithpb2250@gmail.com
In reply to: Aleksander Alekseev (#4)
Re: Remove unused fields in ReorderBufferTupleBuf

2024-01 Commitfest.

Hi, this patch was marked in CF as "Needs Review" [1]https://commitfest.postgresql.org/46/4461/, but there has
been no activity on this thread for 5+ months.

Do you wish to keep this open, or can you post something to elicit
more interest in reviews for the latest patch set? Otherwise, if
nothing happens then the CF entry will be closed ("Returned with
feedback") at the end of this CF.

======
[1]: https://commitfest.postgresql.org/46/4461/

Kind Regards,
Peter Smith.

#6Aleksander Alekseev
aleksander@timescale.com
In reply to: Peter Smith (#5)
Re: Remove unused fields in ReorderBufferTupleBuf

Hi,

Hi, this patch was marked in CF as "Needs Review" [1], but there has
been no activity on this thread for 5+ months.

Do you wish to keep this open, or can you post something to elicit
more interest in reviews for the latest patch set? Otherwise, if
nothing happens then the CF entry will be closed ("Returned with
feedback") at the end of this CF.

I don't think that closing CF entries only due to inactivity is a good
practice, nor something we typically do. When someone will have spare
time this person will (hopefully) review the code.

--
Best regards,
Aleksander Alekseev

#7Amit Kapila
amit.kapila16@gmail.com
In reply to: Aleksander Alekseev (#4)
Re: Remove unused fields in ReorderBufferTupleBuf

On Wed, Jul 26, 2023 at 7:22 PM Aleksander Alekseev
<aleksander@timescale.com> wrote:

Here is the corrected patch. I added it to the nearest CF [1].

I played a bit more with the patch. There was an idea to make
ReorderBufferTupleBufData an opaque structure known only within
reorderbyffer.c but it turned out that replication/logical/decode.c
accesses it directly so I abandoned that idea for now.

Alternatively we could convert ReorderBufferTupleBufData macro to an
inlined function. At least it will add some type safety.

Here is v3 that implements it too as a separate patch.

But why didn't you pursue your idea of getting rid of the wrapper
structure ReorderBufferTupleBuf which after this patch will have just
one member? I think there could be hassles in backpatching bug-fixes
in some cases but in the longer run it would make the code look clean.

--
With Regards,
Amit Kapila.

#8Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Aleksander Alekseev (#6)
Re: Remove unused fields in ReorderBufferTupleBuf

On Mon, Jan 22, 2024 at 4:17 PM Aleksander Alekseev
<aleksander@timescale.com> wrote:

Hi,

Hi, this patch was marked in CF as "Needs Review" [1], but there has
been no activity on this thread for 5+ months.

Do you wish to keep this open, or can you post something to elicit
more interest in reviews for the latest patch set? Otherwise, if
nothing happens then the CF entry will be closed ("Returned with
feedback") at the end of this CF.

I don't think that closing CF entries only due to inactivity is a good
practice, nor something we typically do. When someone will have spare
time this person will (hopefully) review the code.

Agree. IMHO, a patch not picked up by anyone doesn't mean it's the
author's problem to mark it "Returned with feedback". And, the timing
to mark things this way is not quite right as we are getting close to
the PG17 release. The patch may be fixing a problem (like the one
that's closed due to inactivity
https://commitfest.postgresql.org/46/3503/) or may be a feature or an
improvement that no reviewer/committer has had a chance to look at.

I think a new label such as "Returned due to lack of interest" or
"Returned due to disinterest" (or some better wording) helps
reviewers/committers to pick things up. This new label can be
attributed to the class of patches for which initially there's some
positive feedback on the idea, the patch is being kept latest, but
finds no one to get it reviewed for say X number of months.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#9Aleksander Alekseev
aleksander@timescale.com
In reply to: Amit Kapila (#7)
1 attachment(s)
Re: Remove unused fields in ReorderBufferTupleBuf

Hi,

I played a bit more with the patch. There was an idea to make
ReorderBufferTupleBufData an opaque structure known only within
reorderbyffer.c but it turned out that replication/logical/decode.c
accesses it directly so I abandoned that idea for now.

Alternatively we could convert ReorderBufferTupleBufData macro to an
inlined function. At least it will add some type safety.

Here is v3 that implements it too as a separate patch.

But why didn't you pursue your idea of getting rid of the wrapper
structure ReorderBufferTupleBuf which after this patch will have just
one member? I think there could be hassles in backpatching bug-fixes
in some cases but in the longer run it would make the code look clean.

Indeed. In fact turned out that I suggested the same above but
apparently forgot:

On top of that IMO it doesn't make much sense to keep a one-field
wrapper structure. Perhaps we should get rid of it entirely and just
use HeapTupleData instead.

After actually trying the refactoring I agree that the code becomes
cleaner and it's going to be beneficial in the long run. Here is the
patch.

--
Best regards,
Aleksander Alekseev

Attachments:

v4-0001-Remove-ReorderBufferTupleBuf-structure.patchapplication/octet-stream; name=v4-0001-Remove-ReorderBufferTupleBuf-structure.patchDownload
From ac9ed2f7d99dd157032efb17889e77b182aee6e3 Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <aleksander@timescale.com>
Date: Wed, 26 Jul 2023 16:15:38 +0300
Subject: [PATCH v4] Remove ReorderBufferTupleBuf structure

The fields 'node' and 'alloc_tuple_size' of ReorderBufferTupleBuf structure
are no longer used, which leaves only 'tuple' field. Since there is little
sense to keep a one-field structure, remove ReorderBufferTupleBuf altogether
and refactor the code accordingly.

Not backpatched because of ABI change.

Aleksander Alekseev, based on the report and patch by Masahiko Sawada.
Reviewed by Amit Kapila.
Discussion: https://postgr.es/m/CAD21AoCvnuxiXXfRecp7g9+CeC35POQfhuQeJFr7_9u_Q5jc_Q@mail.gmail.com
---
 contrib/test_decoding/test_decoding.c         |  8 +-
 src/backend/replication/logical/decode.c      | 28 +++---
 .../replication/logical/reorderbuffer.c       | 92 +++++++++----------
 src/backend/replication/pgoutput/pgoutput.c   |  4 +-
 src/include/replication/reorderbuffer.h       | 39 +++-----
 src/tools/pgindent/typedefs.list              |  1 -
 6 files changed, 75 insertions(+), 97 deletions(-)

diff --git a/contrib/test_decoding/test_decoding.c b/contrib/test_decoding/test_decoding.c
index 4f4f51a89c..7c50d13969 100644
--- a/contrib/test_decoding/test_decoding.c
+++ b/contrib/test_decoding/test_decoding.c
@@ -640,7 +640,7 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 				appendStringInfoString(ctx->out, " (no-tuple-data)");
 			else
 				tuple_to_stringinfo(ctx->out, tupdesc,
-									&change->data.tp.newtuple->tuple,
+									change->data.tp.newtuple,
 									false);
 			break;
 		case REORDER_BUFFER_CHANGE_UPDATE:
@@ -649,7 +649,7 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 			{
 				appendStringInfoString(ctx->out, " old-key:");
 				tuple_to_stringinfo(ctx->out, tupdesc,
-									&change->data.tp.oldtuple->tuple,
+									change->data.tp.oldtuple,
 									true);
 				appendStringInfoString(ctx->out, " new-tuple:");
 			}
@@ -658,7 +658,7 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 				appendStringInfoString(ctx->out, " (no-tuple-data)");
 			else
 				tuple_to_stringinfo(ctx->out, tupdesc,
-									&change->data.tp.newtuple->tuple,
+									change->data.tp.newtuple,
 									false);
 			break;
 		case REORDER_BUFFER_CHANGE_DELETE:
@@ -670,7 +670,7 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 			/* In DELETE, only the replica identity is present; display that */
 			else
 				tuple_to_stringinfo(ctx->out, tupdesc,
-									&change->data.tp.oldtuple->tuple,
+									change->data.tp.oldtuple,
 									true);
 			break;
 		default:
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index 6a0f22b209..760bc86a0b 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -62,7 +62,7 @@ static void DecodePrepare(LogicalDecodingContext *ctx, XLogRecordBuffer *buf,
 
 
 /* common function to decode tuples */
-static void DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple);
+static void DecodeXLogTuple(char *data, Size len, HeapTuple tuple);
 
 /* helper functions for decoding transactions */
 static inline bool FilterPrepare(LogicalDecodingContext *ctx,
@@ -155,7 +155,7 @@ xlog_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
 		case XLOG_PARAMETER_CHANGE:
 			{
 				xl_parameter_change *xlrec =
-					(xl_parameter_change *) XLogRecGetData(buf->record);
+				(xl_parameter_change *) XLogRecGetData(buf->record);
 
 				/*
 				 * If wal_level on the primary is reduced to less than
@@ -1152,7 +1152,7 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
 		ReorderBufferChange *change;
 		xl_multi_insert_tuple *xlhdr;
 		int			datalen;
-		ReorderBufferTupleBuf *tuple;
+		HeapTuple	tuple;
 		HeapTupleHeader header;
 
 		change = ReorderBufferGetChange(ctx->reorder);
@@ -1169,21 +1169,21 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
 			ReorderBufferGetTupleBuf(ctx->reorder, datalen);
 
 		tuple = change->data.tp.newtuple;
-		header = tuple->tuple.t_data;
+		header = tuple->t_data;
 
 		/* not a disk based tuple */
-		ItemPointerSetInvalid(&tuple->tuple.t_self);
+		ItemPointerSetInvalid(&tuple->t_self);
 
 		/*
 		 * We can only figure this out after reassembling the transactions.
 		 */
-		tuple->tuple.t_tableOid = InvalidOid;
+		tuple->t_tableOid = InvalidOid;
 
-		tuple->tuple.t_len = datalen + SizeofHeapTupleHeader;
+		tuple->t_len = datalen + SizeofHeapTupleHeader;
 
 		memset(header, 0, SizeofHeapTupleHeader);
 
-		memcpy((char *) tuple->tuple.t_data + SizeofHeapTupleHeader,
+		memcpy((char *) tuple->t_data + SizeofHeapTupleHeader,
 			   (char *) data,
 			   datalen);
 		header->t_infomask = xlhdr->t_infomask;
@@ -1253,7 +1253,7 @@ DecodeSpecConfirm(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
  * computed outside as they are record specific.
  */
 static void
-DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple)
+DecodeXLogTuple(char *data, Size len, HeapTuple tuple)
 {
 	xl_heap_header xlhdr;
 	int			datalen = len - SizeOfHeapHeader;
@@ -1261,14 +1261,14 @@ DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple)
 
 	Assert(datalen >= 0);
 
-	tuple->tuple.t_len = datalen + SizeofHeapTupleHeader;
-	header = tuple->tuple.t_data;
+	tuple->t_len = datalen + SizeofHeapTupleHeader;
+	header = tuple->t_data;
 
 	/* not a disk based tuple */
-	ItemPointerSetInvalid(&tuple->tuple.t_self);
+	ItemPointerSetInvalid(&tuple->t_self);
 
 	/* we can only figure this out after reassembling the transactions */
-	tuple->tuple.t_tableOid = InvalidOid;
+	tuple->t_tableOid = InvalidOid;
 
 	/* data is not stored aligned, copy to aligned storage */
 	memcpy((char *) &xlhdr,
@@ -1277,7 +1277,7 @@ DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple)
 
 	memset(header, 0, SizeofHeapTupleHeader);
 
-	memcpy(((char *) tuple->tuple.t_data) + SizeofHeapTupleHeader,
+	memcpy(((char *) tuple->t_data) + SizeofHeapTupleHeader,
 		   data + SizeOfHeapHeader,
 		   datalen);
 
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index d1334ffb55..d62a0758e9 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -498,13 +498,13 @@ ReorderBufferReturnChange(ReorderBuffer *rb, ReorderBufferChange *change,
 		case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
 			if (change->data.tp.newtuple)
 			{
-				ReorderBufferReturnTupleBuf(rb, change->data.tp.newtuple);
+				ReorderBufferReturnTupleBuf(change->data.tp.newtuple);
 				change->data.tp.newtuple = NULL;
 			}
 
 			if (change->data.tp.oldtuple)
 			{
-				ReorderBufferReturnTupleBuf(rb, change->data.tp.oldtuple);
+				ReorderBufferReturnTupleBuf(change->data.tp.oldtuple);
 				change->data.tp.oldtuple = NULL;
 			}
 			break;
@@ -547,36 +547,26 @@ ReorderBufferReturnChange(ReorderBuffer *rb, ReorderBufferChange *change,
 }
 
 /*
- * Get a fresh ReorderBufferTupleBuf fitting at least a tuple of size
+ * Get a fresh HeapTuple fitting at least a tuple of size
  * tuple_len (excluding header overhead).
  */
-ReorderBufferTupleBuf *
+HeapTuple
 ReorderBufferGetTupleBuf(ReorderBuffer *rb, Size tuple_len)
 {
-	ReorderBufferTupleBuf *tuple;
+	HeapTuple tuple;
 	Size		alloc_len;
 
-	alloc_len = tuple_len + SizeofHeapTupleHeader;
+	alloc_len = tuple_len + HEAPTUPLESIZE;
 
-	tuple = (ReorderBufferTupleBuf *)
+	tuple = (HeapTuple)
 		MemoryContextAlloc(rb->tup_context,
-						   sizeof(ReorderBufferTupleBuf) +
+						   HEAPTUPLESIZE +
 						   MAXIMUM_ALIGNOF + alloc_len);
-	tuple->alloc_tuple_size = alloc_len;
-	tuple->tuple.t_data = ReorderBufferTupleBufData(tuple);
+	tuple->t_data = (HeapTupleHeader)((char *)tuple + HEAPTUPLESIZE);
 
 	return tuple;
 }
 
-/*
- * Free a ReorderBufferTupleBuf.
- */
-void
-ReorderBufferReturnTupleBuf(ReorderBuffer *rb, ReorderBufferTupleBuf *tuple)
-{
-	pfree(tuple);
-}
-
 /*
  * Get an array for relids of truncated relations.
  *
@@ -3759,8 +3749,8 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 		case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
 			{
 				char	   *data;
-				ReorderBufferTupleBuf *oldtup,
-						   *newtup;
+				HeapTuple   oldtup,
+						    newtup;
 				Size		oldlen = 0;
 				Size		newlen = 0;
 
@@ -3770,14 +3760,14 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 				if (oldtup)
 				{
 					sz += sizeof(HeapTupleData);
-					oldlen = oldtup->tuple.t_len;
+					oldlen = oldtup->t_len;
 					sz += oldlen;
 				}
 
 				if (newtup)
 				{
 					sz += sizeof(HeapTupleData);
-					newlen = newtup->tuple.t_len;
+					newlen = newtup->t_len;
 					sz += newlen;
 				}
 
@@ -3790,19 +3780,19 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 
 				if (oldlen)
 				{
-					memcpy(data, &oldtup->tuple, sizeof(HeapTupleData));
+					memcpy(data, oldtup, sizeof(HeapTupleData));
 					data += sizeof(HeapTupleData);
 
-					memcpy(data, oldtup->tuple.t_data, oldlen);
+					memcpy(data, oldtup->t_data, oldlen);
 					data += oldlen;
 				}
 
 				if (newlen)
 				{
-					memcpy(data, &newtup->tuple, sizeof(HeapTupleData));
+					memcpy(data, newtup, sizeof(HeapTupleData));
 					data += sizeof(HeapTupleData);
 
-					memcpy(data, newtup->tuple.t_data, newlen);
+					memcpy(data, newtup->t_data, newlen);
 					data += newlen;
 				}
 				break;
@@ -4118,8 +4108,8 @@ ReorderBufferChangeSize(ReorderBufferChange *change)
 		case REORDER_BUFFER_CHANGE_DELETE:
 		case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
 			{
-				ReorderBufferTupleBuf *oldtup,
-						   *newtup;
+				HeapTuple   oldtup,
+						    newtup;
 				Size		oldlen = 0;
 				Size		newlen = 0;
 
@@ -4129,14 +4119,14 @@ ReorderBufferChangeSize(ReorderBufferChange *change)
 				if (oldtup)
 				{
 					sz += sizeof(HeapTupleData);
-					oldlen = oldtup->tuple.t_len;
+					oldlen = oldtup->t_len;
 					sz += oldlen;
 				}
 
 				if (newtup)
 				{
 					sz += sizeof(HeapTupleData);
-					newlen = newtup->tuple.t_len;
+					newlen = newtup->t_len;
 					sz += newlen;
 				}
 
@@ -4365,16 +4355,16 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 					ReorderBufferGetTupleBuf(rb, tuplelen - SizeofHeapTupleHeader);
 
 				/* restore ->tuple */
-				memcpy(&change->data.tp.oldtuple->tuple, data,
+				memcpy(change->data.tp.oldtuple, data,
 					   sizeof(HeapTupleData));
 				data += sizeof(HeapTupleData);
 
 				/* reset t_data pointer into the new tuplebuf */
-				change->data.tp.oldtuple->tuple.t_data =
-					ReorderBufferTupleBufData(change->data.tp.oldtuple);
+				change->data.tp.oldtuple->t_data =
+					(HeapTupleHeader)((char*)change->data.tp.oldtuple + HEAPTUPLESIZE);
 
 				/* restore tuple data itself */
-				memcpy(change->data.tp.oldtuple->tuple.t_data, data, tuplelen);
+				memcpy(change->data.tp.oldtuple->t_data, data, tuplelen);
 				data += tuplelen;
 			}
 
@@ -4390,16 +4380,16 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 					ReorderBufferGetTupleBuf(rb, tuplelen - SizeofHeapTupleHeader);
 
 				/* restore ->tuple */
-				memcpy(&change->data.tp.newtuple->tuple, data,
+				memcpy(change->data.tp.newtuple, data,
 					   sizeof(HeapTupleData));
 				data += sizeof(HeapTupleData);
 
 				/* reset t_data pointer into the new tuplebuf */
-				change->data.tp.newtuple->tuple.t_data =
-					ReorderBufferTupleBufData(change->data.tp.newtuple);
+				change->data.tp.newtuple->t_data =
+					(HeapTupleHeader)((char*)change->data.tp.newtuple + HEAPTUPLESIZE);
 
 				/* restore tuple data itself */
-				memcpy(change->data.tp.newtuple->tuple.t_data, data, tuplelen);
+				memcpy(change->data.tp.newtuple->t_data, data, tuplelen);
 				data += tuplelen;
 			}
 
@@ -4646,7 +4636,7 @@ ReorderBufferToastAppendChunk(ReorderBuffer *rb, ReorderBufferTXN *txn,
 							  Relation relation, ReorderBufferChange *change)
 {
 	ReorderBufferToastEnt *ent;
-	ReorderBufferTupleBuf *newtup;
+	HeapTuple newtup;
 	bool		found;
 	int32		chunksize;
 	bool		isnull;
@@ -4661,9 +4651,9 @@ ReorderBufferToastAppendChunk(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	Assert(IsToastRelation(relation));
 
 	newtup = change->data.tp.newtuple;
-	chunk_id = DatumGetObjectId(fastgetattr(&newtup->tuple, 1, desc, &isnull));
+	chunk_id = DatumGetObjectId(fastgetattr(newtup, 1, desc, &isnull));
 	Assert(!isnull);
-	chunk_seq = DatumGetInt32(fastgetattr(&newtup->tuple, 2, desc, &isnull));
+	chunk_seq = DatumGetInt32(fastgetattr(newtup, 2, desc, &isnull));
 	Assert(!isnull);
 
 	ent = (ReorderBufferToastEnt *)
@@ -4686,7 +4676,7 @@ ReorderBufferToastAppendChunk(ReorderBuffer *rb, ReorderBufferTXN *txn,
 		elog(ERROR, "got sequence entry %d for toast chunk %u instead of seq %d",
 			 chunk_seq, chunk_id, ent->last_chunk_seq + 1);
 
-	chunk = DatumGetPointer(fastgetattr(&newtup->tuple, 3, desc, &isnull));
+	chunk = DatumGetPointer(fastgetattr(newtup, 3, desc, &isnull));
 	Assert(!isnull);
 
 	/* calculate size so we can allocate the right size at once later */
@@ -4737,7 +4727,7 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	Relation	toast_rel;
 	TupleDesc	toast_desc;
 	MemoryContext oldcontext;
-	ReorderBufferTupleBuf *newtup;
+	HeapTuple newtup;
 	Size		old_size;
 
 	/* no toast tuples changed */
@@ -4777,7 +4767,7 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
 
 	newtup = change->data.tp.newtuple;
 
-	heap_deform_tuple(&newtup->tuple, desc, attrs, isnull);
+	heap_deform_tuple(newtup, desc, attrs, isnull);
 
 	for (natt = 0; natt < desc->natts; natt++)
 	{
@@ -4842,12 +4832,12 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
 		{
 			bool		cisnull;
 			ReorderBufferChange *cchange;
-			ReorderBufferTupleBuf *ctup;
+			HeapTuple   ctup;
 			Pointer		chunk;
 
 			cchange = dlist_container(ReorderBufferChange, node, it.cur);
 			ctup = cchange->data.tp.newtuple;
-			chunk = DatumGetPointer(fastgetattr(&ctup->tuple, 3, toast_desc, &cisnull));
+			chunk = DatumGetPointer(fastgetattr(ctup, 3, toast_desc, &cisnull));
 
 			Assert(!cisnull);
 			Assert(!VARATT_IS_EXTERNAL(chunk));
@@ -4882,11 +4872,11 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	 * the tuplebuf because attrs[] will point back into the current content.
 	 */
 	tmphtup = heap_form_tuple(desc, attrs, isnull);
-	Assert(newtup->tuple.t_len <= MaxHeapTupleSize);
-	Assert(ReorderBufferTupleBufData(newtup) == newtup->tuple.t_data);
+	Assert(newtup->t_len <= MaxHeapTupleSize);
+	Assert(newtup->t_data == (HeapTupleHeader)((char*)newtup + HEAPTUPLESIZE));
 
-	memcpy(newtup->tuple.t_data, tmphtup->t_data, tmphtup->t_len);
-	newtup->tuple.t_len = tmphtup->t_len;
+	memcpy(newtup->t_data, tmphtup->t_data, tmphtup->t_len);
+	newtup->t_len = tmphtup->t_len;
 
 	/*
 	 * free resources we won't further need, more persistent stuff will be
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 425238187f..998f92d671 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -1473,7 +1473,7 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 	if (change->data.tp.oldtuple)
 	{
 		old_slot = relentry->old_slot;
-		ExecStoreHeapTuple(&change->data.tp.oldtuple->tuple, old_slot, false);
+		ExecStoreHeapTuple(change->data.tp.oldtuple, old_slot, false);
 
 		/* Convert tuple if needed. */
 		if (relentry->attrmap)
@@ -1488,7 +1488,7 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 	if (change->data.tp.newtuple)
 	{
 		new_slot = relentry->new_slot;
-		ExecStoreHeapTuple(&change->data.tp.newtuple->tuple, new_slot, false);
+		ExecStoreHeapTuple(change->data.tp.newtuple, new_slot, false);
 
 		/* Convert tuple if needed. */
 		if (relentry->attrmap)
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index 3e232c6c27..efa57f2bec 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -28,25 +28,6 @@ typedef enum
 	DEBUG_LOGICAL_REP_STREAMING_IMMEDIATE,
 }			DebugLogicalRepStreamingMode;
 
-/* an individual tuple, stored in one chunk of memory */
-typedef struct ReorderBufferTupleBuf
-{
-	/* position in preallocated list */
-	slist_node	node;
-
-	/* tuple header, the interesting bit for users of logical decoding */
-	HeapTupleData tuple;
-
-	/* pre-allocated size of tuple buffer, different from tuple size */
-	Size		alloc_tuple_size;
-
-	/* actual tuple data follows */
-} ReorderBufferTupleBuf;
-
-/* pointer to the data stored in a TupleBuf */
-#define ReorderBufferTupleBufData(p) \
-	((HeapTupleHeader) MAXALIGN(((char *) p) + sizeof(ReorderBufferTupleBuf)))
-
 /*
  * Types of the change passed to a 'change' callback.
  *
@@ -114,9 +95,9 @@ typedef struct ReorderBufferChange
 			bool		clear_toast_afterwards;
 
 			/* valid for DELETE || UPDATE */
-			ReorderBufferTupleBuf *oldtuple;
+			HeapTuple	oldtuple;
 			/* valid for INSERT || UPDATE */
-			ReorderBufferTupleBuf *newtuple;
+			HeapTuple	newtuple;
 		}			tp;
 
 		/*
@@ -678,10 +659,18 @@ struct ReorderBuffer
 extern ReorderBuffer *ReorderBufferAllocate(void);
 extern void ReorderBufferFree(ReorderBuffer *rb);
 
-extern ReorderBufferTupleBuf *ReorderBufferGetTupleBuf(ReorderBuffer *rb,
-													   Size tuple_len);
-extern void ReorderBufferReturnTupleBuf(ReorderBuffer *rb,
-										ReorderBufferTupleBuf *tuple);
+extern HeapTuple ReorderBufferGetTupleBuf(ReorderBuffer *rb,
+										  Size tuple_len);
+
+/*
+ * Free HeapTuple returned by ReorderBufferGetTupleBuf().
+ */
+static inline void
+ReorderBufferReturnTupleBuf(HeapTuple tuple)
+{
+	pfree(tuple);
+}
+
 extern ReorderBufferChange *ReorderBufferGetChange(ReorderBuffer *rb);
 extern void ReorderBufferReturnChange(ReorderBuffer *rb,
 									  ReorderBufferChange *change, bool upd_mem);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 7e866e3c3d..dc3b0ef871 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2351,7 +2351,6 @@ ReorderBufferStreamTruncateCB
 ReorderBufferTXN
 ReorderBufferTXNByIdEnt
 ReorderBufferToastEnt
-ReorderBufferTupleBuf
 ReorderBufferTupleCidEnt
 ReorderBufferTupleCidKey
 ReorderBufferUpdateProgressTxnCB
-- 
2.43.0

#10Aleksander Alekseev
aleksander@timescale.com
In reply to: Aleksander Alekseev (#9)
1 attachment(s)
Re: Remove unused fields in ReorderBufferTupleBuf

Hi,

But why didn't you pursue your idea of getting rid of the wrapper
structure ReorderBufferTupleBuf which after this patch will have just
one member? I think there could be hassles in backpatching bug-fixes
in some cases but in the longer run it would make the code look clean.

Indeed. In fact turned out that I suggested the same above but
apparently forgot:

On top of that IMO it doesn't make much sense to keep a one-field
wrapper structure. Perhaps we should get rid of it entirely and just
use HeapTupleData instead.

After actually trying the refactoring I agree that the code becomes
cleaner and it's going to be beneficial in the long run. Here is the
patch.

I did a mistake in v4:

```
-    alloc_len = tuple_len + SizeofHeapTupleHeader;
+    alloc_len = tuple_len + HEAPTUPLESIZE;
```

Here is the corrected patch.

--
Best regards,
Aleksander Alekseev

Attachments:

v5-0001-Remove-ReorderBufferTupleBuf-structure.patchapplication/octet-stream; name=v5-0001-Remove-ReorderBufferTupleBuf-structure.patchDownload
From 26579f0cfc848ba8ba2ccd636c3f0643ef0e1688 Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <aleksander@timescale.com>
Date: Wed, 26 Jul 2023 16:15:38 +0300
Subject: [PATCH v5] Remove ReorderBufferTupleBuf structure

The fields 'node' and 'alloc_tuple_size' of ReorderBufferTupleBuf structure
are no longer used, which leaves only 'tuple' field. Since there is little
sense to keep a one-field structure, remove ReorderBufferTupleBuf altogether
and refactor the code accordingly.

Not backpatched because of ABI change.

Aleksander Alekseev, based on the report and patch by Masahiko Sawada.
Reviewed by Amit Kapila.
Discussion: https://postgr.es/m/CAD21AoCvnuxiXXfRecp7g9+CeC35POQfhuQeJFr7_9u_Q5jc_Q@mail.gmail.com
---
 contrib/test_decoding/test_decoding.c         |  8 +-
 src/backend/replication/logical/decode.c      | 28 +++---
 .../replication/logical/reorderbuffer.c       | 90 +++++++++----------
 src/backend/replication/pgoutput/pgoutput.c   |  4 +-
 src/include/replication/reorderbuffer.h       | 39 +++-----
 src/tools/pgindent/typedefs.list              |  1 -
 6 files changed, 74 insertions(+), 96 deletions(-)

diff --git a/contrib/test_decoding/test_decoding.c b/contrib/test_decoding/test_decoding.c
index 4f4f51a89c..7c50d13969 100644
--- a/contrib/test_decoding/test_decoding.c
+++ b/contrib/test_decoding/test_decoding.c
@@ -640,7 +640,7 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 				appendStringInfoString(ctx->out, " (no-tuple-data)");
 			else
 				tuple_to_stringinfo(ctx->out, tupdesc,
-									&change->data.tp.newtuple->tuple,
+									change->data.tp.newtuple,
 									false);
 			break;
 		case REORDER_BUFFER_CHANGE_UPDATE:
@@ -649,7 +649,7 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 			{
 				appendStringInfoString(ctx->out, " old-key:");
 				tuple_to_stringinfo(ctx->out, tupdesc,
-									&change->data.tp.oldtuple->tuple,
+									change->data.tp.oldtuple,
 									true);
 				appendStringInfoString(ctx->out, " new-tuple:");
 			}
@@ -658,7 +658,7 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 				appendStringInfoString(ctx->out, " (no-tuple-data)");
 			else
 				tuple_to_stringinfo(ctx->out, tupdesc,
-									&change->data.tp.newtuple->tuple,
+									change->data.tp.newtuple,
 									false);
 			break;
 		case REORDER_BUFFER_CHANGE_DELETE:
@@ -670,7 +670,7 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 			/* In DELETE, only the replica identity is present; display that */
 			else
 				tuple_to_stringinfo(ctx->out, tupdesc,
-									&change->data.tp.oldtuple->tuple,
+									change->data.tp.oldtuple,
 									true);
 			break;
 		default:
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index 6a0f22b209..760bc86a0b 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -62,7 +62,7 @@ static void DecodePrepare(LogicalDecodingContext *ctx, XLogRecordBuffer *buf,
 
 
 /* common function to decode tuples */
-static void DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple);
+static void DecodeXLogTuple(char *data, Size len, HeapTuple tuple);
 
 /* helper functions for decoding transactions */
 static inline bool FilterPrepare(LogicalDecodingContext *ctx,
@@ -155,7 +155,7 @@ xlog_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
 		case XLOG_PARAMETER_CHANGE:
 			{
 				xl_parameter_change *xlrec =
-					(xl_parameter_change *) XLogRecGetData(buf->record);
+				(xl_parameter_change *) XLogRecGetData(buf->record);
 
 				/*
 				 * If wal_level on the primary is reduced to less than
@@ -1152,7 +1152,7 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
 		ReorderBufferChange *change;
 		xl_multi_insert_tuple *xlhdr;
 		int			datalen;
-		ReorderBufferTupleBuf *tuple;
+		HeapTuple	tuple;
 		HeapTupleHeader header;
 
 		change = ReorderBufferGetChange(ctx->reorder);
@@ -1169,21 +1169,21 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
 			ReorderBufferGetTupleBuf(ctx->reorder, datalen);
 
 		tuple = change->data.tp.newtuple;
-		header = tuple->tuple.t_data;
+		header = tuple->t_data;
 
 		/* not a disk based tuple */
-		ItemPointerSetInvalid(&tuple->tuple.t_self);
+		ItemPointerSetInvalid(&tuple->t_self);
 
 		/*
 		 * We can only figure this out after reassembling the transactions.
 		 */
-		tuple->tuple.t_tableOid = InvalidOid;
+		tuple->t_tableOid = InvalidOid;
 
-		tuple->tuple.t_len = datalen + SizeofHeapTupleHeader;
+		tuple->t_len = datalen + SizeofHeapTupleHeader;
 
 		memset(header, 0, SizeofHeapTupleHeader);
 
-		memcpy((char *) tuple->tuple.t_data + SizeofHeapTupleHeader,
+		memcpy((char *) tuple->t_data + SizeofHeapTupleHeader,
 			   (char *) data,
 			   datalen);
 		header->t_infomask = xlhdr->t_infomask;
@@ -1253,7 +1253,7 @@ DecodeSpecConfirm(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
  * computed outside as they are record specific.
  */
 static void
-DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple)
+DecodeXLogTuple(char *data, Size len, HeapTuple tuple)
 {
 	xl_heap_header xlhdr;
 	int			datalen = len - SizeOfHeapHeader;
@@ -1261,14 +1261,14 @@ DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple)
 
 	Assert(datalen >= 0);
 
-	tuple->tuple.t_len = datalen + SizeofHeapTupleHeader;
-	header = tuple->tuple.t_data;
+	tuple->t_len = datalen + SizeofHeapTupleHeader;
+	header = tuple->t_data;
 
 	/* not a disk based tuple */
-	ItemPointerSetInvalid(&tuple->tuple.t_self);
+	ItemPointerSetInvalid(&tuple->t_self);
 
 	/* we can only figure this out after reassembling the transactions */
-	tuple->tuple.t_tableOid = InvalidOid;
+	tuple->t_tableOid = InvalidOid;
 
 	/* data is not stored aligned, copy to aligned storage */
 	memcpy((char *) &xlhdr,
@@ -1277,7 +1277,7 @@ DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple)
 
 	memset(header, 0, SizeofHeapTupleHeader);
 
-	memcpy(((char *) tuple->tuple.t_data) + SizeofHeapTupleHeader,
+	memcpy(((char *) tuple->t_data) + SizeofHeapTupleHeader,
 		   data + SizeOfHeapHeader,
 		   datalen);
 
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index d1334ffb55..39a69ae07b 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -498,13 +498,13 @@ ReorderBufferReturnChange(ReorderBuffer *rb, ReorderBufferChange *change,
 		case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
 			if (change->data.tp.newtuple)
 			{
-				ReorderBufferReturnTupleBuf(rb, change->data.tp.newtuple);
+				ReorderBufferReturnTupleBuf(change->data.tp.newtuple);
 				change->data.tp.newtuple = NULL;
 			}
 
 			if (change->data.tp.oldtuple)
 			{
-				ReorderBufferReturnTupleBuf(rb, change->data.tp.oldtuple);
+				ReorderBufferReturnTupleBuf(change->data.tp.oldtuple);
 				change->data.tp.oldtuple = NULL;
 			}
 			break;
@@ -547,36 +547,26 @@ ReorderBufferReturnChange(ReorderBuffer *rb, ReorderBufferChange *change,
 }
 
 /*
- * Get a fresh ReorderBufferTupleBuf fitting at least a tuple of size
+ * Get a fresh HeapTuple fitting at least a tuple of size
  * tuple_len (excluding header overhead).
  */
-ReorderBufferTupleBuf *
+HeapTuple
 ReorderBufferGetTupleBuf(ReorderBuffer *rb, Size tuple_len)
 {
-	ReorderBufferTupleBuf *tuple;
+	HeapTuple tuple;
 	Size		alloc_len;
 
 	alloc_len = tuple_len + SizeofHeapTupleHeader;
 
-	tuple = (ReorderBufferTupleBuf *)
+	tuple = (HeapTuple)
 		MemoryContextAlloc(rb->tup_context,
-						   sizeof(ReorderBufferTupleBuf) +
+						   HEAPTUPLESIZE +
 						   MAXIMUM_ALIGNOF + alloc_len);
-	tuple->alloc_tuple_size = alloc_len;
-	tuple->tuple.t_data = ReorderBufferTupleBufData(tuple);
+	tuple->t_data = (HeapTupleHeader)((char *)tuple + HEAPTUPLESIZE);
 
 	return tuple;
 }
 
-/*
- * Free a ReorderBufferTupleBuf.
- */
-void
-ReorderBufferReturnTupleBuf(ReorderBuffer *rb, ReorderBufferTupleBuf *tuple)
-{
-	pfree(tuple);
-}
-
 /*
  * Get an array for relids of truncated relations.
  *
@@ -3759,8 +3749,8 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 		case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
 			{
 				char	   *data;
-				ReorderBufferTupleBuf *oldtup,
-						   *newtup;
+				HeapTuple   oldtup,
+						    newtup;
 				Size		oldlen = 0;
 				Size		newlen = 0;
 
@@ -3770,14 +3760,14 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 				if (oldtup)
 				{
 					sz += sizeof(HeapTupleData);
-					oldlen = oldtup->tuple.t_len;
+					oldlen = oldtup->t_len;
 					sz += oldlen;
 				}
 
 				if (newtup)
 				{
 					sz += sizeof(HeapTupleData);
-					newlen = newtup->tuple.t_len;
+					newlen = newtup->t_len;
 					sz += newlen;
 				}
 
@@ -3790,19 +3780,19 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 
 				if (oldlen)
 				{
-					memcpy(data, &oldtup->tuple, sizeof(HeapTupleData));
+					memcpy(data, oldtup, sizeof(HeapTupleData));
 					data += sizeof(HeapTupleData);
 
-					memcpy(data, oldtup->tuple.t_data, oldlen);
+					memcpy(data, oldtup->t_data, oldlen);
 					data += oldlen;
 				}
 
 				if (newlen)
 				{
-					memcpy(data, &newtup->tuple, sizeof(HeapTupleData));
+					memcpy(data, newtup, sizeof(HeapTupleData));
 					data += sizeof(HeapTupleData);
 
-					memcpy(data, newtup->tuple.t_data, newlen);
+					memcpy(data, newtup->t_data, newlen);
 					data += newlen;
 				}
 				break;
@@ -4118,8 +4108,8 @@ ReorderBufferChangeSize(ReorderBufferChange *change)
 		case REORDER_BUFFER_CHANGE_DELETE:
 		case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
 			{
-				ReorderBufferTupleBuf *oldtup,
-						   *newtup;
+				HeapTuple   oldtup,
+						    newtup;
 				Size		oldlen = 0;
 				Size		newlen = 0;
 
@@ -4129,14 +4119,14 @@ ReorderBufferChangeSize(ReorderBufferChange *change)
 				if (oldtup)
 				{
 					sz += sizeof(HeapTupleData);
-					oldlen = oldtup->tuple.t_len;
+					oldlen = oldtup->t_len;
 					sz += oldlen;
 				}
 
 				if (newtup)
 				{
 					sz += sizeof(HeapTupleData);
-					newlen = newtup->tuple.t_len;
+					newlen = newtup->t_len;
 					sz += newlen;
 				}
 
@@ -4365,16 +4355,16 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 					ReorderBufferGetTupleBuf(rb, tuplelen - SizeofHeapTupleHeader);
 
 				/* restore ->tuple */
-				memcpy(&change->data.tp.oldtuple->tuple, data,
+				memcpy(change->data.tp.oldtuple, data,
 					   sizeof(HeapTupleData));
 				data += sizeof(HeapTupleData);
 
 				/* reset t_data pointer into the new tuplebuf */
-				change->data.tp.oldtuple->tuple.t_data =
-					ReorderBufferTupleBufData(change->data.tp.oldtuple);
+				change->data.tp.oldtuple->t_data =
+					(HeapTupleHeader)((char*)change->data.tp.oldtuple + HEAPTUPLESIZE);
 
 				/* restore tuple data itself */
-				memcpy(change->data.tp.oldtuple->tuple.t_data, data, tuplelen);
+				memcpy(change->data.tp.oldtuple->t_data, data, tuplelen);
 				data += tuplelen;
 			}
 
@@ -4390,16 +4380,16 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 					ReorderBufferGetTupleBuf(rb, tuplelen - SizeofHeapTupleHeader);
 
 				/* restore ->tuple */
-				memcpy(&change->data.tp.newtuple->tuple, data,
+				memcpy(change->data.tp.newtuple, data,
 					   sizeof(HeapTupleData));
 				data += sizeof(HeapTupleData);
 
 				/* reset t_data pointer into the new tuplebuf */
-				change->data.tp.newtuple->tuple.t_data =
-					ReorderBufferTupleBufData(change->data.tp.newtuple);
+				change->data.tp.newtuple->t_data =
+					(HeapTupleHeader)((char*)change->data.tp.newtuple + HEAPTUPLESIZE);
 
 				/* restore tuple data itself */
-				memcpy(change->data.tp.newtuple->tuple.t_data, data, tuplelen);
+				memcpy(change->data.tp.newtuple->t_data, data, tuplelen);
 				data += tuplelen;
 			}
 
@@ -4646,7 +4636,7 @@ ReorderBufferToastAppendChunk(ReorderBuffer *rb, ReorderBufferTXN *txn,
 							  Relation relation, ReorderBufferChange *change)
 {
 	ReorderBufferToastEnt *ent;
-	ReorderBufferTupleBuf *newtup;
+	HeapTuple newtup;
 	bool		found;
 	int32		chunksize;
 	bool		isnull;
@@ -4661,9 +4651,9 @@ ReorderBufferToastAppendChunk(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	Assert(IsToastRelation(relation));
 
 	newtup = change->data.tp.newtuple;
-	chunk_id = DatumGetObjectId(fastgetattr(&newtup->tuple, 1, desc, &isnull));
+	chunk_id = DatumGetObjectId(fastgetattr(newtup, 1, desc, &isnull));
 	Assert(!isnull);
-	chunk_seq = DatumGetInt32(fastgetattr(&newtup->tuple, 2, desc, &isnull));
+	chunk_seq = DatumGetInt32(fastgetattr(newtup, 2, desc, &isnull));
 	Assert(!isnull);
 
 	ent = (ReorderBufferToastEnt *)
@@ -4686,7 +4676,7 @@ ReorderBufferToastAppendChunk(ReorderBuffer *rb, ReorderBufferTXN *txn,
 		elog(ERROR, "got sequence entry %d for toast chunk %u instead of seq %d",
 			 chunk_seq, chunk_id, ent->last_chunk_seq + 1);
 
-	chunk = DatumGetPointer(fastgetattr(&newtup->tuple, 3, desc, &isnull));
+	chunk = DatumGetPointer(fastgetattr(newtup, 3, desc, &isnull));
 	Assert(!isnull);
 
 	/* calculate size so we can allocate the right size at once later */
@@ -4737,7 +4727,7 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	Relation	toast_rel;
 	TupleDesc	toast_desc;
 	MemoryContext oldcontext;
-	ReorderBufferTupleBuf *newtup;
+	HeapTuple newtup;
 	Size		old_size;
 
 	/* no toast tuples changed */
@@ -4777,7 +4767,7 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
 
 	newtup = change->data.tp.newtuple;
 
-	heap_deform_tuple(&newtup->tuple, desc, attrs, isnull);
+	heap_deform_tuple(newtup, desc, attrs, isnull);
 
 	for (natt = 0; natt < desc->natts; natt++)
 	{
@@ -4842,12 +4832,12 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
 		{
 			bool		cisnull;
 			ReorderBufferChange *cchange;
-			ReorderBufferTupleBuf *ctup;
+			HeapTuple   ctup;
 			Pointer		chunk;
 
 			cchange = dlist_container(ReorderBufferChange, node, it.cur);
 			ctup = cchange->data.tp.newtuple;
-			chunk = DatumGetPointer(fastgetattr(&ctup->tuple, 3, toast_desc, &cisnull));
+			chunk = DatumGetPointer(fastgetattr(ctup, 3, toast_desc, &cisnull));
 
 			Assert(!cisnull);
 			Assert(!VARATT_IS_EXTERNAL(chunk));
@@ -4882,11 +4872,11 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	 * the tuplebuf because attrs[] will point back into the current content.
 	 */
 	tmphtup = heap_form_tuple(desc, attrs, isnull);
-	Assert(newtup->tuple.t_len <= MaxHeapTupleSize);
-	Assert(ReorderBufferTupleBufData(newtup) == newtup->tuple.t_data);
+	Assert(newtup->t_len <= MaxHeapTupleSize);
+	Assert(newtup->t_data == (HeapTupleHeader)((char*)newtup + HEAPTUPLESIZE));
 
-	memcpy(newtup->tuple.t_data, tmphtup->t_data, tmphtup->t_len);
-	newtup->tuple.t_len = tmphtup->t_len;
+	memcpy(newtup->t_data, tmphtup->t_data, tmphtup->t_len);
+	newtup->t_len = tmphtup->t_len;
 
 	/*
 	 * free resources we won't further need, more persistent stuff will be
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 425238187f..998f92d671 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -1473,7 +1473,7 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 	if (change->data.tp.oldtuple)
 	{
 		old_slot = relentry->old_slot;
-		ExecStoreHeapTuple(&change->data.tp.oldtuple->tuple, old_slot, false);
+		ExecStoreHeapTuple(change->data.tp.oldtuple, old_slot, false);
 
 		/* Convert tuple if needed. */
 		if (relentry->attrmap)
@@ -1488,7 +1488,7 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 	if (change->data.tp.newtuple)
 	{
 		new_slot = relentry->new_slot;
-		ExecStoreHeapTuple(&change->data.tp.newtuple->tuple, new_slot, false);
+		ExecStoreHeapTuple(change->data.tp.newtuple, new_slot, false);
 
 		/* Convert tuple if needed. */
 		if (relentry->attrmap)
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index 3e232c6c27..efa57f2bec 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -28,25 +28,6 @@ typedef enum
 	DEBUG_LOGICAL_REP_STREAMING_IMMEDIATE,
 }			DebugLogicalRepStreamingMode;
 
-/* an individual tuple, stored in one chunk of memory */
-typedef struct ReorderBufferTupleBuf
-{
-	/* position in preallocated list */
-	slist_node	node;
-
-	/* tuple header, the interesting bit for users of logical decoding */
-	HeapTupleData tuple;
-
-	/* pre-allocated size of tuple buffer, different from tuple size */
-	Size		alloc_tuple_size;
-
-	/* actual tuple data follows */
-} ReorderBufferTupleBuf;
-
-/* pointer to the data stored in a TupleBuf */
-#define ReorderBufferTupleBufData(p) \
-	((HeapTupleHeader) MAXALIGN(((char *) p) + sizeof(ReorderBufferTupleBuf)))
-
 /*
  * Types of the change passed to a 'change' callback.
  *
@@ -114,9 +95,9 @@ typedef struct ReorderBufferChange
 			bool		clear_toast_afterwards;
 
 			/* valid for DELETE || UPDATE */
-			ReorderBufferTupleBuf *oldtuple;
+			HeapTuple	oldtuple;
 			/* valid for INSERT || UPDATE */
-			ReorderBufferTupleBuf *newtuple;
+			HeapTuple	newtuple;
 		}			tp;
 
 		/*
@@ -678,10 +659,18 @@ struct ReorderBuffer
 extern ReorderBuffer *ReorderBufferAllocate(void);
 extern void ReorderBufferFree(ReorderBuffer *rb);
 
-extern ReorderBufferTupleBuf *ReorderBufferGetTupleBuf(ReorderBuffer *rb,
-													   Size tuple_len);
-extern void ReorderBufferReturnTupleBuf(ReorderBuffer *rb,
-										ReorderBufferTupleBuf *tuple);
+extern HeapTuple ReorderBufferGetTupleBuf(ReorderBuffer *rb,
+										  Size tuple_len);
+
+/*
+ * Free HeapTuple returned by ReorderBufferGetTupleBuf().
+ */
+static inline void
+ReorderBufferReturnTupleBuf(HeapTuple tuple)
+{
+	pfree(tuple);
+}
+
 extern ReorderBufferChange *ReorderBufferGetChange(ReorderBuffer *rb);
 extern void ReorderBufferReturnChange(ReorderBuffer *rb,
 									  ReorderBufferChange *change, bool upd_mem);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 7e866e3c3d..dc3b0ef871 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2351,7 +2351,6 @@ ReorderBufferStreamTruncateCB
 ReorderBufferTXN
 ReorderBufferTXNByIdEnt
 ReorderBufferToastEnt
-ReorderBufferTupleBuf
 ReorderBufferTupleCidEnt
 ReorderBufferTupleCidKey
 ReorderBufferUpdateProgressTxnCB
-- 
2.43.0

#11Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Aleksander Alekseev (#10)
Re: Remove unused fields in ReorderBufferTupleBuf

Sorry for being absent for a while.

On Mon, Jan 22, 2024 at 11:19 PM Aleksander Alekseev
<aleksander@timescale.com> wrote:

Hi,

But why didn't you pursue your idea of getting rid of the wrapper
structure ReorderBufferTupleBuf which after this patch will have just
one member? I think there could be hassles in backpatching bug-fixes
in some cases but in the longer run it would make the code look clean.

+1

Indeed. In fact turned out that I suggested the same above but
apparently forgot:

On top of that IMO it doesn't make much sense to keep a one-field
wrapper structure. Perhaps we should get rid of it entirely and just
use HeapTupleData instead.

After actually trying the refactoring I agree that the code becomes
cleaner and it's going to be beneficial in the long run. Here is the
patch.

I did a mistake in v4:

```
-    alloc_len = tuple_len + SizeofHeapTupleHeader;
+    alloc_len = tuple_len + HEAPTUPLESIZE;
```

Here is the corrected patch.

Thank you for updating the patch! I have some comments:

-        tuple = (ReorderBufferTupleBuf *)
+        tuple = (HeapTuple)
                 MemoryContextAlloc(rb->tup_context,
-
sizeof(ReorderBufferTupleBuf) +
+                                                   HEAPTUPLESIZE +
                                                    MAXIMUM_ALIGNOF +
alloc_len);
-        tuple->alloc_tuple_size = alloc_len;
-        tuple->tuple.t_data = ReorderBufferTupleBufData(tuple);
+        tuple->t_data = (HeapTupleHeader)((char *)tuple + HEAPTUPLESIZE);

Why do we need to add MAXIMUM_ALIGNOF? since HEAPTUPLESIZE is the
MAXALIGN'd size, it seems we don't need it. heap_form_tuple() does a
similar thing but it doesn't add it.

---
                                 xl_parameter_change *xlrec =
-                                        (xl_parameter_change *)
XLogRecGetData(buf->record);
+                                (xl_parameter_change *)
XLogRecGetData(buf->record);

Unnecessary change.

---
-/*
- * Free a ReorderBufferTupleBuf.
- */
-void
-ReorderBufferReturnTupleBuf(ReorderBuffer *rb, ReorderBufferTupleBuf *tuple)
-{
- pfree(tuple);
-}
-

Why does ReorderBufferReturnTupleBuf need to be moved from
reorderbuffer.c to reorderbuffer.h? It seems not related to this
refactoring patch so I think we should do it in a separate patch if we
really want it. I'm not sure it's necessary, though.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#12Aleksander Alekseev
aleksander@timescale.com
In reply to: Masahiko Sawada (#11)
1 attachment(s)
Re: Remove unused fields in ReorderBufferTupleBuf

Hi,

Here is the corrected patch.

Thank you for updating the patch! I have some comments:

Thanks for the review.

-        tuple = (ReorderBufferTupleBuf *)
+        tuple = (HeapTuple)
MemoryContextAlloc(rb->tup_context,
-
sizeof(ReorderBufferTupleBuf) +
+                                                   HEAPTUPLESIZE +
MAXIMUM_ALIGNOF +
alloc_len);
-        tuple->alloc_tuple_size = alloc_len;
-        tuple->tuple.t_data = ReorderBufferTupleBufData(tuple);
+        tuple->t_data = (HeapTupleHeader)((char *)tuple + HEAPTUPLESIZE);

Why do we need to add MAXIMUM_ALIGNOF? since HEAPTUPLESIZE is the
MAXALIGN'd size, it seems we don't need it. heap_form_tuple() does a
similar thing but it doesn't add it.

Indeed. I gave it a try and nothing crashed, so it appears that
MAXIMUM_ALIGNOF is not needed.

---
xl_parameter_change *xlrec =
-                                        (xl_parameter_change *)
XLogRecGetData(buf->record);
+                                (xl_parameter_change *)
XLogRecGetData(buf->record);

Unnecessary change.

That's pgindent. Fixed.

---
-/*
- * Free a ReorderBufferTupleBuf.
- */
-void
-ReorderBufferReturnTupleBuf(ReorderBuffer *rb, ReorderBufferTupleBuf *tuple)
-{
- pfree(tuple);
-}
-

Why does ReorderBufferReturnTupleBuf need to be moved from
reorderbuffer.c to reorderbuffer.h? It seems not related to this
refactoring patch so I think we should do it in a separate patch if we
really want it. I'm not sure it's necessary, though.

OK, fixed.

--
Best regards,
Aleksander Alekseev

Attachments:

v6-0001-Remove-ReorderBufferTupleBuf-structure.patchapplication/octet-stream; name=v6-0001-Remove-ReorderBufferTupleBuf-structure.patchDownload
From 4b7a5d980d3b8089d3d07a965ce2a35bc62d2288 Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <aleksander@timescale.com>
Date: Wed, 26 Jul 2023 16:15:38 +0300
Subject: [PATCH v6] Remove ReorderBufferTupleBuf structure

The fields 'node' and 'alloc_tuple_size' of ReorderBufferTupleBuf structure
are no longer used, which leaves only 'tuple' field. Since there is little
sense to keep a one-field structure, remove ReorderBufferTupleBuf altogether
and refactor the code accordingly.

Not backpatched because of ABI change.

Aleksander Alekseev, based on the report and patch by Masahiko Sawada.
Reviewed by Amit Kapila and Masahiko Sawada.
Discussion: https://postgr.es/m/CAD21AoCvnuxiXXfRecp7g9+CeC35POQfhuQeJFr7_9u_Q5jc_Q@mail.gmail.com
---
 contrib/test_decoding/test_decoding.c         |  8 +-
 src/backend/replication/logical/decode.c      | 26 +++---
 .../replication/logical/reorderbuffer.c       | 86 +++++++++----------
 src/backend/replication/pgoutput/pgoutput.c   |  4 +-
 src/include/replication/reorderbuffer.h       | 31 ++-----
 src/tools/pgindent/typedefs.list              |  1 -
 6 files changed, 67 insertions(+), 89 deletions(-)

diff --git a/contrib/test_decoding/test_decoding.c b/contrib/test_decoding/test_decoding.c
index 4f4f51a89c..7c50d13969 100644
--- a/contrib/test_decoding/test_decoding.c
+++ b/contrib/test_decoding/test_decoding.c
@@ -640,7 +640,7 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 				appendStringInfoString(ctx->out, " (no-tuple-data)");
 			else
 				tuple_to_stringinfo(ctx->out, tupdesc,
-									&change->data.tp.newtuple->tuple,
+									change->data.tp.newtuple,
 									false);
 			break;
 		case REORDER_BUFFER_CHANGE_UPDATE:
@@ -649,7 +649,7 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 			{
 				appendStringInfoString(ctx->out, " old-key:");
 				tuple_to_stringinfo(ctx->out, tupdesc,
-									&change->data.tp.oldtuple->tuple,
+									change->data.tp.oldtuple,
 									true);
 				appendStringInfoString(ctx->out, " new-tuple:");
 			}
@@ -658,7 +658,7 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 				appendStringInfoString(ctx->out, " (no-tuple-data)");
 			else
 				tuple_to_stringinfo(ctx->out, tupdesc,
-									&change->data.tp.newtuple->tuple,
+									change->data.tp.newtuple,
 									false);
 			break;
 		case REORDER_BUFFER_CHANGE_DELETE:
@@ -670,7 +670,7 @@ pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 			/* In DELETE, only the replica identity is present; display that */
 			else
 				tuple_to_stringinfo(ctx->out, tupdesc,
-									&change->data.tp.oldtuple->tuple,
+									change->data.tp.oldtuple,
 									true);
 			break;
 		default:
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index 6a0f22b209..7b21731287 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -62,7 +62,7 @@ static void DecodePrepare(LogicalDecodingContext *ctx, XLogRecordBuffer *buf,
 
 
 /* common function to decode tuples */
-static void DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple);
+static void DecodeXLogTuple(char *data, Size len, HeapTuple tuple);
 
 /* helper functions for decoding transactions */
 static inline bool FilterPrepare(LogicalDecodingContext *ctx,
@@ -1152,7 +1152,7 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
 		ReorderBufferChange *change;
 		xl_multi_insert_tuple *xlhdr;
 		int			datalen;
-		ReorderBufferTupleBuf *tuple;
+		HeapTuple	tuple;
 		HeapTupleHeader header;
 
 		change = ReorderBufferGetChange(ctx->reorder);
@@ -1169,21 +1169,21 @@ DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
 			ReorderBufferGetTupleBuf(ctx->reorder, datalen);
 
 		tuple = change->data.tp.newtuple;
-		header = tuple->tuple.t_data;
+		header = tuple->t_data;
 
 		/* not a disk based tuple */
-		ItemPointerSetInvalid(&tuple->tuple.t_self);
+		ItemPointerSetInvalid(&tuple->t_self);
 
 		/*
 		 * We can only figure this out after reassembling the transactions.
 		 */
-		tuple->tuple.t_tableOid = InvalidOid;
+		tuple->t_tableOid = InvalidOid;
 
-		tuple->tuple.t_len = datalen + SizeofHeapTupleHeader;
+		tuple->t_len = datalen + SizeofHeapTupleHeader;
 
 		memset(header, 0, SizeofHeapTupleHeader);
 
-		memcpy((char *) tuple->tuple.t_data + SizeofHeapTupleHeader,
+		memcpy((char *) tuple->t_data + SizeofHeapTupleHeader,
 			   (char *) data,
 			   datalen);
 		header->t_infomask = xlhdr->t_infomask;
@@ -1253,7 +1253,7 @@ DecodeSpecConfirm(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
  * computed outside as they are record specific.
  */
 static void
-DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple)
+DecodeXLogTuple(char *data, Size len, HeapTuple tuple)
 {
 	xl_heap_header xlhdr;
 	int			datalen = len - SizeOfHeapHeader;
@@ -1261,14 +1261,14 @@ DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple)
 
 	Assert(datalen >= 0);
 
-	tuple->tuple.t_len = datalen + SizeofHeapTupleHeader;
-	header = tuple->tuple.t_data;
+	tuple->t_len = datalen + SizeofHeapTupleHeader;
+	header = tuple->t_data;
 
 	/* not a disk based tuple */
-	ItemPointerSetInvalid(&tuple->tuple.t_self);
+	ItemPointerSetInvalid(&tuple->t_self);
 
 	/* we can only figure this out after reassembling the transactions */
-	tuple->tuple.t_tableOid = InvalidOid;
+	tuple->t_tableOid = InvalidOid;
 
 	/* data is not stored aligned, copy to aligned storage */
 	memcpy((char *) &xlhdr,
@@ -1277,7 +1277,7 @@ DecodeXLogTuple(char *data, Size len, ReorderBufferTupleBuf *tuple)
 
 	memset(header, 0, SizeofHeapTupleHeader);
 
-	memcpy(((char *) tuple->tuple.t_data) + SizeofHeapTupleHeader,
+	memcpy(((char *) tuple->t_data) + SizeofHeapTupleHeader,
 		   data + SizeOfHeapHeader,
 		   datalen);
 
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index d1334ffb55..8f1d165bcc 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -498,13 +498,13 @@ ReorderBufferReturnChange(ReorderBuffer *rb, ReorderBufferChange *change,
 		case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
 			if (change->data.tp.newtuple)
 			{
-				ReorderBufferReturnTupleBuf(rb, change->data.tp.newtuple);
+				ReorderBufferReturnTupleBuf(change->data.tp.newtuple);
 				change->data.tp.newtuple = NULL;
 			}
 
 			if (change->data.tp.oldtuple)
 			{
-				ReorderBufferReturnTupleBuf(rb, change->data.tp.oldtuple);
+				ReorderBufferReturnTupleBuf(change->data.tp.oldtuple);
 				change->data.tp.oldtuple = NULL;
 			}
 			break;
@@ -547,32 +547,30 @@ ReorderBufferReturnChange(ReorderBuffer *rb, ReorderBufferChange *change,
 }
 
 /*
- * Get a fresh ReorderBufferTupleBuf fitting at least a tuple of size
+ * Get a fresh HeapTuple fitting at least a tuple of size
  * tuple_len (excluding header overhead).
  */
-ReorderBufferTupleBuf *
+HeapTuple
 ReorderBufferGetTupleBuf(ReorderBuffer *rb, Size tuple_len)
 {
-	ReorderBufferTupleBuf *tuple;
+	HeapTuple tuple;
 	Size		alloc_len;
 
 	alloc_len = tuple_len + SizeofHeapTupleHeader;
 
-	tuple = (ReorderBufferTupleBuf *)
+	tuple = (HeapTuple)
 		MemoryContextAlloc(rb->tup_context,
-						   sizeof(ReorderBufferTupleBuf) +
-						   MAXIMUM_ALIGNOF + alloc_len);
-	tuple->alloc_tuple_size = alloc_len;
-	tuple->tuple.t_data = ReorderBufferTupleBufData(tuple);
+						   HEAPTUPLESIZE + alloc_len);
+	tuple->t_data = (HeapTupleHeader)((char *)tuple + HEAPTUPLESIZE);
 
 	return tuple;
 }
 
 /*
- * Free a ReorderBufferTupleBuf.
+ * Free a HeapTuple returned by ReorderBufferGetTupleBuf().
  */
 void
-ReorderBufferReturnTupleBuf(ReorderBuffer *rb, ReorderBufferTupleBuf *tuple)
+ReorderBufferReturnTupleBuf(HeapTuple tuple)
 {
 	pfree(tuple);
 }
@@ -3759,8 +3757,8 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 		case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
 			{
 				char	   *data;
-				ReorderBufferTupleBuf *oldtup,
-						   *newtup;
+				HeapTuple   oldtup,
+						    newtup;
 				Size		oldlen = 0;
 				Size		newlen = 0;
 
@@ -3770,14 +3768,14 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 				if (oldtup)
 				{
 					sz += sizeof(HeapTupleData);
-					oldlen = oldtup->tuple.t_len;
+					oldlen = oldtup->t_len;
 					sz += oldlen;
 				}
 
 				if (newtup)
 				{
 					sz += sizeof(HeapTupleData);
-					newlen = newtup->tuple.t_len;
+					newlen = newtup->t_len;
 					sz += newlen;
 				}
 
@@ -3790,19 +3788,19 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 
 				if (oldlen)
 				{
-					memcpy(data, &oldtup->tuple, sizeof(HeapTupleData));
+					memcpy(data, oldtup, sizeof(HeapTupleData));
 					data += sizeof(HeapTupleData);
 
-					memcpy(data, oldtup->tuple.t_data, oldlen);
+					memcpy(data, oldtup->t_data, oldlen);
 					data += oldlen;
 				}
 
 				if (newlen)
 				{
-					memcpy(data, &newtup->tuple, sizeof(HeapTupleData));
+					memcpy(data, newtup, sizeof(HeapTupleData));
 					data += sizeof(HeapTupleData);
 
-					memcpy(data, newtup->tuple.t_data, newlen);
+					memcpy(data, newtup->t_data, newlen);
 					data += newlen;
 				}
 				break;
@@ -4118,8 +4116,8 @@ ReorderBufferChangeSize(ReorderBufferChange *change)
 		case REORDER_BUFFER_CHANGE_DELETE:
 		case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
 			{
-				ReorderBufferTupleBuf *oldtup,
-						   *newtup;
+				HeapTuple   oldtup,
+						    newtup;
 				Size		oldlen = 0;
 				Size		newlen = 0;
 
@@ -4129,14 +4127,14 @@ ReorderBufferChangeSize(ReorderBufferChange *change)
 				if (oldtup)
 				{
 					sz += sizeof(HeapTupleData);
-					oldlen = oldtup->tuple.t_len;
+					oldlen = oldtup->t_len;
 					sz += oldlen;
 				}
 
 				if (newtup)
 				{
 					sz += sizeof(HeapTupleData);
-					newlen = newtup->tuple.t_len;
+					newlen = newtup->t_len;
 					sz += newlen;
 				}
 
@@ -4365,16 +4363,16 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 					ReorderBufferGetTupleBuf(rb, tuplelen - SizeofHeapTupleHeader);
 
 				/* restore ->tuple */
-				memcpy(&change->data.tp.oldtuple->tuple, data,
+				memcpy(change->data.tp.oldtuple, data,
 					   sizeof(HeapTupleData));
 				data += sizeof(HeapTupleData);
 
 				/* reset t_data pointer into the new tuplebuf */
-				change->data.tp.oldtuple->tuple.t_data =
-					ReorderBufferTupleBufData(change->data.tp.oldtuple);
+				change->data.tp.oldtuple->t_data =
+					(HeapTupleHeader)((char*)change->data.tp.oldtuple + HEAPTUPLESIZE);
 
 				/* restore tuple data itself */
-				memcpy(change->data.tp.oldtuple->tuple.t_data, data, tuplelen);
+				memcpy(change->data.tp.oldtuple->t_data, data, tuplelen);
 				data += tuplelen;
 			}
 
@@ -4390,16 +4388,16 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 					ReorderBufferGetTupleBuf(rb, tuplelen - SizeofHeapTupleHeader);
 
 				/* restore ->tuple */
-				memcpy(&change->data.tp.newtuple->tuple, data,
+				memcpy(change->data.tp.newtuple, data,
 					   sizeof(HeapTupleData));
 				data += sizeof(HeapTupleData);
 
 				/* reset t_data pointer into the new tuplebuf */
-				change->data.tp.newtuple->tuple.t_data =
-					ReorderBufferTupleBufData(change->data.tp.newtuple);
+				change->data.tp.newtuple->t_data =
+					(HeapTupleHeader)((char*)change->data.tp.newtuple + HEAPTUPLESIZE);
 
 				/* restore tuple data itself */
-				memcpy(change->data.tp.newtuple->tuple.t_data, data, tuplelen);
+				memcpy(change->data.tp.newtuple->t_data, data, tuplelen);
 				data += tuplelen;
 			}
 
@@ -4646,7 +4644,7 @@ ReorderBufferToastAppendChunk(ReorderBuffer *rb, ReorderBufferTXN *txn,
 							  Relation relation, ReorderBufferChange *change)
 {
 	ReorderBufferToastEnt *ent;
-	ReorderBufferTupleBuf *newtup;
+	HeapTuple newtup;
 	bool		found;
 	int32		chunksize;
 	bool		isnull;
@@ -4661,9 +4659,9 @@ ReorderBufferToastAppendChunk(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	Assert(IsToastRelation(relation));
 
 	newtup = change->data.tp.newtuple;
-	chunk_id = DatumGetObjectId(fastgetattr(&newtup->tuple, 1, desc, &isnull));
+	chunk_id = DatumGetObjectId(fastgetattr(newtup, 1, desc, &isnull));
 	Assert(!isnull);
-	chunk_seq = DatumGetInt32(fastgetattr(&newtup->tuple, 2, desc, &isnull));
+	chunk_seq = DatumGetInt32(fastgetattr(newtup, 2, desc, &isnull));
 	Assert(!isnull);
 
 	ent = (ReorderBufferToastEnt *)
@@ -4686,7 +4684,7 @@ ReorderBufferToastAppendChunk(ReorderBuffer *rb, ReorderBufferTXN *txn,
 		elog(ERROR, "got sequence entry %d for toast chunk %u instead of seq %d",
 			 chunk_seq, chunk_id, ent->last_chunk_seq + 1);
 
-	chunk = DatumGetPointer(fastgetattr(&newtup->tuple, 3, desc, &isnull));
+	chunk = DatumGetPointer(fastgetattr(newtup, 3, desc, &isnull));
 	Assert(!isnull);
 
 	/* calculate size so we can allocate the right size at once later */
@@ -4737,7 +4735,7 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	Relation	toast_rel;
 	TupleDesc	toast_desc;
 	MemoryContext oldcontext;
-	ReorderBufferTupleBuf *newtup;
+	HeapTuple newtup;
 	Size		old_size;
 
 	/* no toast tuples changed */
@@ -4777,7 +4775,7 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
 
 	newtup = change->data.tp.newtuple;
 
-	heap_deform_tuple(&newtup->tuple, desc, attrs, isnull);
+	heap_deform_tuple(newtup, desc, attrs, isnull);
 
 	for (natt = 0; natt < desc->natts; natt++)
 	{
@@ -4842,12 +4840,12 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
 		{
 			bool		cisnull;
 			ReorderBufferChange *cchange;
-			ReorderBufferTupleBuf *ctup;
+			HeapTuple   ctup;
 			Pointer		chunk;
 
 			cchange = dlist_container(ReorderBufferChange, node, it.cur);
 			ctup = cchange->data.tp.newtuple;
-			chunk = DatumGetPointer(fastgetattr(&ctup->tuple, 3, toast_desc, &cisnull));
+			chunk = DatumGetPointer(fastgetattr(ctup, 3, toast_desc, &cisnull));
 
 			Assert(!cisnull);
 			Assert(!VARATT_IS_EXTERNAL(chunk));
@@ -4882,11 +4880,11 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	 * the tuplebuf because attrs[] will point back into the current content.
 	 */
 	tmphtup = heap_form_tuple(desc, attrs, isnull);
-	Assert(newtup->tuple.t_len <= MaxHeapTupleSize);
-	Assert(ReorderBufferTupleBufData(newtup) == newtup->tuple.t_data);
+	Assert(newtup->t_len <= MaxHeapTupleSize);
+	Assert(newtup->t_data == (HeapTupleHeader)((char*)newtup + HEAPTUPLESIZE));
 
-	memcpy(newtup->tuple.t_data, tmphtup->t_data, tmphtup->t_len);
-	newtup->tuple.t_len = tmphtup->t_len;
+	memcpy(newtup->t_data, tmphtup->t_data, tmphtup->t_len);
+	newtup->t_len = tmphtup->t_len;
 
 	/*
 	 * free resources we won't further need, more persistent stuff will be
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 425238187f..998f92d671 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -1473,7 +1473,7 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 	if (change->data.tp.oldtuple)
 	{
 		old_slot = relentry->old_slot;
-		ExecStoreHeapTuple(&change->data.tp.oldtuple->tuple, old_slot, false);
+		ExecStoreHeapTuple(change->data.tp.oldtuple, old_slot, false);
 
 		/* Convert tuple if needed. */
 		if (relentry->attrmap)
@@ -1488,7 +1488,7 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
 	if (change->data.tp.newtuple)
 	{
 		new_slot = relentry->new_slot;
-		ExecStoreHeapTuple(&change->data.tp.newtuple->tuple, new_slot, false);
+		ExecStoreHeapTuple(change->data.tp.newtuple, new_slot, false);
 
 		/* Convert tuple if needed. */
 		if (relentry->attrmap)
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index 3e232c6c27..0b2c95f7aa 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -28,25 +28,6 @@ typedef enum
 	DEBUG_LOGICAL_REP_STREAMING_IMMEDIATE,
 }			DebugLogicalRepStreamingMode;
 
-/* an individual tuple, stored in one chunk of memory */
-typedef struct ReorderBufferTupleBuf
-{
-	/* position in preallocated list */
-	slist_node	node;
-
-	/* tuple header, the interesting bit for users of logical decoding */
-	HeapTupleData tuple;
-
-	/* pre-allocated size of tuple buffer, different from tuple size */
-	Size		alloc_tuple_size;
-
-	/* actual tuple data follows */
-} ReorderBufferTupleBuf;
-
-/* pointer to the data stored in a TupleBuf */
-#define ReorderBufferTupleBufData(p) \
-	((HeapTupleHeader) MAXALIGN(((char *) p) + sizeof(ReorderBufferTupleBuf)))
-
 /*
  * Types of the change passed to a 'change' callback.
  *
@@ -114,9 +95,9 @@ typedef struct ReorderBufferChange
 			bool		clear_toast_afterwards;
 
 			/* valid for DELETE || UPDATE */
-			ReorderBufferTupleBuf *oldtuple;
+			HeapTuple	oldtuple;
 			/* valid for INSERT || UPDATE */
-			ReorderBufferTupleBuf *newtuple;
+			HeapTuple	newtuple;
 		}			tp;
 
 		/*
@@ -678,10 +659,10 @@ struct ReorderBuffer
 extern ReorderBuffer *ReorderBufferAllocate(void);
 extern void ReorderBufferFree(ReorderBuffer *rb);
 
-extern ReorderBufferTupleBuf *ReorderBufferGetTupleBuf(ReorderBuffer *rb,
-													   Size tuple_len);
-extern void ReorderBufferReturnTupleBuf(ReorderBuffer *rb,
-										ReorderBufferTupleBuf *tuple);
+extern HeapTuple ReorderBufferGetTupleBuf(ReorderBuffer *rb,
+										  Size tuple_len);
+extern void ReorderBufferReturnTupleBuf(HeapTuple tuple);
+
 extern ReorderBufferChange *ReorderBufferGetChange(ReorderBuffer *rb);
 extern void ReorderBufferReturnChange(ReorderBuffer *rb,
 									  ReorderBufferChange *change, bool upd_mem);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 7e866e3c3d..dc3b0ef871 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2351,7 +2351,6 @@ ReorderBufferStreamTruncateCB
 ReorderBufferTXN
 ReorderBufferTXNByIdEnt
 ReorderBufferToastEnt
-ReorderBufferTupleBuf
 ReorderBufferTupleCidEnt
 ReorderBufferTupleCidKey
 ReorderBufferUpdateProgressTxnCB
-- 
2.43.0

#13Noname
reid.thompson@crunchydata.com
In reply to: Aleksander Alekseev (#12)
Re: Remove unused fields in ReorderBufferTupleBuf

On Thu, 2024-01-25 at 16:16 +0300, Aleksander Alekseev wrote:

Hi,

Here is the corrected patch.

Thank you for updating the patch! I have some comments:

Thanks for the review.

-        tuple = (ReorderBufferTupleBuf *)
+        tuple = (HeapTuple)
MemoryContextAlloc(rb->tup_context,
-
sizeof(ReorderBufferTupleBuf) +
+                                                   HEAPTUPLESIZE +
MAXIMUM_ALIGNOF +
alloc_len);
-        tuple->alloc_tuple_size = alloc_len;
-        tuple->tuple.t_data = ReorderBufferTupleBufData(tuple);
+        tuple->t_data = (HeapTupleHeader)((char *)tuple + HEAPTUPLESIZE);

Why do we need to add MAXIMUM_ALIGNOF? since HEAPTUPLESIZE is the
MAXALIGN'd size, it seems we don't need it. heap_form_tuple() does a
similar thing but it doesn't add it.

Indeed. I gave it a try and nothing crashed, so it appears that
MAXIMUM_ALIGNOF is not needed.

---
xl_parameter_change *xlrec =
-                                        (xl_parameter_change *)
XLogRecGetData(buf->record);
+                                (xl_parameter_change *)
XLogRecGetData(buf->record);

Unnecessary change.

That's pgindent. Fixed.

---
-/*
- * Free a ReorderBufferTupleBuf.
- */
-void
-ReorderBufferReturnTupleBuf(ReorderBuffer *rb, ReorderBufferTupleBuf *tuple)
-{
- pfree(tuple);
-}
-

Why does ReorderBufferReturnTupleBuf need to be moved from
reorderbuffer.c to reorderbuffer.h? It seems not related to this
refactoring patch so I think we should do it in a separate patch if we
really want it. I'm not sure it's necessary, though.

OK, fixed.

I walked through v6 and didn't note any issues.

I do want to ask, the patch alters ReorderBufferReturnTupleBuf() and
drops the unused parameter ReorderBuffer *rb. It seems that
ReorderBufferFreeSnap(), ReorderBufferReturnRelids(),
ReorderBufferImmediateInvalidation(), and ReorderBufferRestoreCleanup()
also pass ReorderBuffer *rb but do not use it. Would it be beneficial
to implement a separate patch to remove this parameter from these
functions also?

Thanks,
Reid

#14Noname
reid.thompson@crunchydata.com
In reply to: Noname (#13)
Re: Remove unused fields in ReorderBufferTupleBuf

On Thu, 2024-01-25 at 16:11 -0500, reid.thompson@crunchydata.com wrote:

I walked through v6 and didn't note any issues.

I do want to ask, the patch alters ReorderBufferReturnTupleBuf() and
drops the unused parameter ReorderBuffer *rb. It seems that
ReorderBufferFreeSnap(), ReorderBufferReturnRelids(),
ReorderBufferImmediateInvalidation(), and ReorderBufferRestoreCleanup()
also pass ReorderBuffer *rb but do not use it. Would it be beneficial
to implement a separate patch to remove this parameter from these
functions also?

Thanks,
Reid

It also appears that ReorderBufferSerializeChange() has 5 instances
where it increments the local variables "data" but then they're never
read.
Lines 3806, 3836, 3854, 3889, 3910

I can create patch and post it to this thread or a new one if deemed
worthwhile.

Thanks,
Reid

#15Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Noname (#14)
Re: Remove unused fields in ReorderBufferTupleBuf

On Fri, Jan 26, 2024 at 1:24 PM <reid.thompson@crunchydata.com> wrote:

On Thu, 2024-01-25 at 16:11 -0500, reid.thompson@crunchydata.com wrote:

I walked through v6 and didn't note any issues.

Thank you for reviewing the patch!

I do want to ask, the patch alters ReorderBufferReturnTupleBuf() and
drops the unused parameter ReorderBuffer *rb. It seems that
ReorderBufferFreeSnap(), ReorderBufferReturnRelids(),
ReorderBufferImmediateInvalidation(), and ReorderBufferRestoreCleanup()
also pass ReorderBuffer *rb but do not use it. Would it be beneficial
to implement a separate patch to remove this parameter from these
functions also?

It also appears that ReorderBufferSerializeChange() has 5 instances
where it increments the local variables "data" but then they're never
read.
Lines 3806, 3836, 3854, 3889, 3910

I can create patch and post it to this thread or a new one if deemed
worthwhile.

I'm not sure these changes are really beneficial. They contribute to
improving neither readability and performance IMO.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#16Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Aleksander Alekseev (#12)
Re: Remove unused fields in ReorderBufferTupleBuf

On Thu, Jan 25, 2024 at 10:17 PM Aleksander Alekseev
<aleksander@timescale.com> wrote:

Hi,

Here is the corrected patch.

Thank you for updating the patch! I have some comments:

Thanks for the review.

-        tuple = (ReorderBufferTupleBuf *)
+        tuple = (HeapTuple)
MemoryContextAlloc(rb->tup_context,
-
sizeof(ReorderBufferTupleBuf) +
+                                                   HEAPTUPLESIZE +
MAXIMUM_ALIGNOF +
alloc_len);
-        tuple->alloc_tuple_size = alloc_len;
-        tuple->tuple.t_data = ReorderBufferTupleBufData(tuple);
+        tuple->t_data = (HeapTupleHeader)((char *)tuple + HEAPTUPLESIZE);

Why do we need to add MAXIMUM_ALIGNOF? since HEAPTUPLESIZE is the
MAXALIGN'd size, it seems we don't need it. heap_form_tuple() does a
similar thing but it doesn't add it.

Indeed. I gave it a try and nothing crashed, so it appears that
MAXIMUM_ALIGNOF is not needed.

---
xl_parameter_change *xlrec =
-                                        (xl_parameter_change *)
XLogRecGetData(buf->record);
+                                (xl_parameter_change *)
XLogRecGetData(buf->record);

Unnecessary change.

That's pgindent. Fixed.

---
-/*
- * Free a ReorderBufferTupleBuf.
- */
-void
-ReorderBufferReturnTupleBuf(ReorderBuffer *rb, ReorderBufferTupleBuf *tuple)
-{
- pfree(tuple);
-}
-

Why does ReorderBufferReturnTupleBuf need to be moved from
reorderbuffer.c to reorderbuffer.h? It seems not related to this
refactoring patch so I think we should do it in a separate patch if we
really want it. I'm not sure it's necessary, though.

OK, fixed.

Thank you for updating the patch. It looks good to me. I'm going to
push it next week, barring any objections.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#17Noname
reid.thompson@crunchydata.com
In reply to: Masahiko Sawada (#15)
Re: Remove unused fields in ReorderBufferTupleBuf

On Fri, 2024-01-26 at 13:51 +0900, Masahiko Sawada wrote:

On Fri, Jan 26, 2024 at 1:24 PM <reid.thompson@crunchydata.com> wrote:

On Thu, 2024-01-25 at 16:11 -0500, reid.thompson@crunchydata.com wrote:

I walked through v6 and didn't note any issues.

Thank you for reviewing the patch!

Happy to.

I'm not sure these changes are really beneficial. They contribute to
improving neither readability and performance IMO.

Regards,

I thought that may be the case, but wanted to ask to be sure. Thank you
for the followup.

Reid

#18Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Masahiko Sawada (#16)
Re: Remove unused fields in ReorderBufferTupleBuf

On Fri, Jan 26, 2024 at 4:04 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

On Thu, Jan 25, 2024 at 10:17 PM Aleksander Alekseev
<aleksander@timescale.com> wrote:

Hi,

Here is the corrected patch.

Thank you for updating the patch! I have some comments:

Thanks for the review.

-        tuple = (ReorderBufferTupleBuf *)
+        tuple = (HeapTuple)
MemoryContextAlloc(rb->tup_context,
-
sizeof(ReorderBufferTupleBuf) +
+                                                   HEAPTUPLESIZE +
MAXIMUM_ALIGNOF +
alloc_len);
-        tuple->alloc_tuple_size = alloc_len;
-        tuple->tuple.t_data = ReorderBufferTupleBufData(tuple);
+        tuple->t_data = (HeapTupleHeader)((char *)tuple + HEAPTUPLESIZE);

Why do we need to add MAXIMUM_ALIGNOF? since HEAPTUPLESIZE is the
MAXALIGN'd size, it seems we don't need it. heap_form_tuple() does a
similar thing but it doesn't add it.

Indeed. I gave it a try and nothing crashed, so it appears that
MAXIMUM_ALIGNOF is not needed.

---
xl_parameter_change *xlrec =
-                                        (xl_parameter_change *)
XLogRecGetData(buf->record);
+                                (xl_parameter_change *)
XLogRecGetData(buf->record);

Unnecessary change.

That's pgindent. Fixed.

---
-/*
- * Free a ReorderBufferTupleBuf.
- */
-void
-ReorderBufferReturnTupleBuf(ReorderBuffer *rb, ReorderBufferTupleBuf *tuple)
-{
- pfree(tuple);
-}
-

Why does ReorderBufferReturnTupleBuf need to be moved from
reorderbuffer.c to reorderbuffer.h? It seems not related to this
refactoring patch so I think we should do it in a separate patch if we
really want it. I'm not sure it's necessary, though.

OK, fixed.

Thank you for updating the patch. It looks good to me. I'm going to
push it next week, barring any objections.

Pushed (08e6344fd642).

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com