pgsql: Document XLOG_INCLUDE_XID a little better

Started by Alvaro Herreraover 4 years ago29 messages
#1Alvaro Herrera
alvherre@alvh.no-ip.org

Document XLOG_INCLUDE_XID a little better

I noticed that commit 0bead9af484c left this flag undocumented in
XLogSetRecordFlags, which led me to discover that the flag doesn't
actually do what the one comment on it said it does. Improve the
situation by adding some more comments.

Backpatch to 14, where the aforementioned commit appears.

Author: Álvaro Herrera <alvherre@alvh.no-ip.org>
Discussion: /messages/by-id/202109212119.c3nhfp64t2ql@alvherre.pgsql

Branch
------
REL_14_STABLE

Details
-------
https://git.postgresql.org/pg/commitdiff/c1d1ae1db23796e4d1b04f5c087944722cf1446a

Modified Files
--------------
src/backend/access/transam/xloginsert.c | 2 ++
src/include/access/xlog.h | 2 +-
src/include/access/xlogrecord.h | 5 +++--
3 files changed, 6 insertions(+), 3 deletions(-)

#2Robert Haas
robertmhaas@gmail.com
In reply to: Alvaro Herrera (#1)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Tue, Sep 21, 2021 at 6:48 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

Document XLOG_INCLUDE_XID a little better

I noticed that commit 0bead9af484c left this flag undocumented in
XLogSetRecordFlags, which led me to discover that the flag doesn't
actually do what the one comment on it said it does. Improve the
situation by adding some more comments.

Backpatch to 14, where the aforementioned commit appears.

I'm not sure that saying something is a "hack" is really all that
useful as documentation.

But more to the point, I think this hack is ugly and needs to be
replaced with something less hacky.

Amit?

--
Robert Haas
EDB: http://www.enterprisedb.com

#3Amit Kapila
amit.kapila16@gmail.com
In reply to: Robert Haas (#2)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Wed, Sep 29, 2021 at 8:50 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Sep 21, 2021 at 6:48 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

Document XLOG_INCLUDE_XID a little better

I noticed that commit 0bead9af484c left this flag undocumented in
XLogSetRecordFlags, which led me to discover that the flag doesn't
actually do what the one comment on it said it does. Improve the
situation by adding some more comments.

Backpatch to 14, where the aforementioned commit appears.

I'm not sure that saying something is a "hack" is really all that
useful as documentation.

But more to the point, I think this hack is ugly and needs to be
replaced with something less hacky.

I think we can do better than using XLOG_INCLUDE_XID flag in the
record being inserted. We need this flag so that we can mark
SubTransaction assigned after XLogInsertRecord() is successful. We
can instead output a flag (say sub_xact_assigned) from
XLogRecordAssemble() and pass it to XLogInsertRecord(). Then in
XLogInsertRecord(), we can mark SubTransactionAssigned once the record
is inserted (after or before calling
MarkCurrentTransactionIdLoggedIfAny()).

The other idea could be that in XLogInsertRecord(), we check
IsSubTransactionAssignmentPending() after the record is successfully
inserted and then mark SubTransaction assigned but I think the
previous one is better.

What do you think?

--
With Regards,
Amit Kapila.

#4Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#3)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Thu, Sep 30, 2021 at 6:08 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

I think we can do better than using XLOG_INCLUDE_XID flag in the
record being inserted. We need this flag so that we can mark
SubTransaction assigned after XLogInsertRecord() is successful. We
can instead output a flag (say sub_xact_assigned) from
XLogRecordAssemble() and pass it to XLogInsertRecord(). Then in
XLogInsertRecord(), we can mark SubTransactionAssigned once the record
is inserted (after or before calling
MarkCurrentTransactionIdLoggedIfAny()).

Isn't there other communication between these routines that just uses
global variables?

--
Robert Haas
EDB: http://www.enterprisedb.com

#5Amit Kapila
amit.kapila16@gmail.com
In reply to: Robert Haas (#4)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Fri, Oct 1, 2021 at 12:32 AM Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Sep 30, 2021 at 6:08 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

I think we can do better than using XLOG_INCLUDE_XID flag in the
record being inserted. We need this flag so that we can mark
SubTransaction assigned after XLogInsertRecord() is successful. We
can instead output a flag (say sub_xact_assigned) from
XLogRecordAssemble() and pass it to XLogInsertRecord(). Then in
XLogInsertRecord(), we can mark SubTransactionAssigned once the record
is inserted (after or before calling
MarkCurrentTransactionIdLoggedIfAny()).

Isn't there other communication between these routines that just uses
global variables?

AFAICS, there are two possibilities w.r.t global variables: (a) use
curinsert_flags which we are doing now, (b) another is to introduce a
new global variable, set it after we make the association, and then
reset it after we mark SubTransaction assigned and on error. I have
also thought of passing it via XLogCtlInsert but as that is shared by
different processes, it can be set by one process and be read by
another process which we don't want here.

I am not sure if any of these is better than doing this communication
via local variable. Do you have something specific in mind?

--
With Regards,
Amit Kapila.

#6Alvaro Herrera
alvherre@alvh.no-ip.org
In reply to: Amit Kapila (#5)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On 2021-Oct-01, Amit Kapila wrote:

AFAICS, there are two possibilities w.r.t global variables: (a) use
curinsert_flags which we are doing now, (b) another is to introduce a
new global variable, set it after we make the association, and then
reset it after we mark SubTransaction assigned and on error. I have
also thought of passing it via XLogCtlInsert but as that is shared by
different processes, it can be set by one process and be read by
another process which we don't want here.

So, in my mind, curinsert_flags is a way for the high-level user of
XLogInsert to pass info about the record being inserted to the low-level
xloginsert.c infrastructure. In contrast, XLOG_INCLUDE_XID is being
used solely within xloginsert.c, by one piece of low-level
infrastructure to communicate to another piece of low-level
infrastructure that some cleanup is needed. Nothing outside of
xloginsert.c needs to know anything about XLOG_INCLUDE_XID, in contrast
with the other bits that can be set by XLogSetRecordFlags. You could
move the #define to xloginsert.c and everything would compile fine.

Another tell-tale sign that things are not fitting right is that
XLOG_INCLUDE_XID is not set via XLogSetRecordFlags, contrary the comment
above those defines.

(Aside: I wonder why do we have XLogSetRecordFlags at all -- I think we
could just pass the other two flags via XLogBeginInsert).

Regarding XLOG_INCLUDE_XID, I don't think replacing it with a bit in
shared memory is a good idea, since it only applies to the insertion
being carried out by the current process, right?

I think a straight standalone variable (probably a static boolean in
xloginsert.c) might be less confusing.

... so, reading the xact.c code again, TransactionState->assigned really
means "whether the subXID-to-topXID association has been wal-logged",
which is a completely different meaning from what the term 'assigned'
means in all other comments in xact.c ... and I think the subroutine
name MarkSubTransactionAssigned() is not a great choice either.

--
Álvaro Herrera 39°49'30"S 73°17'W — https://www.EnterpriseDB.com/
"Nunca se desea ardientemente lo que solo se desea por razón" (F. Alexandre)

#7Robert Haas
robertmhaas@gmail.com
In reply to: Alvaro Herrera (#6)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Fri, Oct 1, 2021 at 8:53 AM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

I think a straight standalone variable (probably a static boolean in
xloginsert.c) might be less confusing.

+1.

... so, reading the xact.c code again, TransactionState->assigned really
means "whether the subXID-to-topXID association has been wal-logged",
which is a completely different meaning from what the term 'assigned'
means in all other comments in xact.c ... and I think the subroutine
name MarkSubTransactionAssigned() is not a great choice either.

+1.

--
Robert Haas
EDB: http://www.enterprisedb.com

#8Dilip Kumar
dilipbalaut@gmail.com
In reply to: Alvaro Herrera (#6)
2 attachment(s)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Fri, Oct 1, 2021 at 6:24 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

On 2021-Oct-01, Amit Kapila wrote:

I think a straight standalone variable (probably a static boolean in
xloginsert.c) might be less confusing.

I have written two patches, Approach1 is as you described using a
static boolean and Approach2 as a local variable to XLogAssembleRecord
as described by Amit, attached both of them for your reference.
IMHO, either of these approaches looks cleaner.

... so, reading the xact.c code again, TransactionState->assigned really
means "whether the subXID-to-topXID association has been wal-logged",
which is a completely different meaning from what the term 'assigned'
means in all other comments in xact.c ... and I think the subroutine
name MarkSubTransactionAssigned() is not a great choice either.

I have also renamed the variable and functions as per the actual usage.

--
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Refactor-code-for-logging-the-top-transaction-id-in-Approach2.patchtext/x-patch; charset=US-ASCII; name=0001-Refactor-code-for-logging-the-top-transaction-id-in-Approach2.patchDownload
From 3d4fb94fdeef2ae46511291f144b6305c9eea9f7 Mon Sep 17 00:00:00 2001
From: Dilip Kumar <dilipkumar@localhost.localdomain>
Date: Sat, 2 Oct 2021 15:21:52 +0530
Subject: [PATCH] Refactor code for logging the top transaction id in WAL

---
 src/backend/access/transam/xact.c       | 22 +++++++++++-----------
 src/backend/access/transam/xlog.c       |  7 ++++++-
 src/backend/access/transam/xloginsert.c | 23 ++++++++++-------------
 src/include/access/xact.h               |  4 ++--
 src/include/access/xlog.h               |  4 ++--
 5 files changed, 31 insertions(+), 29 deletions(-)

diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 4cc38f0..893147649 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -204,7 +204,7 @@ typedef struct TransactionStateData
 	bool		didLogXid;		/* has xid been included in WAL record? */
 	int			parallelModeLevel;	/* Enter/ExitParallelMode counter */
 	bool		chain;			/* start a new block after this one */
-	bool		assigned;		/* assigned to top-level XID */
+	bool		topXidLogged;	/* top-level XID is logged?*/
 	struct TransactionStateData *parent;	/* back link to parent */
 } TransactionStateData;
 
@@ -237,7 +237,7 @@ typedef struct SerializedTransactionState
 static TransactionStateData TopTransactionStateData = {
 	.state = TRANS_DEFAULT,
 	.blockState = TBLOCK_DEFAULT,
-	.assigned = false,
+	.topXidLogged = false,
 };
 
 /*
@@ -5159,7 +5159,7 @@ PushTransaction(void)
 	GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
 	s->prevXactReadOnly = XactReadOnly;
 	s->parallelModeLevel = 0;
-	s->assigned = false;
+	s->topXidLogged = false;
 
 	CurrentTransactionState = s;
 
@@ -6093,7 +6093,7 @@ xact_redo(XLogReaderState *record)
 }
 
 /*
- * IsSubTransactionAssignmentPending
+ * IsLogTopTransactionIdPending
  *
  * This is used to decide whether we need to WAL log the top-level XID for
  * operation in a subtransaction.  We require that for logical decoding, see
@@ -6104,7 +6104,7 @@ xact_redo(XLogReaderState *record)
  * record.
  */
 bool
-IsSubTransactionAssignmentPending(void)
+IsLogTopTransactionIdPending(void)
 {
 	/* wal_level has to be logical */
 	if (!XLogLogicalInfoActive())
@@ -6123,18 +6123,18 @@ IsSubTransactionAssignmentPending(void)
 		return false;
 
 	/* and it should not be already 'assigned' */
-	return !CurrentTransactionState->assigned;
+	return !CurrentTransactionState->topXidLogged;
 }
 
 /*
- * MarkSubTransactionAssigned
+ * MarkTopTransactionIdLogged
  *
- * Mark the subtransaction assignment as completed.
+ * Mark top transaction id is WAL logged for the current subtransaction.
  */
 void
-MarkSubTransactionAssigned(void)
+MarkTopTransactionIdLogged(void)
 {
-	Assert(IsSubTransactionAssignmentPending());
+	Assert(IsLogTopTransactionIdPending());
 
-	CurrentTransactionState->assigned = true;
+	CurrentTransactionState->topXidLogged = true;
 }
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index f8c714b..78232aa 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -1010,7 +1010,8 @@ XLogRecPtr
 XLogInsertRecord(XLogRecData *rdata,
 				 XLogRecPtr fpw_lsn,
 				 uint8 flags,
-				 int num_fpi)
+				 int num_fpi,
+				 bool topxid_included)
 {
 	XLogCtlInsert *Insert = &XLogCtl->Insert;
 	pg_crc32c	rdata_crc;
@@ -1163,6 +1164,10 @@ XLogInsertRecord(XLogRecData *rdata,
 
 	MarkCurrentTransactionIdLoggedIfAny();
 
+	/* Mark top transaction id is logged (if needed) */
+	if (topxid_included)
+		MarkTopTransactionIdLogged();
+
 	END_CRIT_SECTION();
 
 	/*
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index b492c65..6b5925e 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -123,7 +123,8 @@ static MemoryContext xloginsert_cxt;
 
 static XLogRecData *XLogRecordAssemble(RmgrId rmid, uint8 info,
 									   XLogRecPtr RedoRecPtr, bool doPageWrites,
-									   XLogRecPtr *fpw_lsn, int *num_fpi);
+									   XLogRecPtr *fpw_lsn, int *num_fpi,
+									   bool *topxid_included);
 static bool XLogCompressBackupBlock(char *page, uint16 hole_offset,
 									uint16 hole_length, char *dest, uint16 *dlen);
 
@@ -209,10 +210,6 @@ XLogResetInsertion(void)
 {
 	int			i;
 
-	/* reset the subxact assignment flag (if needed) */
-	if (curinsert_flags & XLOG_INCLUDE_XID)
-		MarkSubTransactionAssigned();
-
 	for (i = 0; i < max_registered_block_id; i++)
 		registered_buffers[i].in_use = false;
 
@@ -409,8 +406,6 @@ XLogRegisterBufData(uint8 block_id, char *data, int len)
  * - XLOG_MARK_UNIMPORTANT, to signal that the record is not important for
  *	 durability, which allows to avoid triggering WAL archiving and other
  *	 background activity.
- * - XLOG_INCLUDE_XID, a message-passing hack between XLogRecordAssemble
- *	 and XLogResetInsertion.
  */
 void
 XLogSetRecordFlags(uint8 flags)
@@ -465,6 +460,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 	{
 		XLogRecPtr	RedoRecPtr;
 		bool		doPageWrites;
+		bool		topxid_included = false;
 		XLogRecPtr	fpw_lsn;
 		XLogRecData *rdt;
 		int			num_fpi = 0;
@@ -477,9 +473,10 @@ XLogInsert(RmgrId rmid, uint8 info)
 		GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites);
 
 		rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites,
-								 &fpw_lsn, &num_fpi);
+								 &fpw_lsn, &num_fpi, &topxid_included);
 
-		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi);
+		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
+								  topxid_included);
 	} while (EndPos == InvalidXLogRecPtr);
 
 	XLogResetInsertion();
@@ -502,7 +499,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 static XLogRecData *
 XLogRecordAssemble(RmgrId rmid, uint8 info,
 				   XLogRecPtr RedoRecPtr, bool doPageWrites,
-				   XLogRecPtr *fpw_lsn, int *num_fpi)
+				   XLogRecPtr *fpw_lsn, int *num_fpi, bool *topxid_included)
 {
 	XLogRecData *rdt;
 	uint32		total_len = 0;
@@ -788,12 +785,12 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 	}
 
 	/* followed by toplevel XID, if not already included in previous record */
-	if (IsSubTransactionAssignmentPending())
+	if (IsLogTopTransactionIdPending())
 	{
 		TransactionId xid = GetTopTransactionIdIfAny();
 
-		/* update the flag (later used by XLogResetInsertion) */
-		XLogSetRecordFlags(XLOG_INCLUDE_XID);
+		/* Set update the flag that the top xid is included in the WAL */
+		*topxid_included = true;
 
 		*(scratch++) = (char) XLR_BLOCK_ID_TOPLEVEL_XID;
 		memcpy(scratch, &xid, sizeof(TransactionId));
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 134f686..e2dafe6 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -433,8 +433,8 @@ extern void UnregisterXactCallback(XactCallback callback, void *arg);
 extern void RegisterSubXactCallback(SubXactCallback callback, void *arg);
 extern void UnregisterSubXactCallback(SubXactCallback callback, void *arg);
 
-extern bool IsSubTransactionAssignmentPending(void);
-extern void MarkSubTransactionAssigned(void);
+extern bool IsLogTopTransactionIdPending(void);
+extern void MarkTopTransactionIdLogged(void);
 
 extern int	xactGetCommittedChildren(TransactionId **ptr);
 
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 5e2c94a..c0a5602 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -212,7 +212,6 @@ extern bool XLOG_DEBUG;
  */
 #define XLOG_INCLUDE_ORIGIN		0x01	/* include the replication origin */
 #define XLOG_MARK_UNIMPORTANT	0x02	/* record not important for durability */
-#define XLOG_INCLUDE_XID		0x04	/* WAL-internal message-passing hack */
 
 
 /* Checkpoint statistics */
@@ -258,7 +257,8 @@ struct XLogRecData;
 extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
 								   XLogRecPtr fpw_lsn,
 								   uint8 flags,
-								   int num_fpi);
+								   int num_fpi,
+								   bool topxid_included);
 extern void XLogFlush(XLogRecPtr RecPtr);
 extern bool XLogBackgroundFlush(void);
 extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
-- 
1.8.3.1

0001-Refactor-code-for-logging-the-top-transaction-id-in-Approach1.patchtext/x-patch; charset=US-ASCII; name=0001-Refactor-code-for-logging-the-top-transaction-id-in-Approach1.patchDownload
From 55a6fe0256c314ed077bf8472d5f4b5dd87d2da8 Mon Sep 17 00:00:00 2001
From: Dilip Kumar <dilipkumar@localhost.localdomain>
Date: Sat, 2 Oct 2021 16:08:57 +0530
Subject: [PATCH] Refactor code for logging the top transaction id in WAL

Instead of using the curinsert_flags, which is used for different
purpose, directly use the file level static variable.  And also
change variable/function name which looks more appropriate.
---
 src/backend/access/transam/xact.c       | 22 +++++++++++-----------
 src/backend/access/transam/xloginsert.c | 22 +++++++++++++++-------
 src/include/access/xact.h               |  4 ++--
 src/include/access/xlog.h               |  1 -
 4 files changed, 28 insertions(+), 21 deletions(-)

diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 4cc38f0..893147649 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -204,7 +204,7 @@ typedef struct TransactionStateData
 	bool		didLogXid;		/* has xid been included in WAL record? */
 	int			parallelModeLevel;	/* Enter/ExitParallelMode counter */
 	bool		chain;			/* start a new block after this one */
-	bool		assigned;		/* assigned to top-level XID */
+	bool		topXidLogged;	/* top-level XID is logged?*/
 	struct TransactionStateData *parent;	/* back link to parent */
 } TransactionStateData;
 
@@ -237,7 +237,7 @@ typedef struct SerializedTransactionState
 static TransactionStateData TopTransactionStateData = {
 	.state = TRANS_DEFAULT,
 	.blockState = TBLOCK_DEFAULT,
-	.assigned = false,
+	.topXidLogged = false,
 };
 
 /*
@@ -5159,7 +5159,7 @@ PushTransaction(void)
 	GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
 	s->prevXactReadOnly = XactReadOnly;
 	s->parallelModeLevel = 0;
-	s->assigned = false;
+	s->topXidLogged = false;
 
 	CurrentTransactionState = s;
 
@@ -6093,7 +6093,7 @@ xact_redo(XLogReaderState *record)
 }
 
 /*
- * IsSubTransactionAssignmentPending
+ * IsLogTopTransactionIdPending
  *
  * This is used to decide whether we need to WAL log the top-level XID for
  * operation in a subtransaction.  We require that for logical decoding, see
@@ -6104,7 +6104,7 @@ xact_redo(XLogReaderState *record)
  * record.
  */
 bool
-IsSubTransactionAssignmentPending(void)
+IsLogTopTransactionIdPending(void)
 {
 	/* wal_level has to be logical */
 	if (!XLogLogicalInfoActive())
@@ -6123,18 +6123,18 @@ IsSubTransactionAssignmentPending(void)
 		return false;
 
 	/* and it should not be already 'assigned' */
-	return !CurrentTransactionState->assigned;
+	return !CurrentTransactionState->topXidLogged;
 }
 
 /*
- * MarkSubTransactionAssigned
+ * MarkTopTransactionIdLogged
  *
- * Mark the subtransaction assignment as completed.
+ * Mark top transaction id is WAL logged for the current subtransaction.
  */
 void
-MarkSubTransactionAssigned(void)
+MarkTopTransactionIdLogged(void)
 {
-	Assert(IsSubTransactionAssignmentPending());
+	Assert(IsLogTopTransactionIdPending());
 
-	CurrentTransactionState->assigned = true;
+	CurrentTransactionState->topXidLogged = true;
 }
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index b492c65..2e2344b 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -100,6 +100,15 @@ static uint8 curinsert_flags = 0;
 static XLogRecData hdr_rdt;
 static char *hdr_scratch = NULL;
 
+/*
+ * This variable is used for indicating that the top transaction xid is
+ * included in the current WAL record.  This temporary flag is set by
+ * XLogRecordAssemble and used by XLogResetInsertion to mark the flag
+ * in CurrentTransactionState.  For more detail about this, refer to comments
+ * atop IsLogTopTransactionIdPending().
+ */
+static bool	topxid_included = false;
+
 #define SizeOfXlogOrigin	(sizeof(RepOriginId) + sizeof(char))
 #define SizeOfXLogTransactionId	(sizeof(TransactionId) + sizeof(char))
 
@@ -209,9 +218,9 @@ XLogResetInsertion(void)
 {
 	int			i;
 
-	/* reset the subxact assignment flag (if needed) */
-	if (curinsert_flags & XLOG_INCLUDE_XID)
-		MarkSubTransactionAssigned();
+	/* Mark top transaction id is logged (if needed) */
+	if (topxid_included)
+		MarkTopTransactionIdLogged();
 
 	for (i = 0; i < max_registered_block_id; i++)
 		registered_buffers[i].in_use = false;
@@ -222,6 +231,7 @@ XLogResetInsertion(void)
 	mainrdata_last = (XLogRecData *) &mainrdata_head;
 	curinsert_flags = 0;
 	begininsert_called = false;
+	topxid_included = false;
 }
 
 /*
@@ -409,8 +419,6 @@ XLogRegisterBufData(uint8 block_id, char *data, int len)
  * - XLOG_MARK_UNIMPORTANT, to signal that the record is not important for
  *	 durability, which allows to avoid triggering WAL archiving and other
  *	 background activity.
- * - XLOG_INCLUDE_XID, a message-passing hack between XLogRecordAssemble
- *	 and XLogResetInsertion.
  */
 void
 XLogSetRecordFlags(uint8 flags)
@@ -788,12 +796,12 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 	}
 
 	/* followed by toplevel XID, if not already included in previous record */
-	if (IsSubTransactionAssignmentPending())
+	if (IsLogTopTransactionIdPending())
 	{
 		TransactionId xid = GetTopTransactionIdIfAny();
 
 		/* update the flag (later used by XLogResetInsertion) */
-		XLogSetRecordFlags(XLOG_INCLUDE_XID);
+		topxid_included = true;
 
 		*(scratch++) = (char) XLR_BLOCK_ID_TOPLEVEL_XID;
 		memcpy(scratch, &xid, sizeof(TransactionId));
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 134f686..e2dafe6 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -433,8 +433,8 @@ extern void UnregisterXactCallback(XactCallback callback, void *arg);
 extern void RegisterSubXactCallback(SubXactCallback callback, void *arg);
 extern void UnregisterSubXactCallback(SubXactCallback callback, void *arg);
 
-extern bool IsSubTransactionAssignmentPending(void);
-extern void MarkSubTransactionAssigned(void);
+extern bool IsLogTopTransactionIdPending(void);
+extern void MarkTopTransactionIdLogged(void);
 
 extern int	xactGetCommittedChildren(TransactionId **ptr);
 
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 5e2c94a..01a6a8b 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -212,7 +212,6 @@ extern bool XLOG_DEBUG;
  */
 #define XLOG_INCLUDE_ORIGIN		0x01	/* include the replication origin */
 #define XLOG_MARK_UNIMPORTANT	0x02	/* record not important for durability */
-#define XLOG_INCLUDE_XID		0x04	/* WAL-internal message-passing hack */
 
 
 /* Checkpoint statistics */
-- 
1.8.3.1

#9Alvaro Herrera
alvherre@alvh.no-ip.org
In reply to: Dilip Kumar (#8)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On 2021-Oct-02, Dilip Kumar wrote:

I have written two patches, Approach1 is as you described using a
static boolean and Approach2 as a local variable to XLogAssembleRecord
as described by Amit, attached both of them for your reference.
IMHO, either of these approaches looks cleaner.

Thanks! I haven't read these patches carefully, but I think the
variable is about assigning the *subxid*, not the topxid. Amit can
confirm ...

--
Álvaro Herrera 39°49'30"S 73°17'W — https://www.EnterpriseDB.com/
"Aprender sin pensar es inútil; pensar sin aprender, peligroso" (Confucio)

#10Dilip Kumar
dilipbalaut@gmail.com
In reply to: Alvaro Herrera (#9)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Sat, Oct 2, 2021 at 8:10 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

On 2021-Oct-02, Dilip Kumar wrote:

I have written two patches, Approach1 is as you described using a
static boolean and Approach2 as a local variable to XLogAssembleRecord
as described by Amit, attached both of them for your reference.
IMHO, either of these approaches looks cleaner.

Thanks! I haven't read these patches carefully, but I think the
variable is about assigning the *subxid*, not the topxid. Amit can
confirm ...

IIRC, this variable is for logging the top xid in the first WAL by
each subtransaction. So that during logical decoding, while creating
the ReorderBufferTxn for the subtransaction we can associate it to the
top transaction without seeing the commit WAL.

--
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com

#11Amit Kapila
amit.kapila16@gmail.com
In reply to: Dilip Kumar (#10)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Sun, Oct 3, 2021 at 5:05 PM Dilip Kumar <dilipbalaut@gmail.com> wrote:

On Sat, Oct 2, 2021 at 8:10 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

On 2021-Oct-02, Dilip Kumar wrote:

I have written two patches, Approach1 is as you described using a
static boolean and Approach2 as a local variable to XLogAssembleRecord
as described by Amit, attached both of them for your reference.
IMHO, either of these approaches looks cleaner.

Thanks! I haven't read these patches carefully, but I think the
variable is about assigning the *subxid*, not the topxid. Amit can
confirm ...

IIRC, this variable is for logging the top xid in the first WAL by
each subtransaction. So that during logical decoding, while creating
the ReorderBufferTxn for the subtransaction we can associate it to the
top transaction without seeing the commit WAL.

This is correct.

--
With Regards,
Amit Kapila.

#12Amit Kapila
amit.kapila16@gmail.com
In reply to: Alvaro Herrera (#6)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Fri, Oct 1, 2021 at 6:23 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

On 2021-Oct-01, Amit Kapila wrote:

AFAICS, there are two possibilities w.r.t global variables: (a) use
curinsert_flags which we are doing now, (b) another is to introduce a
new global variable, set it after we make the association, and then
reset it after we mark SubTransaction assigned and on error. I have
also thought of passing it via XLogCtlInsert but as that is shared by
different processes, it can be set by one process and be read by
another process which we don't want here.

So, in my mind, curinsert_flags is a way for the high-level user of
XLogInsert to pass info about the record being inserted to the low-level
xloginsert.c infrastructure. In contrast, XLOG_INCLUDE_XID is being
used solely within xloginsert.c, by one piece of low-level
infrastructure to communicate to another piece of low-level
infrastructure that some cleanup is needed. Nothing outside of
xloginsert.c needs to know anything about XLOG_INCLUDE_XID, in contrast
with the other bits that can be set by XLogSetRecordFlags. You could
move the #define to xloginsert.c and everything would compile fine.

Another tell-tale sign that things are not fitting right is that
XLOG_INCLUDE_XID is not set via XLogSetRecordFlags, contrary the comment
above those defines.

(Aside: I wonder why do we have XLogSetRecordFlags at all -- I think we
could just pass the other two flags via XLogBeginInsert).

Agreed, I think we can do that if we want but we still need to set
curinsert_flags or some other similar variable in xloginsert.c so that
we can later use and reset it.

Regarding XLOG_INCLUDE_XID, I don't think replacing it with a bit in
shared memory is a good idea, since it only applies to the insertion
being carried out by the current process, right?

Right. Ideally, we can set this in a local variable via
XLogRecordAssemble() and then use it in XLogInsertRecord() as is done
in 0001-Refactor-code-for-logging-the-top-transaction-id-in-Approach2.
Basically, we just need to ensure that we mark the
CurrentTransactionState for this flag once we are sure that the
function XLogInsertRecord() will perform the insertion and won't
return InvalidXLogRecPtr. OTOH, I see the point in using a global
static variable to achieve this purpose as that allows to do the
required work only in xloginsert.c.

I think a straight standalone variable (probably a static boolean in
xloginsert.c) might be less confusing.

... so, reading the xact.c code again, TransactionState->assigned really
means "whether the subXID-to-topXID association has been wal-logged",
which is a completely different meaning from what the term 'assigned'
means in all other comments in xact.c ...

I think you have interpreted it correctly and we make this association
logged with the first WAL of each subtransaction if the WAL level is
logical.

--
With Regards,
Amit Kapila.

#13Robert Haas
robertmhaas@gmail.com
In reply to: Dilip Kumar (#8)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Sat, Oct 2, 2021 at 6:46 AM Dilip Kumar <dilipbalaut@gmail.com> wrote:

I have written two patches, Approach1 is as you described using a
static boolean and Approach2 as a local variable to XLogAssembleRecord
as described by Amit, attached both of them for your reference.
IMHO, either of these approaches looks cleaner.

I agree, and I don't have a strong preference between them. If I were
writing code like this from scratch, I would do what 0001 does. But
0002 is arguably more consistent with the existing style. It's kind of
hard to judge, at least for me, which is to be preferred.

--
Robert Haas
EDB: http://www.enterprisedb.com

#14Amit Kapila
amit.kapila16@gmail.com
In reply to: Dilip Kumar (#8)
1 attachment(s)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Sat, Oct 2, 2021 at 4:16 PM Dilip Kumar <dilipbalaut@gmail.com> wrote:

On Fri, Oct 1, 2021 at 6:24 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

On 2021-Oct-01, Amit Kapila wrote:

I think a straight standalone variable (probably a static boolean in
xloginsert.c) might be less confusing.

I have written two patches, Approach1 is as you described using a
static boolean and Approach2 as a local variable to XLogAssembleRecord
as described by Amit, attached both of them for your reference.
IMHO, either of these approaches looks cleaner.

I have tried to improve some comments and a variable name in the
Approach-2 (use local variable) patch and also reverts one of the
comments introduced by the commit ade24dab97. I am fine if we decide
to go with Approach-1 as well but personally, I would prefer to keep
the code consistent with nearby code.

Let me know what you think of the attached?

With Regards,
Amit Kapila.

Attachments:

v2-0001-Replace-XLOG_INCLUDE_XID-flag-with-a-more-localiz.patchapplication/octet-stream; name=v2-0001-Replace-XLOG_INCLUDE_XID-flag-with-a-more-localiz.patchDownload
From 05ae038d92be6743ede04fcfc509303850d3a50a Mon Sep 17 00:00:00 2001
From: Amit Kapila <akapila@postgresql.org>
Date: Thu, 7 Oct 2021 10:37:06 +0530
Subject: [PATCH v2] Replace XLOG_INCLUDE_XID flag with a more localized flag.

Commit 0bead9af484c introduced XLOG_INCLUDE_XID flag to indicate that the
WAL record contains subXID-to-topXID association. It uses that flag later
to mark in CurrentTransactionState that top-xid is logged so that we
should not try to log it again with the next WAL record in the current
subtransaction. However, we can use a localized variable to pass that
information.

This also reverts the changes made by commit ade24dab97 where we have
improved the documentation for XLOG_INCLUDE_XID flag.
---
 src/backend/access/transam/xact.c       | 24 ++++++++++++------------
 src/backend/access/transam/xlog.c       | 13 ++++++++++++-
 src/backend/access/transam/xloginsert.c | 23 ++++++++++-------------
 src/include/access/xact.h               |  4 ++--
 src/include/access/xlog.h               |  4 ++--
 src/include/access/xlogrecord.h         |  5 ++---
 6 files changed, 40 insertions(+), 33 deletions(-)

diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 4cc38f0..bf31949 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -204,7 +204,7 @@ typedef struct TransactionStateData
 	bool		didLogXid;		/* has xid been included in WAL record? */
 	int			parallelModeLevel;	/* Enter/ExitParallelMode counter */
 	bool		chain;			/* start a new block after this one */
-	bool		assigned;		/* assigned to top-level XID */
+	bool		topXidLogged;	/* top-level XID is logged? */
 	struct TransactionStateData *parent;	/* back link to parent */
 } TransactionStateData;
 
@@ -237,7 +237,7 @@ typedef struct SerializedTransactionState
 static TransactionStateData TopTransactionStateData = {
 	.state = TRANS_DEFAULT,
 	.blockState = TBLOCK_DEFAULT,
-	.assigned = false,
+	.topXidLogged = false,
 };
 
 /*
@@ -5159,7 +5159,7 @@ PushTransaction(void)
 	GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
 	s->prevXactReadOnly = XactReadOnly;
 	s->parallelModeLevel = 0;
-	s->assigned = false;
+	s->topXidLogged = false;
 
 	CurrentTransactionState = s;
 
@@ -6093,7 +6093,7 @@ xact_redo(XLogReaderState *record)
 }
 
 /*
- * IsSubTransactionAssignmentPending
+ * IsLogTopTransactionIdPending
  *
  * This is used to decide whether we need to WAL log the top-level XID for
  * operation in a subtransaction.  We require that for logical decoding, see
@@ -6104,7 +6104,7 @@ xact_redo(XLogReaderState *record)
  * record.
  */
 bool
-IsSubTransactionAssignmentPending(void)
+IsLogTopTransactionIdPending(void)
 {
 	/* wal_level has to be logical */
 	if (!XLogLogicalInfoActive())
@@ -6122,19 +6122,19 @@ IsSubTransactionAssignmentPending(void)
 	if (!TransactionIdIsValid(GetCurrentTransactionIdIfAny()))
 		return false;
 
-	/* and it should not be already 'assigned' */
-	return !CurrentTransactionState->assigned;
+	/* and it should not be already 'logged' */
+	return !CurrentTransactionState->topXidLogged;
 }
 
 /*
- * MarkSubTransactionAssigned
+ * MarkTopTransactionIdLogged
  *
- * Mark the subtransaction assignment as completed.
+ * Mark top transaction id is WAL logged for the current subtransaction.
  */
 void
-MarkSubTransactionAssigned(void)
+MarkTopTransactionIdLogged(void)
 {
-	Assert(IsSubTransactionAssignmentPending());
+	Assert(IsLogTopTransactionIdPending());
 
-	CurrentTransactionState->assigned = true;
+	CurrentTransactionState->topXidLogged = true;
 }
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 26dcc00..496387f 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -995,6 +995,9 @@ static void WALInsertLockUpdateInsertingAt(XLogRecPtr insertingAt);
  * 'flags' gives more in-depth control on the record being inserted. See
  * XLogSetRecordFlags() for details.
  *
+ * 'include_topxid' tells whether the top-transaction id is logged along with
+ * current subtransaction. See XLogRecordAssemble().
+ *
  * The first XLogRecData in the chain must be for the record header, and its
  * data must be MAXALIGNed.  XLogInsertRecord fills in the xl_prev and
  * xl_crc fields in the header, the rest of the header must already be filled
@@ -1010,7 +1013,8 @@ XLogRecPtr
 XLogInsertRecord(XLogRecData *rdata,
 				 XLogRecPtr fpw_lsn,
 				 uint8 flags,
-				 int num_fpi)
+				 int num_fpi,
+				 bool include_topxid)
 {
 	XLogCtlInsert *Insert = &XLogCtl->Insert;
 	pg_crc32c	rdata_crc;
@@ -1163,6 +1167,13 @@ XLogInsertRecord(XLogRecData *rdata,
 
 	MarkCurrentTransactionIdLoggedIfAny();
 
+	/*
+	 * Mark top transaction id is logged (if needed) so that we should not try
+	 * to log it again with the next WAL record in the current subtransaction.
+	 */
+	if (include_topxid)
+		MarkTopTransactionIdLogged();
+
 	END_CRIT_SECTION();
 
 	/*
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index b492c65..411b57d 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -123,7 +123,8 @@ static MemoryContext xloginsert_cxt;
 
 static XLogRecData *XLogRecordAssemble(RmgrId rmid, uint8 info,
 									   XLogRecPtr RedoRecPtr, bool doPageWrites,
-									   XLogRecPtr *fpw_lsn, int *num_fpi);
+									   XLogRecPtr *fpw_lsn, int *num_fpi,
+									   bool *topxid_included);
 static bool XLogCompressBackupBlock(char *page, uint16 hole_offset,
 									uint16 hole_length, char *dest, uint16 *dlen);
 
@@ -209,10 +210,6 @@ XLogResetInsertion(void)
 {
 	int			i;
 
-	/* reset the subxact assignment flag (if needed) */
-	if (curinsert_flags & XLOG_INCLUDE_XID)
-		MarkSubTransactionAssigned();
-
 	for (i = 0; i < max_registered_block_id; i++)
 		registered_buffers[i].in_use = false;
 
@@ -409,8 +406,6 @@ XLogRegisterBufData(uint8 block_id, char *data, int len)
  * - XLOG_MARK_UNIMPORTANT, to signal that the record is not important for
  *	 durability, which allows to avoid triggering WAL archiving and other
  *	 background activity.
- * - XLOG_INCLUDE_XID, a message-passing hack between XLogRecordAssemble
- *	 and XLogResetInsertion.
  */
 void
 XLogSetRecordFlags(uint8 flags)
@@ -465,6 +460,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 	{
 		XLogRecPtr	RedoRecPtr;
 		bool		doPageWrites;
+		bool		include_topxid = false;
 		XLogRecPtr	fpw_lsn;
 		XLogRecData *rdt;
 		int			num_fpi = 0;
@@ -477,9 +473,10 @@ XLogInsert(RmgrId rmid, uint8 info)
 		GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites);
 
 		rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites,
-								 &fpw_lsn, &num_fpi);
+								 &fpw_lsn, &num_fpi, &include_topxid);
 
-		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi);
+		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
+								  include_topxid);
 	} while (EndPos == InvalidXLogRecPtr);
 
 	XLogResetInsertion();
@@ -502,7 +499,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 static XLogRecData *
 XLogRecordAssemble(RmgrId rmid, uint8 info,
 				   XLogRecPtr RedoRecPtr, bool doPageWrites,
-				   XLogRecPtr *fpw_lsn, int *num_fpi)
+				   XLogRecPtr *fpw_lsn, int *num_fpi, bool *include_topxid)
 {
 	XLogRecData *rdt;
 	uint32		total_len = 0;
@@ -788,12 +785,12 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 	}
 
 	/* followed by toplevel XID, if not already included in previous record */
-	if (IsSubTransactionAssignmentPending())
+	if (IsLogTopTransactionIdPending())
 	{
 		TransactionId xid = GetTopTransactionIdIfAny();
 
-		/* update the flag (later used by XLogResetInsertion) */
-		XLogSetRecordFlags(XLOG_INCLUDE_XID);
+		/* Set the flag that the top xid is included in the WAL */
+		*include_topxid = true;
 
 		*(scratch++) = (char) XLR_BLOCK_ID_TOPLEVEL_XID;
 		memcpy(scratch, &xid, sizeof(TransactionId));
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 134f686..e2dafe6 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -433,8 +433,8 @@ extern void UnregisterXactCallback(XactCallback callback, void *arg);
 extern void RegisterSubXactCallback(SubXactCallback callback, void *arg);
 extern void UnregisterSubXactCallback(SubXactCallback callback, void *arg);
 
-extern bool IsSubTransactionAssignmentPending(void);
-extern void MarkSubTransactionAssigned(void);
+extern bool IsLogTopTransactionIdPending(void);
+extern void MarkTopTransactionIdLogged(void);
 
 extern int	xactGetCommittedChildren(TransactionId **ptr);
 
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 5e2c94a..c616512 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -212,7 +212,6 @@ extern bool XLOG_DEBUG;
  */
 #define XLOG_INCLUDE_ORIGIN		0x01	/* include the replication origin */
 #define XLOG_MARK_UNIMPORTANT	0x02	/* record not important for durability */
-#define XLOG_INCLUDE_XID		0x04	/* WAL-internal message-passing hack */
 
 
 /* Checkpoint statistics */
@@ -258,7 +257,8 @@ struct XLogRecData;
 extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
 								   XLogRecPtr fpw_lsn,
 								   uint8 flags,
-								   int num_fpi);
+								   int num_fpi,
+								   bool include_topxid);
 extern void XLogFlush(XLogRecPtr RecPtr);
 extern bool XLogBackgroundFlush(void);
 extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
diff --git a/src/include/access/xlogrecord.h b/src/include/access/xlogrecord.h
index 8d1305e..e06ee92 100644
--- a/src/include/access/xlogrecord.h
+++ b/src/include/access/xlogrecord.h
@@ -215,9 +215,8 @@ typedef struct XLogRecordDataHeaderLong
  * Block IDs used to distinguish different kinds of record fragments. Block
  * references are numbered from 0 to XLR_MAX_BLOCK_ID. A rmgr is free to use
  * any ID number in that range (although you should stick to small numbers,
- * because the WAL machinery is optimized for that case). A few ID
- * numbers are reserved to denote the "main" data portion of the record,
- * as well as replication-supporting transaction metadata.
+ * because the WAL machinery is optimized for that case). A couple of ID
+ * numbers are reserved to denote the "main" data portion of the record.
  *
  * The maximum is currently set at 32, quite arbitrarily. Most records only
  * need a handful of block references, but there are a few exceptions that
-- 
1.8.3.1

#15Amit Kapila
amit.kapila16@gmail.com
In reply to: Amit Kapila (#14)
1 attachment(s)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Thu, Oct 7, 2021 at 10:46 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Sat, Oct 2, 2021 at 4:16 PM Dilip Kumar <dilipbalaut@gmail.com> wrote:

On Fri, Oct 1, 2021 at 6:24 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

On 2021-Oct-01, Amit Kapila wrote:

I think a straight standalone variable (probably a static boolean in
xloginsert.c) might be less confusing.

I have written two patches, Approach1 is as you described using a
static boolean and Approach2 as a local variable to XLogAssembleRecord
as described by Amit, attached both of them for your reference.
IMHO, either of these approaches looks cleaner.

I have tried to improve some comments and a variable name in the
Approach-2 (use local variable) patch and also reverts one of the
comments introduced by the commit ade24dab97. I am fine if we decide
to go with Approach-1 as well but personally, I would prefer to keep
the code consistent with nearby code.

Let me know what you think of the attached?

Today, I have looked at this patch again and slightly changed a
comment, one of the function name and variable name. Do, let me know
if you or others have any suggestions for better names or otherwise? I
think we should backpatch this to 14 as well where this code was
introduced.

--
With Regards,
Amit Kapila.

Attachments:

v3-0001-Replace-XLOG_INCLUDE_XID-flag-with-a-more-localiz.patchapplication/octet-stream; name=v3-0001-Replace-XLOG_INCLUDE_XID-flag-with-a-more-localiz.patchDownload
From fcbb965e6ba7a444c9616bb0162913fda6e1cde3 Mon Sep 17 00:00:00 2001
From: Amit Kapila <akapila@postgresql.org>
Date: Mon, 18 Oct 2021 10:23:12 +0530
Subject: [PATCH v3] Replace XLOG_INCLUDE_XID flag with a more localized flag.

Commit 0bead9af484c introduced XLOG_INCLUDE_XID flag to indicate that the
WAL record contains subXID-to-topXID association. It uses that flag later
to mark in CurrentTransactionState that top-xid is logged so that we
should not try to log it again with the next WAL record in the current
subtransaction. However, we can use a localized variable to pass that
information.

In passing, change the related function and variable names to make them
consistent with what the code is actually doing.

This also reverts the changes made by commit ade24dab97 where we have
improved the documentation for XLOG_INCLUDE_XID flag.

Author: Dilip Kumar
Reviewed-by: Amit Kapila
Discussion: https://postgr.es/m/E1mSoYz-0007Fh-D9@gemulon.postgresql.org
---
 src/backend/access/transam/xact.c       | 25 +++++++++++++------------
 src/backend/access/transam/xlog.c       | 13 ++++++++++++-
 src/backend/access/transam/xloginsert.c | 23 ++++++++++-------------
 src/include/access/xact.h               |  4 ++--
 src/include/access/xlog.h               |  4 ++--
 src/include/access/xlogrecord.h         |  5 ++---
 6 files changed, 41 insertions(+), 33 deletions(-)

diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index d96881c0de..8f9884a69b 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -205,7 +205,7 @@ typedef struct TransactionStateData
 	bool		didLogXid;		/* has xid been included in WAL record? */
 	int			parallelModeLevel;	/* Enter/ExitParallelMode counter */
 	bool		chain;			/* start a new block after this one */
-	bool		assigned;		/* assigned to top-level XID */
+	bool		topXidLogged;	/* top-level XID is logged? */
 	struct TransactionStateData *parent;	/* back link to parent */
 } TransactionStateData;
 
@@ -238,7 +238,7 @@ typedef struct SerializedTransactionState
 static TransactionStateData TopTransactionStateData = {
 	.state = TRANS_DEFAULT,
 	.blockState = TBLOCK_DEFAULT,
-	.assigned = false,
+	.topXidLogged = false,
 };
 
 /*
@@ -5168,7 +5168,7 @@ PushTransaction(void)
 	GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
 	s->prevXactReadOnly = XactReadOnly;
 	s->parallelModeLevel = 0;
-	s->assigned = false;
+	s->topXidLogged = false;
 
 	CurrentTransactionState = s;
 
@@ -6102,7 +6102,7 @@ xact_redo(XLogReaderState *record)
 }
 
 /*
- * IsSubTransactionAssignmentPending
+ * IsTopTransactionIdLogged
  *
  * This is used to decide whether we need to WAL log the top-level XID for
  * operation in a subtransaction.  We require that for logical decoding, see
@@ -6113,7 +6113,7 @@ xact_redo(XLogReaderState *record)
  * record.
  */
 bool
-IsSubTransactionAssignmentPending(void)
+IsTopTransactionIdLogged(void)
 {
 	/* wal_level has to be logical */
 	if (!XLogLogicalInfoActive())
@@ -6131,19 +6131,20 @@ IsSubTransactionAssignmentPending(void)
 	if (!TransactionIdIsValid(GetCurrentTransactionIdIfAny()))
 		return false;
 
-	/* and it should not be already 'assigned' */
-	return !CurrentTransactionState->assigned;
+	/* and it should not be already 'logged' */
+	return !CurrentTransactionState->topXidLogged;
 }
 
 /*
- * MarkSubTransactionAssigned
+ * MarkTopTransactionIdLogged
  *
- * Mark the subtransaction assignment as completed.
+ * Remember that the top transaction id for the current subtransaction is WAL
+ * logged now.
  */
 void
-MarkSubTransactionAssigned(void)
+MarkTopTransactionIdLogged(void)
 {
-	Assert(IsSubTransactionAssignmentPending());
+	Assert(IsTopTransactionIdLogged());
 
-	CurrentTransactionState->assigned = true;
+	CurrentTransactionState->topXidLogged = true;
 }
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 62862255fc..c899bd88d8 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -998,6 +998,9 @@ static void WALInsertLockUpdateInsertingAt(XLogRecPtr insertingAt);
  * 'flags' gives more in-depth control on the record being inserted. See
  * XLogSetRecordFlags() for details.
  *
+ * 'topxid_included' tells whether the top-transaction id is logged along with
+ * current subtransaction. See XLogRecordAssemble().
+ *
  * The first XLogRecData in the chain must be for the record header, and its
  * data must be MAXALIGNed.  XLogInsertRecord fills in the xl_prev and
  * xl_crc fields in the header, the rest of the header must already be filled
@@ -1013,7 +1016,8 @@ XLogRecPtr
 XLogInsertRecord(XLogRecData *rdata,
 				 XLogRecPtr fpw_lsn,
 				 uint8 flags,
-				 int num_fpi)
+				 int num_fpi,
+				 bool topxid_included)
 {
 	XLogCtlInsert *Insert = &XLogCtl->Insert;
 	pg_crc32c	rdata_crc;
@@ -1166,6 +1170,13 @@ XLogInsertRecord(XLogRecData *rdata,
 
 	MarkCurrentTransactionIdLoggedIfAny();
 
+	/*
+	 * Mark top transaction id is logged (if needed) so that we should not try
+	 * to log it again with the next WAL record in the current subtransaction.
+	 */
+	if (topxid_included)
+		MarkTopTransactionIdLogged();
+
 	END_CRIT_SECTION();
 
 	/*
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index b492c656d7..8b76ca0286 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -123,7 +123,8 @@ static MemoryContext xloginsert_cxt;
 
 static XLogRecData *XLogRecordAssemble(RmgrId rmid, uint8 info,
 									   XLogRecPtr RedoRecPtr, bool doPageWrites,
-									   XLogRecPtr *fpw_lsn, int *num_fpi);
+									   XLogRecPtr *fpw_lsn, int *num_fpi,
+									   bool *topxid_included);
 static bool XLogCompressBackupBlock(char *page, uint16 hole_offset,
 									uint16 hole_length, char *dest, uint16 *dlen);
 
@@ -209,10 +210,6 @@ XLogResetInsertion(void)
 {
 	int			i;
 
-	/* reset the subxact assignment flag (if needed) */
-	if (curinsert_flags & XLOG_INCLUDE_XID)
-		MarkSubTransactionAssigned();
-
 	for (i = 0; i < max_registered_block_id; i++)
 		registered_buffers[i].in_use = false;
 
@@ -409,8 +406,6 @@ XLogRegisterBufData(uint8 block_id, char *data, int len)
  * - XLOG_MARK_UNIMPORTANT, to signal that the record is not important for
  *	 durability, which allows to avoid triggering WAL archiving and other
  *	 background activity.
- * - XLOG_INCLUDE_XID, a message-passing hack between XLogRecordAssemble
- *	 and XLogResetInsertion.
  */
 void
 XLogSetRecordFlags(uint8 flags)
@@ -465,6 +460,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 	{
 		XLogRecPtr	RedoRecPtr;
 		bool		doPageWrites;
+		bool		topxid_included = false;
 		XLogRecPtr	fpw_lsn;
 		XLogRecData *rdt;
 		int			num_fpi = 0;
@@ -477,9 +473,10 @@ XLogInsert(RmgrId rmid, uint8 info)
 		GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites);
 
 		rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites,
-								 &fpw_lsn, &num_fpi);
+								 &fpw_lsn, &num_fpi, &topxid_included);
 
-		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi);
+		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
+								  topxid_included);
 	} while (EndPos == InvalidXLogRecPtr);
 
 	XLogResetInsertion();
@@ -502,7 +499,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 static XLogRecData *
 XLogRecordAssemble(RmgrId rmid, uint8 info,
 				   XLogRecPtr RedoRecPtr, bool doPageWrites,
-				   XLogRecPtr *fpw_lsn, int *num_fpi)
+				   XLogRecPtr *fpw_lsn, int *num_fpi, bool *topxid_included)
 {
 	XLogRecData *rdt;
 	uint32		total_len = 0;
@@ -788,12 +785,12 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 	}
 
 	/* followed by toplevel XID, if not already included in previous record */
-	if (IsSubTransactionAssignmentPending())
+	if (IsTopTransactionIdLogged())
 	{
 		TransactionId xid = GetTopTransactionIdIfAny();
 
-		/* update the flag (later used by XLogResetInsertion) */
-		XLogSetRecordFlags(XLOG_INCLUDE_XID);
+		/* Set the flag that the top xid is included in the WAL */
+		*topxid_included = true;
 
 		*(scratch++) = (char) XLR_BLOCK_ID_TOPLEVEL_XID;
 		memcpy(scratch, &xid, sizeof(TransactionId));
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 134f6862da..e39915a86e 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -433,8 +433,8 @@ extern void UnregisterXactCallback(XactCallback callback, void *arg);
 extern void RegisterSubXactCallback(SubXactCallback callback, void *arg);
 extern void UnregisterSubXactCallback(SubXactCallback callback, void *arg);
 
-extern bool IsSubTransactionAssignmentPending(void);
-extern void MarkSubTransactionAssigned(void);
+extern bool IsTopTransactionIdLogged(void);
+extern void MarkTopTransactionIdLogged(void);
 
 extern int	xactGetCommittedChildren(TransactionId **ptr);
 
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 5e2c94a05f..c0a560204b 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -212,7 +212,6 @@ extern bool XLOG_DEBUG;
  */
 #define XLOG_INCLUDE_ORIGIN		0x01	/* include the replication origin */
 #define XLOG_MARK_UNIMPORTANT	0x02	/* record not important for durability */
-#define XLOG_INCLUDE_XID		0x04	/* WAL-internal message-passing hack */
 
 
 /* Checkpoint statistics */
@@ -258,7 +257,8 @@ struct XLogRecData;
 extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
 								   XLogRecPtr fpw_lsn,
 								   uint8 flags,
-								   int num_fpi);
+								   int num_fpi,
+								   bool topxid_included);
 extern void XLogFlush(XLogRecPtr RecPtr);
 extern bool XLogBackgroundFlush(void);
 extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
diff --git a/src/include/access/xlogrecord.h b/src/include/access/xlogrecord.h
index 8d1305eae8..e06ee92a5e 100644
--- a/src/include/access/xlogrecord.h
+++ b/src/include/access/xlogrecord.h
@@ -215,9 +215,8 @@ typedef struct XLogRecordDataHeaderLong
  * Block IDs used to distinguish different kinds of record fragments. Block
  * references are numbered from 0 to XLR_MAX_BLOCK_ID. A rmgr is free to use
  * any ID number in that range (although you should stick to small numbers,
- * because the WAL machinery is optimized for that case). A few ID
- * numbers are reserved to denote the "main" data portion of the record,
- * as well as replication-supporting transaction metadata.
+ * because the WAL machinery is optimized for that case). A couple of ID
+ * numbers are reserved to denote the "main" data portion of the record.
  *
  * The maximum is currently set at 32, quite arbitrarily. Most records only
  * need a handful of block references, but there are a few exceptions that
-- 
2.28.0.windows.1

#16Dilip Kumar
dilipbalaut@gmail.com
In reply to: Amit Kapila (#15)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Mon, Oct 18, 2021 at 10:48 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

Today, I have looked at this patch again and slightly changed a
comment, one of the function name and variable name. Do, let me know
if you or others have any suggestions for better names or otherwise? I
think we should backpatch this to 14 as well where this code was
introduced.

bool
-IsSubTransactionAssignmentPending(void)
+IsTopTransactionIdLogged(void)
{
/* wal_level has to be logical */
if (!XLogLogicalInfoActive())
@@ -6131,19 +6131,20 @@ IsSubTransactionAssignmentPending(void)
if (!TransactionIdIsValid(GetCurrentTransactionIdIfAny()))
return false;

- /* and it should not be already 'assigned' */
- return !CurrentTransactionState->assigned;
+ /* and it should not be already 'logged' */
+ return !CurrentTransactionState->topXidLogged;
 }

I have one comment here, basically, you have changed the function name
to "IsTopTransactionIdLogged", but it still behaves like
IsTopTransactionIdLogPending. Now with the new name, it should return
(CurrentTransactionState->topXidLogged) instead of
(!CurrentTransactionState->topXidLogged).

And the caller should also be changed accordingly. Other changes look fine.

--
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com

#17Amit Kapila
amit.kapila16@gmail.com
In reply to: Dilip Kumar (#16)
1 attachment(s)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Wed, Oct 20, 2021 at 10:25 AM Dilip Kumar <dilipbalaut@gmail.com> wrote:

On Mon, Oct 18, 2021 at 10:48 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

Today, I have looked at this patch again and slightly changed a
comment, one of the function name and variable name. Do, let me know
if you or others have any suggestions for better names or otherwise? I
think we should backpatch this to 14 as well where this code was
introduced.

bool
-IsSubTransactionAssignmentPending(void)
+IsTopTransactionIdLogged(void)
{
/* wal_level has to be logical */
if (!XLogLogicalInfoActive())
@@ -6131,19 +6131,20 @@ IsSubTransactionAssignmentPending(void)
if (!TransactionIdIsValid(GetCurrentTransactionIdIfAny()))
return false;

- /* and it should not be already 'assigned' */
- return !CurrentTransactionState->assigned;
+ /* and it should not be already 'logged' */
+ return !CurrentTransactionState->topXidLogged;
}

I have one comment here, basically, you have changed the function name
to "IsTopTransactionIdLogged", but it still behaves like
IsTopTransactionIdLogPending. Now with the new name, it should return
(CurrentTransactionState->topXidLogged) instead of
(!CurrentTransactionState->topXidLogged).

Valid point but I think the change suggested by you won't be
sufficient. We also need to change all the other checks in that
function to return true which will make it a bit awkward. So instead,
we can change the function name to IsTopTransactionIdLogPending().
Does that make sense?

--
With Regards,
Amit Kapila.

Attachments:

v4-0001-Replace-XLOG_INCLUDE_XID-flag-with-a-more-localiz.patchapplication/octet-stream; name=v4-0001-Replace-XLOG_INCLUDE_XID-flag-with-a-more-localiz.patchDownload
From eca2c354f24d38df7415228844e6ed928a127f25 Mon Sep 17 00:00:00 2001
From: Amit Kapila <akapila@postgresql.org>
Date: Wed, 20 Oct 2021 14:55:54 +0530
Subject: [PATCH v4] Replace XLOG_INCLUDE_XID flag with a more localized flag.

Commit 0bead9af484c introduced XLOG_INCLUDE_XID flag to indicate that the
WAL record contains subXID-to-topXID association. It uses that flag later
to mark in CurrentTransactionState that top-xid is logged so that we
should not try to log it again with the next WAL record in the current
subtransaction. However, we can use a localized variable to pass that
information.

In passing, change the related function and variable names to make them
consistent with what the code is actually doing.

This also reverts the changes made by commit ade24dab97 where we have
improved the documentation for XLOG_INCLUDE_XID flag.

Author: Dilip Kumar
Reviewed-by: Amit Kapila
Discussion: https://postgr.es/m/E1mSoYz-0007Fh-D9@gemulon.postgresql.org
---
 src/backend/access/transam/xact.c       | 25 +++++++++++++------------
 src/backend/access/transam/xlog.c       | 13 ++++++++++++-
 src/backend/access/transam/xloginsert.c | 23 ++++++++++-------------
 src/include/access/xact.h               |  4 ++--
 src/include/access/xlog.h               |  4 ++--
 src/include/access/xlogrecord.h         |  5 ++---
 6 files changed, 41 insertions(+), 33 deletions(-)

diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index d96881c0de..fe77a1bab2 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -205,7 +205,7 @@ typedef struct TransactionStateData
 	bool		didLogXid;		/* has xid been included in WAL record? */
 	int			parallelModeLevel;	/* Enter/ExitParallelMode counter */
 	bool		chain;			/* start a new block after this one */
-	bool		assigned;		/* assigned to top-level XID */
+	bool		topXidLogged;	/* top-level XID is logged? */
 	struct TransactionStateData *parent;	/* back link to parent */
 } TransactionStateData;
 
@@ -238,7 +238,7 @@ typedef struct SerializedTransactionState
 static TransactionStateData TopTransactionStateData = {
 	.state = TRANS_DEFAULT,
 	.blockState = TBLOCK_DEFAULT,
-	.assigned = false,
+	.topXidLogged = false,
 };
 
 /*
@@ -5168,7 +5168,7 @@ PushTransaction(void)
 	GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
 	s->prevXactReadOnly = XactReadOnly;
 	s->parallelModeLevel = 0;
-	s->assigned = false;
+	s->topXidLogged = false;
 
 	CurrentTransactionState = s;
 
@@ -6102,7 +6102,7 @@ xact_redo(XLogReaderState *record)
 }
 
 /*
- * IsSubTransactionAssignmentPending
+ * IsTopTransactionIdLogPending
  *
  * This is used to decide whether we need to WAL log the top-level XID for
  * operation in a subtransaction.  We require that for logical decoding, see
@@ -6113,7 +6113,7 @@ xact_redo(XLogReaderState *record)
  * record.
  */
 bool
-IsSubTransactionAssignmentPending(void)
+IsTopTransactionIdLogPending(void)
 {
 	/* wal_level has to be logical */
 	if (!XLogLogicalInfoActive())
@@ -6131,19 +6131,20 @@ IsSubTransactionAssignmentPending(void)
 	if (!TransactionIdIsValid(GetCurrentTransactionIdIfAny()))
 		return false;
 
-	/* and it should not be already 'assigned' */
-	return !CurrentTransactionState->assigned;
+	/* and it should not be already 'logged' */
+	return !CurrentTransactionState->topXidLogged;
 }
 
 /*
- * MarkSubTransactionAssigned
+ * MarkTopTransactionIdLogged
  *
- * Mark the subtransaction assignment as completed.
+ * Remember that the top transaction id for the current subtransaction is WAL
+ * logged now.
  */
 void
-MarkSubTransactionAssigned(void)
+MarkTopTransactionIdLogged(void)
 {
-	Assert(IsSubTransactionAssignmentPending());
+	Assert(IsTopTransactionIdLogPending());
 
-	CurrentTransactionState->assigned = true;
+	CurrentTransactionState->topXidLogged = true;
 }
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 62862255fc..c899bd88d8 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -998,6 +998,9 @@ static void WALInsertLockUpdateInsertingAt(XLogRecPtr insertingAt);
  * 'flags' gives more in-depth control on the record being inserted. See
  * XLogSetRecordFlags() for details.
  *
+ * 'topxid_included' tells whether the top-transaction id is logged along with
+ * current subtransaction. See XLogRecordAssemble().
+ *
  * The first XLogRecData in the chain must be for the record header, and its
  * data must be MAXALIGNed.  XLogInsertRecord fills in the xl_prev and
  * xl_crc fields in the header, the rest of the header must already be filled
@@ -1013,7 +1016,8 @@ XLogRecPtr
 XLogInsertRecord(XLogRecData *rdata,
 				 XLogRecPtr fpw_lsn,
 				 uint8 flags,
-				 int num_fpi)
+				 int num_fpi,
+				 bool topxid_included)
 {
 	XLogCtlInsert *Insert = &XLogCtl->Insert;
 	pg_crc32c	rdata_crc;
@@ -1166,6 +1170,13 @@ XLogInsertRecord(XLogRecData *rdata,
 
 	MarkCurrentTransactionIdLoggedIfAny();
 
+	/*
+	 * Mark top transaction id is logged (if needed) so that we should not try
+	 * to log it again with the next WAL record in the current subtransaction.
+	 */
+	if (topxid_included)
+		MarkTopTransactionIdLogged();
+
 	END_CRIT_SECTION();
 
 	/*
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index b492c656d7..f1babc0f02 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -123,7 +123,8 @@ static MemoryContext xloginsert_cxt;
 
 static XLogRecData *XLogRecordAssemble(RmgrId rmid, uint8 info,
 									   XLogRecPtr RedoRecPtr, bool doPageWrites,
-									   XLogRecPtr *fpw_lsn, int *num_fpi);
+									   XLogRecPtr *fpw_lsn, int *num_fpi,
+									   bool *topxid_included);
 static bool XLogCompressBackupBlock(char *page, uint16 hole_offset,
 									uint16 hole_length, char *dest, uint16 *dlen);
 
@@ -209,10 +210,6 @@ XLogResetInsertion(void)
 {
 	int			i;
 
-	/* reset the subxact assignment flag (if needed) */
-	if (curinsert_flags & XLOG_INCLUDE_XID)
-		MarkSubTransactionAssigned();
-
 	for (i = 0; i < max_registered_block_id; i++)
 		registered_buffers[i].in_use = false;
 
@@ -409,8 +406,6 @@ XLogRegisterBufData(uint8 block_id, char *data, int len)
  * - XLOG_MARK_UNIMPORTANT, to signal that the record is not important for
  *	 durability, which allows to avoid triggering WAL archiving and other
  *	 background activity.
- * - XLOG_INCLUDE_XID, a message-passing hack between XLogRecordAssemble
- *	 and XLogResetInsertion.
  */
 void
 XLogSetRecordFlags(uint8 flags)
@@ -465,6 +460,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 	{
 		XLogRecPtr	RedoRecPtr;
 		bool		doPageWrites;
+		bool		topxid_included = false;
 		XLogRecPtr	fpw_lsn;
 		XLogRecData *rdt;
 		int			num_fpi = 0;
@@ -477,9 +473,10 @@ XLogInsert(RmgrId rmid, uint8 info)
 		GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites);
 
 		rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites,
-								 &fpw_lsn, &num_fpi);
+								 &fpw_lsn, &num_fpi, &topxid_included);
 
-		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi);
+		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
+								  topxid_included);
 	} while (EndPos == InvalidXLogRecPtr);
 
 	XLogResetInsertion();
@@ -502,7 +499,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 static XLogRecData *
 XLogRecordAssemble(RmgrId rmid, uint8 info,
 				   XLogRecPtr RedoRecPtr, bool doPageWrites,
-				   XLogRecPtr *fpw_lsn, int *num_fpi)
+				   XLogRecPtr *fpw_lsn, int *num_fpi, bool *topxid_included)
 {
 	XLogRecData *rdt;
 	uint32		total_len = 0;
@@ -788,12 +785,12 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 	}
 
 	/* followed by toplevel XID, if not already included in previous record */
-	if (IsSubTransactionAssignmentPending())
+	if (IsTopTransactionIdLogPending())
 	{
 		TransactionId xid = GetTopTransactionIdIfAny();
 
-		/* update the flag (later used by XLogResetInsertion) */
-		XLogSetRecordFlags(XLOG_INCLUDE_XID);
+		/* Set the flag that the top xid is included in the WAL */
+		*topxid_included = true;
 
 		*(scratch++) = (char) XLR_BLOCK_ID_TOPLEVEL_XID;
 		memcpy(scratch, &xid, sizeof(TransactionId));
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 134f6862da..0f24bcd062 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -433,8 +433,8 @@ extern void UnregisterXactCallback(XactCallback callback, void *arg);
 extern void RegisterSubXactCallback(SubXactCallback callback, void *arg);
 extern void UnregisterSubXactCallback(SubXactCallback callback, void *arg);
 
-extern bool IsSubTransactionAssignmentPending(void);
-extern void MarkSubTransactionAssigned(void);
+extern bool IsTopTransactionIdLogPending(void);
+extern void MarkTopTransactionIdLogged(void);
 
 extern int	xactGetCommittedChildren(TransactionId **ptr);
 
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 5e2c94a05f..c0a560204b 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -212,7 +212,6 @@ extern bool XLOG_DEBUG;
  */
 #define XLOG_INCLUDE_ORIGIN		0x01	/* include the replication origin */
 #define XLOG_MARK_UNIMPORTANT	0x02	/* record not important for durability */
-#define XLOG_INCLUDE_XID		0x04	/* WAL-internal message-passing hack */
 
 
 /* Checkpoint statistics */
@@ -258,7 +257,8 @@ struct XLogRecData;
 extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
 								   XLogRecPtr fpw_lsn,
 								   uint8 flags,
-								   int num_fpi);
+								   int num_fpi,
+								   bool topxid_included);
 extern void XLogFlush(XLogRecPtr RecPtr);
 extern bool XLogBackgroundFlush(void);
 extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
diff --git a/src/include/access/xlogrecord.h b/src/include/access/xlogrecord.h
index 8d1305eae8..e06ee92a5e 100644
--- a/src/include/access/xlogrecord.h
+++ b/src/include/access/xlogrecord.h
@@ -215,9 +215,8 @@ typedef struct XLogRecordDataHeaderLong
  * Block IDs used to distinguish different kinds of record fragments. Block
  * references are numbered from 0 to XLR_MAX_BLOCK_ID. A rmgr is free to use
  * any ID number in that range (although you should stick to small numbers,
- * because the WAL machinery is optimized for that case). A few ID
- * numbers are reserved to denote the "main" data portion of the record,
- * as well as replication-supporting transaction metadata.
+ * because the WAL machinery is optimized for that case). A couple of ID
+ * numbers are reserved to denote the "main" data portion of the record.
  *
  * The maximum is currently set at 32, quite arbitrarily. Most records only
  * need a handful of block references, but there are a few exceptions that
-- 
2.28.0.windows.1

#18Dilip Kumar
dilipbalaut@gmail.com
In reply to: Amit Kapila (#17)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Wed, Oct 20, 2021 at 4:17 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Wed, Oct 20, 2021 at 10:25 AM Dilip Kumar <dilipbalaut@gmail.com> wrote:

I have one comment here, basically, you have changed the function name
to "IsTopTransactionIdLogged", but it still behaves like
IsTopTransactionIdLogPending. Now with the new name, it should return
(CurrentTransactionState->topXidLogged) instead of
(!CurrentTransactionState->topXidLogged).

Valid point but I think the change suggested by you won't be
sufficient. We also need to change all the other checks in that
function to return true which will make it a bit awkward. So instead,
we can change the function name to IsTopTransactionIdLogPending().
Does that make sense?

Yeah, that makes sense.

--
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com

#19Alvaro Herrera
alvherre@alvh.no-ip.org
In reply to: Amit Kapila (#17)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

API-wise, this seems a good improvement and it brings a lot of clarity
to what is really going on. Thanks for working on it.

Some minor comments:

Please do not revert the comment change in xlogrecord.h. It is not
wrong. The exceptions mentioned are values 252-255, so "a few" is
better than "a couple".

In IsTopTransactionIdLogPending(), I suggest to reorder the tests so
that the faster ones are first -- or at least, the last one should be at
the top, so in some cases we can return without additional function
calls. I don't think it'd be extremely noticeable, but as Tom likes to
say, a cycle shaved is a cycle earned.

XLogRecordAssemble's comment should explain its new output argument.
Maybe "*topxid_included is set if the topmost transaction ID is logged
with the current subtransaction".

I think these new routines IsTopTransactionIdLogPending and
MarkTopTransactionIdLogged should not be at the end of the file; a
location closer to where MarkCurrentTransactionIdLoggedIfAny() seems
more appropriate. Keep related things closer. (In this case these are
operating on TransactionStateData, and it looks right that they would
appear somewhat about AssignTransactionId and
GetStableLatestTransactionId.)

Does MarkTopTransactionIdLogged() have to be inside XLogInsertRecord's
critical section?

The names IsTopTransactionIdLogPending() and
MarkTopTransactionIdLogged() irk me somewhat. It's not at all obvious
from these names that these routines are mostly about actions taken for
a subtransaction. I propose IsSubxactTopXidLogPending() and
MarkSubxactTopXidLogged(). I don't feel the need to expand "Xid" to
"TransactionId" in these function names.

In TransactionStateData, I propose this wording for the comment:

bool topXidLogged; /* for a subxact: is top-level XID logged? */

Thanks!

--
Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/
"Cuando mañana llegue pelearemos segun lo que mañana exija" (Mowgli)

#20Dilip Kumar
dilipbalaut@gmail.com
In reply to: Alvaro Herrera (#19)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Wed, Oct 20, 2021 at 7:09 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

API-wise, this seems a good improvement and it brings a lot of clarity
to what is really going on. Thanks for working on it.

Some minor comments:

Thanks for the review, most of the comments look fine, and will work
on those, but I think some of them need more thoughts so replying to
those.

In IsTopTransactionIdLogPending(), I suggest to reorder the tests so
that the faster ones are first -- or at least, the last one should be at
the top, so in some cases we can return without additional function
calls. I don't think it'd be extremely noticeable, but as Tom likes to
say, a cycle shaved is a cycle earned.

I don't think we can really move the last at top. Basically, we only
want to log the top transaction id if all the above check passes and
the top xid is not yet logged. For example, if the WAL level is not
logical then we don't want to log the top xid even if it is not yet
logged, similarly, if the current transaction is not a subtransaction
then also we don't want to log the top transaction.

Does MarkTopTransactionIdLogged() have to be inside XLogInsertRecord's
critical section?

I think this function is doing somewhat similar things to what we are
doing in MarkCurrentTransactionIdLoggedIfAny() so put at the same
place. But I don't see any reason for this to be in the critical
section.

--
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com

#21Alvaro Herrera
alvherre@alvh.no-ip.org
In reply to: Dilip Kumar (#20)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On 2021-Oct-20, Dilip Kumar wrote:

On Wed, Oct 20, 2021 at 7:09 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

In IsTopTransactionIdLogPending(), I suggest to reorder the tests so
that the faster ones are first -- or at least, the last one should be at
the top, so in some cases we can return without additional function
calls. I don't think it'd be extremely noticeable, but as Tom likes to
say, a cycle shaved is a cycle earned.

I don't think we can really move the last at top. Basically, we only
want to log the top transaction id if all the above check passes and
the top xid is not yet logged. For example, if the WAL level is not
logical then we don't want to log the top xid even if it is not yet
logged, similarly, if the current transaction is not a subtransaction
then also we don't want to log the top transaction.

Well, I don't suggest to move it verbatim, but ISTM the code can be
restructured so that we do that test first, and if we see that flag set
to true, we don't have to consider any of the other tests. That flag
can only be set true if we saw all the other checks pass in the same
subtransaction, right?

--
Álvaro Herrera 39°49'30"S 73°17'W — https://www.EnterpriseDB.com/

#22Dilip Kumar
dilipbalaut@gmail.com
In reply to: Alvaro Herrera (#21)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Wed, Oct 20, 2021 at 9:46 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

On 2021-Oct-20, Dilip Kumar wrote:

On Wed, Oct 20, 2021 at 7:09 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

In IsTopTransactionIdLogPending(), I suggest to reorder the tests so
that the faster ones are first -- or at least, the last one should be at
the top, so in some cases we can return without additional function
calls. I don't think it'd be extremely noticeable, but as Tom likes to
say, a cycle shaved is a cycle earned.

I don't think we can really move the last at top. Basically, we only
want to log the top transaction id if all the above check passes and
the top xid is not yet logged. For example, if the WAL level is not
logical then we don't want to log the top xid even if it is not yet
logged, similarly, if the current transaction is not a subtransaction
then also we don't want to log the top transaction.

Well, I don't suggest to move it verbatim, but ISTM the code can be
restructured so that we do that test first, and if we see that flag set
to true, we don't have to consider any of the other tests. That flag
can only be set true if we saw all the other checks pass in the same
subtransaction, right?

Yeah you are right, I will change it.

--
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com

#23Amit Kapila
amit.kapila16@gmail.com
In reply to: Dilip Kumar (#20)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Wed, Oct 20, 2021 at 8:49 PM Dilip Kumar <dilipbalaut@gmail.com> wrote:

On Wed, Oct 20, 2021 at 7:09 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

Does MarkTopTransactionIdLogged() have to be inside XLogInsertRecord's
critical section?

I think this function is doing somewhat similar things to what we are
doing in MarkCurrentTransactionIdLoggedIfAny() so put at the same
place. But I don't see any reason for this to be in the critical
section.

Yeah, I also don't see any reason for this to be in the critical
section but it might be better to keep both together. So, if we want
to keep MarkTopTransactionIdLogged() out of the critical section in
this patch then we should move the existing function
MarkCurrentTransactionIdLoggedIfAny() in a separate patch so that
future readers doesn't get confused as to why one of these is in the
critical section and other is not. OTOH, we can move
MarkCurrentTransactionIdLoggedIfAny() out of the critical section in
this patch itself but that appears like an unrelated change and we may
or may not want to back-patch the same.

--
With Regards,
Amit Kapila.

#24Dilip Kumar
dilipbalaut@gmail.com
In reply to: Amit Kapila (#23)
2 attachment(s)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Thu, Oct 21, 2021 at 9:11 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Wed, Oct 20, 2021 at 8:49 PM Dilip Kumar <dilipbalaut@gmail.com> wrote:

On Wed, Oct 20, 2021 at 7:09 PM Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

Does MarkTopTransactionIdLogged() have to be inside XLogInsertRecord's
critical section?

I think this function is doing somewhat similar things to what we are
doing in MarkCurrentTransactionIdLoggedIfAny() so put at the same
place. But I don't see any reason for this to be in the critical
section.

Yeah, I also don't see any reason for this to be in the critical
section but it might be better to keep both together. So, if we want
to keep MarkTopTransactionIdLogged() out of the critical section in
this patch then we should move the existing function
MarkCurrentTransactionIdLoggedIfAny() in a separate patch so that
future readers doesn't get confused as to why one of these is in the
critical section and other is not. OTOH, we can move
MarkCurrentTransactionIdLoggedIfAny() out of the critical section in
this patch itself but that appears like an unrelated change and we may
or may not want to back-patch the same.

v5-0001, incorporates all the comment fixes suggested by Alvaro. and
0001 is an additional patch which moves
MarkCurrentTransactionIdLoggedIfAny(), out of the critical section.

--
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v5-0001-Replace-XLOG_INCLUDE_XID-flag-with-a-more-localiz.patchtext/x-patch; charset=US-ASCII; name=v5-0001-Replace-XLOG_INCLUDE_XID-flag-with-a-more-localiz.patchDownload
From 797f274c395f56b72f1d7ec5ee20099f73d6fa9f Mon Sep 17 00:00:00 2001
From: Dilip Kumar <dilipkumar@localhost.localdomain>
Date: Thu, 21 Oct 2021 09:52:09 +0530
Subject: [PATCH v5 1/2] Replace XLOG_INCLUDE_XID flag with a more localized
 flag.

Commit 0bead9af484c introduced XLOG_INCLUDE_XID flag to indicate that the
WAL record contains subXID-to-topXID association. It uses that flag later
to mark in CurrentTransactionState that top-xid is logged so that we
should not try to log it again with the next WAL record in the current
subtransaction. However, we can use a localized variable to pass that
information.

In passing, change the related function and variable names to make them
consistent with what the code is actually doing.

This also reverts the changes made by commit ade24dab97 where we have
improved the documentation for XLOG_INCLUDE_XID flag.

Author: Dilip Kumar
Reviewed-by: Amit Kapila
Discussion: https://postgr.es/m/E1mSoYz-0007Fh-D9@gemulon.postgresql.org
---
 src/backend/access/transam/xact.c       | 103 ++++++++++++++++----------------
 src/backend/access/transam/xlog.c       |  13 +++-
 src/backend/access/transam/xloginsert.c |  26 ++++----
 src/include/access/xact.h               |   4 +-
 src/include/access/xlog.h               |   4 +-
 5 files changed, 82 insertions(+), 68 deletions(-)

diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index d96881c..90e689e 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -205,7 +205,7 @@ typedef struct TransactionStateData
 	bool		didLogXid;		/* has xid been included in WAL record? */
 	int			parallelModeLevel;	/* Enter/ExitParallelMode counter */
 	bool		chain;			/* start a new block after this one */
-	bool		assigned;		/* assigned to top-level XID */
+	bool		topXidLogged;	/* for a subxact: is top-level XID logged? */
 	struct TransactionStateData *parent;	/* back link to parent */
 } TransactionStateData;
 
@@ -238,7 +238,7 @@ typedef struct SerializedTransactionState
 static TransactionStateData TopTransactionStateData = {
 	.state = TRANS_DEFAULT,
 	.blockState = TBLOCK_DEFAULT,
-	.assigned = false,
+	.topXidLogged = false,
 };
 
 /*
@@ -529,6 +529,56 @@ MarkCurrentTransactionIdLoggedIfAny(void)
 		CurrentTransactionState->didLogXid = true;
 }
 
+/*
+ * IsSubxactTopXidLogPending
+ *
+ * This is used to decide whether we need to WAL log the top-level XID for
+ * operation in a subtransaction.  We require that for logical decoding, see
+ * LogicalDecodingProcessRecord.
+ *
+ * This returns true if wal_level >= logical and we are inside a valid
+ * subtransaction, for which the assignment was not yet written to any WAL
+ * record.
+ */
+bool
+IsSubxactTopXidLogPending(void)
+{
+	/* check whether it is already logged */
+	if (CurrentTransactionState->topXidLogged)
+		return false;
+
+	/* wal_level has to be logical */
+	if (!XLogLogicalInfoActive())
+		return false;
+
+	/* we need to be in a transaction state */
+	if (!IsTransactionState())
+		return false;
+
+	/* it has to be a subtransaction */
+	if (!IsSubTransaction())
+		return false;
+
+	/* the subtransaction has to have a XID assigned */
+	if (!TransactionIdIsValid(GetCurrentTransactionIdIfAny()))
+		return false;
+
+	return true;
+}
+
+/*
+ * MarkSubxactTopXidLogged
+ *
+ * Remember that the top transaction id for the current subtransaction is WAL
+ * logged now.
+ */
+void
+MarkSubxactTopXidLogged(void)
+{
+	Assert(IsSubxactTopXidLogPending());
+
+	CurrentTransactionState->topXidLogged = true;
+}
 
 /*
  *	GetStableLatestTransactionId
@@ -5168,7 +5218,7 @@ PushTransaction(void)
 	GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
 	s->prevXactReadOnly = XactReadOnly;
 	s->parallelModeLevel = 0;
-	s->assigned = false;
+	s->topXidLogged = false;
 
 	CurrentTransactionState = s;
 
@@ -6100,50 +6150,3 @@ xact_redo(XLogReaderState *record)
 	else
 		elog(PANIC, "xact_redo: unknown op code %u", info);
 }
-
-/*
- * IsSubTransactionAssignmentPending
- *
- * This is used to decide whether we need to WAL log the top-level XID for
- * operation in a subtransaction.  We require that for logical decoding, see
- * LogicalDecodingProcessRecord.
- *
- * This returns true if wal_level >= logical and we are inside a valid
- * subtransaction, for which the assignment was not yet written to any WAL
- * record.
- */
-bool
-IsSubTransactionAssignmentPending(void)
-{
-	/* wal_level has to be logical */
-	if (!XLogLogicalInfoActive())
-		return false;
-
-	/* we need to be in a transaction state */
-	if (!IsTransactionState())
-		return false;
-
-	/* it has to be a subtransaction */
-	if (!IsSubTransaction())
-		return false;
-
-	/* the subtransaction has to have a XID assigned */
-	if (!TransactionIdIsValid(GetCurrentTransactionIdIfAny()))
-		return false;
-
-	/* and it should not be already 'assigned' */
-	return !CurrentTransactionState->assigned;
-}
-
-/*
- * MarkSubTransactionAssigned
- *
- * Mark the subtransaction assignment as completed.
- */
-void
-MarkSubTransactionAssigned(void)
-{
-	Assert(IsSubTransactionAssignmentPending());
-
-	CurrentTransactionState->assigned = true;
-}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 6286225..ee30315 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -998,6 +998,9 @@ static void WALInsertLockUpdateInsertingAt(XLogRecPtr insertingAt);
  * 'flags' gives more in-depth control on the record being inserted. See
  * XLogSetRecordFlags() for details.
  *
+ * 'topxid_included' tells whether the top-transaction id is logged along with
+ * current subtransaction. See XLogRecordAssemble().
+ *
  * The first XLogRecData in the chain must be for the record header, and its
  * data must be MAXALIGNed.  XLogInsertRecord fills in the xl_prev and
  * xl_crc fields in the header, the rest of the header must already be filled
@@ -1013,7 +1016,8 @@ XLogRecPtr
 XLogInsertRecord(XLogRecData *rdata,
 				 XLogRecPtr fpw_lsn,
 				 uint8 flags,
-				 int num_fpi)
+				 int num_fpi,
+				 bool topxid_included)
 {
 	XLogCtlInsert *Insert = &XLogCtl->Insert;
 	pg_crc32c	rdata_crc;
@@ -1169,6 +1173,13 @@ XLogInsertRecord(XLogRecData *rdata,
 	END_CRIT_SECTION();
 
 	/*
+	 * Mark top transaction id is logged (if needed) so that we should not try
+	 * to log it again with the next WAL record in the current subtransaction.
+	 */
+	if (topxid_included)
+		MarkSubxactTopXidLogged();
+
+	/*
 	 * Update shared LogwrtRqst.Write, if we crossed page boundary.
 	 */
 	if (StartPos / XLOG_BLCKSZ != EndPos / XLOG_BLCKSZ)
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index b492c65..689384a 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -123,7 +123,8 @@ static MemoryContext xloginsert_cxt;
 
 static XLogRecData *XLogRecordAssemble(RmgrId rmid, uint8 info,
 									   XLogRecPtr RedoRecPtr, bool doPageWrites,
-									   XLogRecPtr *fpw_lsn, int *num_fpi);
+									   XLogRecPtr *fpw_lsn, int *num_fpi,
+									   bool *topxid_included);
 static bool XLogCompressBackupBlock(char *page, uint16 hole_offset,
 									uint16 hole_length, char *dest, uint16 *dlen);
 
@@ -209,10 +210,6 @@ XLogResetInsertion(void)
 {
 	int			i;
 
-	/* reset the subxact assignment flag (if needed) */
-	if (curinsert_flags & XLOG_INCLUDE_XID)
-		MarkSubTransactionAssigned();
-
 	for (i = 0; i < max_registered_block_id; i++)
 		registered_buffers[i].in_use = false;
 
@@ -409,8 +406,6 @@ XLogRegisterBufData(uint8 block_id, char *data, int len)
  * - XLOG_MARK_UNIMPORTANT, to signal that the record is not important for
  *	 durability, which allows to avoid triggering WAL archiving and other
  *	 background activity.
- * - XLOG_INCLUDE_XID, a message-passing hack between XLogRecordAssemble
- *	 and XLogResetInsertion.
  */
 void
 XLogSetRecordFlags(uint8 flags)
@@ -465,6 +460,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 	{
 		XLogRecPtr	RedoRecPtr;
 		bool		doPageWrites;
+		bool		topxid_included = false;
 		XLogRecPtr	fpw_lsn;
 		XLogRecData *rdt;
 		int			num_fpi = 0;
@@ -477,9 +473,10 @@ XLogInsert(RmgrId rmid, uint8 info)
 		GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites);
 
 		rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites,
-								 &fpw_lsn, &num_fpi);
+								 &fpw_lsn, &num_fpi, &topxid_included);
 
-		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi);
+		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
+								  topxid_included);
 	} while (EndPos == InvalidXLogRecPtr);
 
 	XLogResetInsertion();
@@ -498,11 +495,14 @@ XLogInsert(RmgrId rmid, uint8 info)
  * of all of them, *fpw_lsn is set to the lowest LSN among such pages. This
  * signals that the assembled record is only good for insertion on the
  * assumption that the RedoRecPtr and doPageWrites values were up-to-date.
+ *
+ * *topxid_included is set if the topmost transaction ID is logged with the
+ * current subtransaction.
  */
 static XLogRecData *
 XLogRecordAssemble(RmgrId rmid, uint8 info,
 				   XLogRecPtr RedoRecPtr, bool doPageWrites,
-				   XLogRecPtr *fpw_lsn, int *num_fpi)
+				   XLogRecPtr *fpw_lsn, int *num_fpi, bool *topxid_included)
 {
 	XLogRecData *rdt;
 	uint32		total_len = 0;
@@ -788,12 +788,12 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 	}
 
 	/* followed by toplevel XID, if not already included in previous record */
-	if (IsSubTransactionAssignmentPending())
+	if (IsSubxactTopXidLogPending())
 	{
 		TransactionId xid = GetTopTransactionIdIfAny();
 
-		/* update the flag (later used by XLogResetInsertion) */
-		XLogSetRecordFlags(XLOG_INCLUDE_XID);
+		/* Set the flag that the top xid is included in the WAL */
+		*topxid_included = true;
 
 		*(scratch++) = (char) XLR_BLOCK_ID_TOPLEVEL_XID;
 		memcpy(scratch, &xid, sizeof(TransactionId));
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 134f686..5546d33 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -433,8 +433,8 @@ extern void UnregisterXactCallback(XactCallback callback, void *arg);
 extern void RegisterSubXactCallback(SubXactCallback callback, void *arg);
 extern void UnregisterSubXactCallback(SubXactCallback callback, void *arg);
 
-extern bool IsSubTransactionAssignmentPending(void);
-extern void MarkSubTransactionAssigned(void);
+extern bool IsSubxactTopXidLogPending(void);
+extern void MarkSubxactTopXidLogged(void);
 
 extern int	xactGetCommittedChildren(TransactionId **ptr);
 
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 5e2c94a..c0a5602 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -212,7 +212,6 @@ extern bool XLOG_DEBUG;
  */
 #define XLOG_INCLUDE_ORIGIN		0x01	/* include the replication origin */
 #define XLOG_MARK_UNIMPORTANT	0x02	/* record not important for durability */
-#define XLOG_INCLUDE_XID		0x04	/* WAL-internal message-passing hack */
 
 
 /* Checkpoint statistics */
@@ -258,7 +257,8 @@ struct XLogRecData;
 extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
 								   XLogRecPtr fpw_lsn,
 								   uint8 flags,
-								   int num_fpi);
+								   int num_fpi,
+								   bool topxid_included);
 extern void XLogFlush(XLogRecPtr RecPtr);
 extern bool XLogBackgroundFlush(void);
 extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
-- 
1.8.3.1

0001-Code-refactoring-move-unwanted-function-out-of-the-c.patchtext/x-patch; charset=US-ASCII; name=0001-Code-refactoring-move-unwanted-function-out-of-the-c.patchDownload
From df06247d10325c0b659f7fdcb8a6c6c32828ef82 Mon Sep 17 00:00:00 2001
From: Dilip Kumar <dilipkumar@localhost.localdomain>
Date: Thu, 21 Oct 2021 11:15:30 +0530
Subject: [PATCH] Code refactoring, move unwanted function out of the critical
 section

Move MarkCurrentTransactionIdLoggedIfAny out of the critical
section.
---
 src/backend/access/transam/xlog.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index ee30315..28935e4 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -1168,10 +1168,10 @@ XLogInsertRecord(XLogRecData *rdata,
 	 */
 	WALInsertLockRelease();
 
-	MarkCurrentTransactionIdLoggedIfAny();
-
 	END_CRIT_SECTION();
 
+	MarkCurrentTransactionIdLoggedIfAny();
+
 	/*
 	 * Mark top transaction id is logged (if needed) so that we should not try
 	 * to log it again with the next WAL record in the current subtransaction.
-- 
1.8.3.1

#25Amit Kapila
amit.kapila16@gmail.com
In reply to: Dilip Kumar (#24)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Thu, Oct 21, 2021 at 11:20 AM Dilip Kumar <dilipbalaut@gmail.com> wrote:

On Thu, Oct 21, 2021 at 9:11 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

v5-0001, incorporates all the comment fixes suggested by Alvaro. and
0001 is an additional patch which moves
MarkCurrentTransactionIdLoggedIfAny(), out of the critical section.

Thanks, both your patches look good to me except that we need to
remove the sentence related to the revert of ade24dab97 from the
commit message. I think we should backpatch the first patch to 14
where it was introduced and commit the second patch (related to moving
code out of critical section) only to HEAD but we can even backpatch
the second one till 9.6 for the sake of consistency. What do you guys
think?

--
With Regards,
Amit Kapila.

#26Amit Kapila
amit.kapila16@gmail.com
In reply to: Amit Kapila (#25)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Mon, Oct 25, 2021 at 4:21 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Thu, Oct 21, 2021 at 11:20 AM Dilip Kumar <dilipbalaut@gmail.com> wrote:

On Thu, Oct 21, 2021 at 9:11 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

v5-0001, incorporates all the comment fixes suggested by Alvaro. and
0001 is an additional patch which moves
MarkCurrentTransactionIdLoggedIfAny(), out of the critical section.

Thanks, both your patches look good to me except that we need to
remove the sentence related to the revert of ade24dab97 from the
commit message. I think we should backpatch the first patch to 14
where it was introduced and commit the second patch (related to moving
code out of critical section) only to HEAD but we can even backpatch
the second one till 9.6 for the sake of consistency. What do you guys
think?

The other option could be to just commit both these patches in HEAD as
there is no correctness issue here.

--
With Regards,
Amit Kapila.

#27Dilip Kumar
dilipbalaut@gmail.com
In reply to: Amit Kapila (#26)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Tue, Oct 26, 2021 at 9:19 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Mon, Oct 25, 2021 at 4:21 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Thu, Oct 21, 2021 at 11:20 AM Dilip Kumar <dilipbalaut@gmail.com> wrote:

On Thu, Oct 21, 2021 at 9:11 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

v5-0001, incorporates all the comment fixes suggested by Alvaro. and
0001 is an additional patch which moves
MarkCurrentTransactionIdLoggedIfAny(), out of the critical section.

Thanks, both your patches look good to me except that we need to
remove the sentence related to the revert of ade24dab97 from the
commit message. I think we should backpatch the first patch to 14
where it was introduced and commit the second patch (related to moving
code out of critical section) only to HEAD but we can even backpatch
the second one till 9.6 for the sake of consistency. What do you guys
think?

The other option could be to just commit both these patches in HEAD as
there is no correctness issue here.

Right, even I feel we should just commit it to the HEAD as there is no
correctness issue.

--
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com

#28Amit Kapila
amit.kapila16@gmail.com
In reply to: Dilip Kumar (#27)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Wed, Oct 27, 2021 at 4:39 PM Dilip Kumar <dilipbalaut@gmail.com> wrote:

On Tue, Oct 26, 2021 at 9:19 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

Thanks, both your patches look good to me except that we need to
remove the sentence related to the revert of ade24dab97 from the
commit message. I think we should backpatch the first patch to 14
where it was introduced and commit the second patch (related to moving
code out of critical section) only to HEAD but we can even backpatch
the second one till 9.6 for the sake of consistency. What do you guys
think?

The other option could be to just commit both these patches in HEAD as
there is no correctness issue here.

Right, even I feel we should just commit it to the HEAD as there is no
correctness issue.

Thanks for your opinion. I'll commit it to the HEAD by next Tuesday
unless someone feels that we should backpatch this.

--
With Regards,
Amit Kapila.

#29Amit Kapila
amit.kapila16@gmail.com
In reply to: Amit Kapila (#28)
Re: pgsql: Document XLOG_INCLUDE_XID a little better

On Thu, Oct 28, 2021 at 8:15 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Wed, Oct 27, 2021 at 4:39 PM Dilip Kumar <dilipbalaut@gmail.com> wrote:

On Tue, Oct 26, 2021 at 9:19 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

Thanks, both your patches look good to me except that we need to
remove the sentence related to the revert of ade24dab97 from the
commit message. I think we should backpatch the first patch to 14
where it was introduced and commit the second patch (related to moving
code out of critical section) only to HEAD but we can even backpatch
the second one till 9.6 for the sake of consistency. What do you guys
think?

The other option could be to just commit both these patches in HEAD as
there is no correctness issue here.

Right, even I feel we should just commit it to the HEAD as there is no
correctness issue.

Thanks for your opinion. I'll commit it to the HEAD by next Tuesday
unless someone feels that we should backpatch this.

Pushed.

--
With Regards,
Amit Kapila.