public inbox for [email protected]  
help / color / mirror / Atom feed
From: Yushi Ogiwara <[email protected]>
To: Masahiko Sawada <[email protected]>
Cc: Pgsql Hackers <[email protected]>
Subject: Re: Fix for consume_xids advancing XIDs incorrectly
Date: Wed, 16 Oct 2024 14:06:14 +0900
Message-ID: <[email protected]> (raw)
In-Reply-To: <CAD21AoATuDuqSr=V3vCSbHbOg6g9zKL61EEbe4ZPG3xOUa0Pcw@mail.gmail.com>
References: <[email protected]>
	<CAD21AoATuDuqSr=V3vCSbHbOg6g9zKL61EEbe4ZPG3xOUa0Pcw@mail.gmail.com>

Hi,

Thank you for your comment.

Regarding the first patch, I believe it works correctly when 
consume_xids(1) is called.  This is because the lastxid variable in the 
consume_xids_common function is initialized as lastxid = 
ReadNextFullTransactionId(), where the ReadNextFullTransactionId 
function returns the (current XID) + 1.

Separately, I found that consume_xids(0) does not behave as expected. 
Below is an example:

postgres=# select txid_current();
  txid_current
--------------
         45496
(1 row)

postgres=# select consume_xids(0);
  consume_xids
--------------
         45497
(1 row)

postgres=# select consume_xids(0);
  consume_xids
--------------
         45497
(1 row)

In the example, the argument to consume_xids is 0, meaning it should not 
consume any XIDs. However, the first invocation of consume_xids(0) looks 
like unexpectedly consuming 1 XID though it's not consuming actually. 
This happens because consume_xids(0) returns the value from 
ReadNextFullTransactionId.

I have updated the patch (skip.diff, attached to this e-mail) to address 
this issue. Now, when consume_xids(0) is called, it returns 
ReadNextFullTransactionId().value - 1, ensuring no XID is consumed as 
shown below:

postgres=# select txid_current();
  txid_current
--------------
         45498
(1 row)

postgres=# select consume_xids(0);
  consume_xids
--------------
         45498
(1 row)


Regards,
Yushi

On 2024-10-16 07:26, Masahiko Sawada wrote:
> Hi,
> 
> Thank you for the report.
> 
> On Mon, Oct 14, 2024 at 6:51 PM Yushi Ogiwara
> <[email protected]> wrote:
>> 
>> Hi,
>> 
>> I found that the consume_xids function incorrectly advances XIDs as
>> shown:
>> 
>> postgres=# select txid_current();
>>   txid_current
>> --------------
>>          746
>> (1 row)
>> 
>> postgres=# select consume_xids('100');
>>   consume_xids
>> --------------
>>          847
>> (1 row)
>> 
>> In the example, the consume_xids function consumes 100 XIDs when XID =
>> 746, so the desired outcome from consume_xids should be 746 + 100 = 
>> 846,
>> which differs from the actual outcome, 847.
>> 
>> Behavior inside a transaction block:
>> 
>> postgres=# select txid_current();
>>   txid_current
>> --------------
>>           1410
>> (1 row)
>> 
>> postgres=# begin;
>> BEGIN
>> postgres=*# select consume_xids('100');
>>   consume_xids
>> --------------
>>           1511
>> (1 row)
>> postgres=*# select consume_xids('100');
>>   consume_xids
>> --------------
>>           1521
>> (1 row)
>> 
>> Here, the first call inside the transaction block consumes 100+1 XIDs
>> (incorrect), while the second call consumes exactly 100 XIDs (as
>> expected)
>> 
>> Summary:
>> 
>> The function performs incorrectly when:
>> - Outside of a transaction block
>> - The first call inside a transaction block
>> But works correctly when:
>> - After the second call inside a transaction block
>> 
>> The issue arises because consume_xids does not correctly count the
>> consumed XIDs when it calls the GetTopTransactionId function, which
>> allocates a new XID when none has been assigned.
> 
> I agree with your analysis.
> 
> I have one comment on the patch:
> 
> -       (void) GetTopTransactionId();
> +       if(!FullTransactionIdIsValid(GetTopFullTransactionIdIfAny()))
> +       {
> +               (void) GetTopTransactionId();
> +               consumed++;
> +       }
> 
> If we count this case as consumed too, I think we need to set the
> returned value of GetTopTranasctionId() to lastxid. Because otherwise,
> the return value when passing 1 to the function would be the latest
> XID at the time but not the last XID consumed by the function. Passing
> 1 to this function is very unrealistic case, though.
> 
> Regards,


Attachments:

  [text/x-diff] skip.diff (946B, ../[email protected]/2-skip.diff)
  download | inline diff:
diff --git a/src/test/modules/xid_wraparound/xid_wraparound.c b/src/test/modules/xid_wraparound/xid_wraparound.c
index dce81c0c6d..4b9788d2d9 100644
--- a/src/test/modules/xid_wraparound/xid_wraparound.c
+++ b/src/test/modules/xid_wraparound/xid_wraparound.c
@@ -38,7 +38,7 @@ consume_xids(PG_FUNCTION_ARGS)
 		elog(ERROR, "invalid nxids argument: %lld", (long long) nxids);
 
 	if (nxids == 0)
-		lastxid = ReadNextFullTransactionId();
+		lastxid = FullTransactionIdFromU64(ReadNextFullTransactionId().value - 1);
 	else
 		lastxid = consume_xids_common(InvalidFullTransactionId, (uint64) nxids);
 
@@ -89,7 +89,11 @@ consume_xids_common(FullTransactionId untilxid, uint64 nxids)
 	 * the cache overflows, but beyond that, we don't keep track of the
 	 * consumed XIDs.
 	 */
-	(void) GetTopTransactionId();
+	if(!FullTransactionIdIsValid(GetTopFullTransactionIdIfAny()))
+	{
+		(void) GetTopTransactionId();
+		consumed++;
+	}
 
 	for (;;)
 	{


view thread (4+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected]
  Subject: Re: Fix for consume_xids advancing XIDs incorrectly
  In-Reply-To: <[email protected]>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox