Remove extraneous break condition in logical slot advance function

Started by Bharath Rupireddyabout 2 years ago5 messages
#1Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
1 attachment(s)

Hi,

There exists an extraneous break condition in
pg_logical_replication_slot_advance(). When the end of WAL or moveto
LSN is reached, the main while condition helps to exit the loop, so no
separate break condition is needed. Attached patch removes it.

Thoughts?

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

Attachments:

v1-0001-Remove-extraneous-break-condition-in-logical-slot.patchapplication/octet-stream; name=v1-0001-Remove-extraneous-break-condition-in-logical-slot.patchDownload
From bc1ebcce98a935c34944bfd5355f04e36e776214 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Sat, 21 Oct 2023 00:12:57 +0000
Subject: [PATCH v1] Remove extraneous break condition in logical slot advance
 function

There exists an extraneous break condition in
pg_logical_replication_slot_advance(). When end of WAL or moveto
LSN is reached, the main while condition helps to exit the loop,
so no separate break condition is needed.
---
 src/backend/replication/slotfuncs.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 6035cf4816..4e5581e7ff 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -523,10 +523,6 @@ pg_logical_replication_slot_advance(XLogRecPtr moveto)
 			if (record)
 				LogicalDecodingProcessRecord(ctx, ctx->reader);
 
-			/* Stop once the requested target has been reached */
-			if (moveto <= ctx->reader->EndRecPtr)
-				break;
-
 			CHECK_FOR_INTERRUPTS();
 		}
 
-- 
2.34.1

#2Gurjeet Singh
gurjeet@singh.im
In reply to: Bharath Rupireddy (#1)
Re: Remove extraneous break condition in logical slot advance function

On Fri, Oct 20, 2023 at 7:30 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

Hi,

There exists an extraneous break condition in
pg_logical_replication_slot_advance(). When the end of WAL or moveto
LSN is reached, the main while condition helps to exit the loop, so no
separate break condition is needed. Attached patch removes it.

Thoughts?

+1 for the patch.

The only advantage I see of the code as it stands right now is that it
avoids one last call to CHECK_FOR_INTERRUPTS() by break'ing early. I
don't think we'd lose much in terms of performance by making one (very
cheap, in common case) extra call of this macro.

Best regards,
Gurjeet
http://Gurje.et

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: Gurjeet Singh (#2)
Re: Remove extraneous break condition in logical slot advance function

Gurjeet Singh <gurjeet@singh.im> writes:

On Fri, Oct 20, 2023 at 7:30 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

There exists an extraneous break condition in
pg_logical_replication_slot_advance(). When the end of WAL or moveto
LSN is reached, the main while condition helps to exit the loop, so no
separate break condition is needed. Attached patch removes it.

The only advantage I see of the code as it stands right now is that it
avoids one last call to CHECK_FOR_INTERRUPTS() by break'ing early. I
don't think we'd lose much in terms of performance by making one (very
cheap, in common case) extra call of this macro.

Agreed, bypassing the last CHECK_FOR_INTERRUPTS() shouldn't save
anything noticeable. Could there be a correctness argument for it
though? Can't see what. We should assume that CFIs might happen
down inside LogicalDecodingProcessRecord.

I wondered why the code looks like this, and whether there used
to be more of a reason for it. "git blame" reveals the probable
answer: when this code was added, in 9c7d06d60, the loop
condition was different so the break was necessary.
38a957316 simplified the loop condition to what we see today,
but didn't notice that the break was thereby made pointless.

While we're here ... the comment above the loop seems wrong
already, and this makes it more so. I suggest something like

-		/* Decode at least one record, until we run out of records */
+		/* Decode records until we reach the requested target */
		while (ctx->reader->EndRecPtr < moveto)

regards, tom lane

#4Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Tom Lane (#3)
1 attachment(s)
Re: Remove extraneous break condition in logical slot advance function

On Sat, Oct 21, 2023 at 11:40 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Gurjeet Singh <gurjeet@singh.im> writes:

On Fri, Oct 20, 2023 at 7:30 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

There exists an extraneous break condition in
pg_logical_replication_slot_advance(). When the end of WAL or moveto
LSN is reached, the main while condition helps to exit the loop, so no
separate break condition is needed. Attached patch removes it.

The only advantage I see of the code as it stands right now is that it
avoids one last call to CHECK_FOR_INTERRUPTS() by break'ing early. I
don't think we'd lose much in terms of performance by making one (very
cheap, in common case) extra call of this macro.

Agreed, bypassing the last CHECK_FOR_INTERRUPTS() shouldn't save
anything noticeable. Could there be a correctness argument for it
though? Can't see what. We should assume that CFIs might happen
down inside LogicalDecodingProcessRecord.

AFAICS, there's no correctness argument for breaking before CFI. As
rightly said, CFIs can happen before the break condition either down
inside LogicalDecodingProcessRecord or XLogReadRecord (page_read
callbacks for instance).

Having said that, what may happen if CFI happens and interrupts are
processed before the break condition is that the decoding occurs again
which IMV is not a big problem.

An idea to keep all of XLogReadRecord() -
LogicalDecodingProcessRecord() loops consistent is by having CFI at
the start of the loops before the XLogReadRecord().

I wondered why the code looks like this, and whether there used
to be more of a reason for it. "git blame" reveals the probable
answer: when this code was added, in 9c7d06d60, the loop
condition was different so the break was necessary.
38a957316 simplified the loop condition to what we see today,
but didn't notice that the break was thereby made pointless.

Right. Thanks for these references.

While we're here ... the comment above the loop seems wrong
already, and this makes it more so. I suggest something like

-               /* Decode at least one record, until we run out of records */
+               /* Decode records until we reach the requested target */
while (ctx->reader->EndRecPtr < moveto)

+1 and done so in the attached v2 patch.

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

Attachments:

v2-0001-Remove-extraneous-break-condition-in-logical-slot.patchapplication/octet-stream; name=v2-0001-Remove-extraneous-break-condition-in-logical-slot.patchDownload
From 3f86c6138f45f49f09380ec17fc25901f3f6784f Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Sun, 22 Oct 2023 06:59:05 +0000
Subject: [PATCH v2] Remove extraneous break condition in logical slot advance
 function

There exists an extraneous break condition in
pg_logical_replication_slot_advance(). When end of WAL or moveto
LSN is reached, the main while condition helps to exit the loop,
so no separate break condition is needed.

In passing, modify the comment atop the while loop by specifying
that the loop runs until the requested target LSN has been
reached.
---
 src/backend/replication/slotfuncs.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 6035cf4816..4b694a03d0 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -500,7 +500,7 @@ pg_logical_replication_slot_advance(XLogRecPtr moveto)
 		/* invalidate non-timetravel entries */
 		InvalidateSystemCaches();
 
-		/* Decode at least one record, until we run out of records */
+		/* Decode records until we reach the requested target */
 		while (ctx->reader->EndRecPtr < moveto)
 		{
 			char	   *errm = NULL;
@@ -523,10 +523,6 @@ pg_logical_replication_slot_advance(XLogRecPtr moveto)
 			if (record)
 				LogicalDecodingProcessRecord(ctx, ctx->reader);
 
-			/* Stop once the requested target has been reached */
-			if (moveto <= ctx->reader->EndRecPtr)
-				break;
-
 			CHECK_FOR_INTERRUPTS();
 		}
 
-- 
2.34.1

#5Michael Paquier
michael@paquier.xyz
In reply to: Bharath Rupireddy (#4)
Re: Remove extraneous break condition in logical slot advance function

On Sun, Oct 22, 2023 at 11:59:00PM +0530, Bharath Rupireddy wrote:

AFAICS, there's no correctness argument for breaking before CFI. As
rightly said, CFIs can happen before the break condition either down
inside LogicalDecodingProcessRecord or XLogReadRecord (page_read
callbacks for instance).

Having said that, what may happen if CFI happens and interrupts are
processed before the break condition is that the decoding occurs again
which IMV is not a big problem.

An idea to keep all of XLogReadRecord() -
LogicalDecodingProcessRecord() loops consistent is by having CFI at
the start of the loops before the XLogReadRecord().

Passing by.. All that just looks like an oversight of 38a957316d7e
that simplified the main while loop, so I've just applied your v2.
--
Michael