public inbox for [email protected]  
help / color / mirror / Atom feed
From: Chao Li <[email protected]>
To: Amit Langote <[email protected]>
Cc: Junwang Zhao <[email protected]>
Cc: Haibo Yan <[email protected]>
Cc: Pavel Stehule <[email protected]>
Cc: PostgreSQL-development <[email protected]>
Cc: Tomas Vondra <[email protected]>
Subject: Re: Eliminating SPI / SQL from some RI triggers - take 3
Date: Thu, 2 Apr 2026 15:59:37 +0800
Message-ID: <[email protected]> (raw)
In-Reply-To: <CA+HiwqF2Ma6R_QyjfPBvFreYbezFpGcwASJE0a2bM+Y0jvof+g@mail.gmail.com>
References: <CA+HiwqF4C0ws3cO+z5cLkPuvwnAwkSp7sfvgGj3yQ=Li6KNMqA@mail.gmail.com>
	<CA+HiwqGM6nvAV5O+=Nr+BXMPWOma0oeCRVzVP0XiLE8zX5TVAg@mail.gmail.com>
	<CA+HiwqGMaovCUgDbGxVGnK0Mrivr+ph3YE2Ws+47-ugyPb4f7g@mail.gmail.com>
	<CAFj8pRDaiBe_GOLk_yyYHTtPiDAAaLOM8u1-=Q3ZgXBTH+1igg@mail.gmail.com>
	<CA+HiwqGA5Ay_MR0eJEEbt4j6WrVh4F+AasTp8yCbs5aJLOJn6Q@mail.gmail.com>
	<CAEG8a3JM=NoqiTK0V6S9FNxZPvy1+C5F7rfafTtPKBVWnunL-g@mail.gmail.com>
	<CA+HiwqEyiLCY6MTLbOJXDdLNNQLaURYHvdW797MQgbjEK9od4Q@mail.gmail.com>
	<CAEG8a3+VBpwPf1Rm-ECD90whM9b3YnGhux5CVXdsL6khiBfzRQ@mail.gmail.com>
	<CA+HiwqF2UHzF0sKCp-F2a-U29rqh_9ZPy=f1h+Fh_=M8efj3pg@mail.gmail.com>
	<CAEG8a3L9Ew-WL8sxLROVOcypeaENPmd8qCmMvz4geoGL1TDGCA@mail.gmail.com>
	<CAEG8a3+nUFQo4sdPQF9xy0J73J8RFJ5U9A5+_kMosGDaZ+1sXA@mail.gmail.com>
	<[email protected]>
	<CAEG8a3JyKdizWvYsF+z_mA1BKy=dpW11iKVMOG=bk6Tbz6M1Bw@mail.gmail.com>
	<CAEG8a3+Hf4tvvbts29_k_AFhWQmRYfEo_SW4C5FY_140iKghBw@mail.gmail.com>
	<CA+HiwqFV-PY-3BxM6j5TaAiC3AwedDxo-6vwRSbvygg3zF+xAQ@mail.gmail.com>
	<CA+HiwqHpaisS-e+0gAgzh92qZAFxncAJMmmTRZZN=efoeTPgOg@mail.gmail.com>
	<CA+HiwqFwZ6WLRbY8R7VC7JVp5Jot6ktZOkr9wDxTjoK=W1SgdQ@mail.gmail.com>
	<CA+HiwqF_Kz=R8juHJBiOATvabWSOugK4VaGOxoJ_n=E2c7UM9w@mail.gmail.com>
	<CA+HiwqHCB7kcbspkhaLN9enoj5x=ehzhFM4PXDgWUUP8Px41GA@mail.gmail.com>
	<[email protected]>
	<CA+HiwqHpVtP485wEKuXdOkdoZWhvVvfFH40-og07Jp3MPx21eg@mail.gmail.com>
	<CAEG8a3JWHkJSXe9nNcVK7wnYKUEqWuMGFDhy5BynB_9tEjmEUg@mail.gmail.com>
	<CA+HiwqFjfumKrWy03q5M309xJJVYt0WgGfH6AZ8BjFhSwppwsQ@mail.gmail.com>
	<CAEG8a3JjP1LaKSv-r3AMJLRyLMzENJrKshWsDvDouMPM_sizmA@mail.gmail.com>
	<CA+HiwqFQ+ZA7hSOygv4uv_t75B3r0_gosjadetCsAEoaZwTu6g@mail.gmail.com>
	<CA+HiwqHdB0r8z6Mut13BxpYNq2W-os+Arju4mcZbCyU9PeaVog@mail.gmail.com>
	<CAEG8a3K5ayVNkCDnK9OtNb+4OY0chJtW6ObgEOSFjqyymQda8Q@mail.gmail.com>
	<CA+HiwqGJYCgEs_F-LBtrRdx-Y969LMr-OVogjFXU6U-0q5bOwQ@mail.gmail.com>
	<CA+HiwqF2Ma6R_QyjfPBvFreYbezFpGcwASJE0a2bM+Y0jvof+g@mail.gmail.com>



> On Apr 2, 2026, at 15:41, Amit Langote <[email protected]> wrote:
> 
> On Wed, Apr 1, 2026 at 9:18 PM Amit Langote <[email protected]> wrote:
>> On Wed, Apr 1, 2026 at 8:56 PM Junwang Zhao <[email protected]> wrote:
>>> On Wed, Apr 1, 2026 at 5:51 PM Amit Langote <[email protected]> wrote:
>>>> 
>>>> On Wed, Apr 1, 2026 at 5:51 PM Amit Langote <[email protected]> wrote:
>>>>> On Wed, Apr 1, 2026 at 12:54 AM Junwang Zhao <[email protected]> wrote:
>>>>>> +       if (riinfo->fpmeta == NULL)
>>>>>> +       {
>>>>>> +               /* Reload to ensure it's valid. */
>>>>>> +               riinfo = ri_LoadConstraintInfo(riinfo->constraint_id);
>>>>>> 
>>>>>> I was thinking of wrapping the reload in a conditional check like
>>>>>> `!riinfo->valid`, since `riinfo` can be valid even when `fpmeta == NULL`.
>>>>>> However,  `if (riinfo->fpmeta == NULL)` should rarely be true, so the
>>>>>> unconditional reload is harmless, and the code is cleaner.
>>>>>> 
>>>>>> +1 to the fix.
>>>>> 
>>>>> Thanks for checking.
>>>>> 
>>>>> I have just pushed a slightly modified version of that.
>>>>> 
>>>>>>> 0002 is the rebased batching patch.
>>>>>> 
>>>>>> The change of RI_FastPathEntry from storing riinfo to fk_relid
>>>>>> makes sense to me. I'll do another review on 0002 tomorrow.
>>>>> 
>>>>> Here's another version.
>>>>> 
>>>>> This time, I have another fixup patch (0001) to make FastPathMeta
>>>>> self-contained by copying the FmgrInfo structs it needs out of
>>>>> RI_CompareHashEntry rather than storing pointers into it.  This avoids
>>>>> any dependency on those cache entries remaining stable.  I'll push
>>>>> that once the just committed patch has seen enough BF animals.
>>>> 
>>>> Pushed.
>>>> 
>>>>> 0002 is rebased over that.
>>>> 
>>>> Rebased again.
>>> 
>>> +static void
>>> +ri_FastPathBatchFlush(RI_FastPathEntry *fpentry, Relation fk_rel)
>>> +{
>>> + /* Reload; may have been invalidated since last batch accumulation. */
>>> + const RI_ConstraintInfo *riinfo = ri_LoadConstraintInfo(fpentry->conoid);
>>> 
>>> ...
>>> + if (riinfo->fpmeta == NULL)
>>> + {
>>> + /* Reload to ensure it's valid. */
>>> + riinfo = ri_LoadConstraintInfo(riinfo->constraint_id);
>>> + ri_populate_fastpath_metadata((RI_ConstraintInfo *) riinfo,
>>> +   fk_rel, idx_rel);
>>> + }
>>> 
>>> ri_LoadConstraintInfo is currently invoked twice within
>>> ri_FastPathBatchFlush. Should we eliminate the second call?
>> 
>> I think we can't because the entry may be stale by the time we get to
>> the ri_populate_fastpath_metadata() call due to intervening steps;
>> even something as benign-looking index_beginscan() may call code paths
>> that can trigger invalidation in rare cases. Maybe predictably in
>> CLOBBER_CACHE_ALWAYS builds.
>> 
>>> Alternatively, we could refactor ri_FastPathBatchFlush to accept
>>> an additional parameter, `const RI_ConstraintInfo *riinfo`, so we
>>> can remove the need for the first call. In that case, we need to call
>>> ri_LoadConstraintInfo in ri_FastPathEndBatch.
>> 
>> Yeah, I think that's fine.  Done that way in the attached.
>> 
>> Also, I realized that we could do:
>> 
>> @@ -2937,7 +2937,7 @@ ri_FastPathBatchFlush(RI_FastPathEntry *fpentry,
>> Relation fk_rel)
>>                                       fk_rel, idx_rel);
>>     }
>>     Assert(riinfo->fpmeta);
>> -    if (riinfo->nkeys == 1)
>> +    if (riinfo->nkeys == 1 && fpentry->batch_count > 1)
>>         violation_index = ri_FastPathFlushArray(fpentry, fk_slot, riinfo,
>>                                                 fk_rel, snapshot, scandesc);
>> 
>> so that the fixed overhead of ri_FastPathFlushArray (allocating
>> matched[] array on stack and constructing ArrayType, etc.) is not paid
>> unnecessarily for single-row batches.
> 
> There's another case in which it is not ok to use FlushArray and that
> is if the index AM's amsearcharray is false (should be true in all
> cases because the unique index used for PK is always btree).  Added an
> Assert to that effect next to where SK_SEARCHARRAY is set in
> ri_FastPathFlushArray rather than a runtime check in the dispatch
> condition.
> 
> Patch updated.  Also added a comment about invalidation requirement or
> lack thereof for RI_FastPathEntry, rename AfterTriggerBatchIsActive()
> to simply AfterTriggerIsActive(), fixed the comments in trigger.h
> describing the callback mechanism.
> 
> Will push tomorrow morning (Friday) barring objections.
> 
> -- 
> Thanks, Amit Langote
> <v17-0001-Batch-FK-rows-and-use-SK_SEARCHARRAY-for-fast-pa.patch>

With a quick eyeball review, I found a typo:
```
+ * relcache invalidation.  The entry itself is torn down at batch at batch end
```

There are two “at batch”.

I plan to spend time testing and tracing this patch tomorrow. But I don’t want to block your progress, if I find anything, I will report to you.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/









view thread (63+ 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], [email protected], [email protected], [email protected], [email protected]
  Subject: Re: Eliminating SPI / SQL from some RI triggers - take 3
  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