Re: Support to define custom wait events for extensions

Поиск
Список
Период
Сортировка
От Masahiro Ikeda
Тема Re: Support to define custom wait events for extensions
Дата
Msg-id 71381f06e7429e9d432530f8437bd3a7@oss.nttdata.com
обсуждение исходный текст
Ответ на Re: Support to define custom wait events for extensions  (Andres Freund <andres@anarazel.de>)
Список pgsql-hackers
On 2023-07-12 09:36, Andres Freund wrote:
> Hi,
> 
> On 2023-07-11 16:45:26 +0900, Michael Paquier wrote:
>> +/* ----------
>> + * Wait Events - Extension
>> + *
>> + * Use this category when the server process is waiting for some 
>> condition
>> + * defined by an extension module.
>> + *
>> + * Extensions can define custom wait events.  First, call
>> + * WaitEventExtensionNewTranche() just once to obtain a new wait 
>> event
>> + * tranche.  The ID is allocated from a shared counter.  Next, each
>> + * individual process using the tranche should call
>> + * WaitEventExtensionRegisterTranche() to associate that wait event 
>> with
>> + * a name.
> 
> What does "tranche" mean here? For LWLocks it makes some sense, it's 
> used for
> a set of lwlocks, not an individual one. But here that doesn't really 
> seem to
> apply?

Thanks for useful comments.
OK, I will change to WaitEventExtensionNewId() and 
WaitEventExtensionRegisterName().

>> + * It may seem strange that each process using the tranche must 
>> register it
>> + * separately, but dynamic shared memory segments aren't guaranteed 
>> to be
>> + * mapped at the same address in all coordinating backends, so 
>> storing the
>> + * registration in the main shared memory segment wouldn't work for 
>> that case.
>> + */
> I don't really see how this applies to wait events? There's no pointers
> here...

Yes, I'll fix the comments.

> 
>> +typedef enum
>> +{
>> +    WAIT_EVENT_EXTENSION = PG_WAIT_EXTENSION,
>> +    WAIT_EVENT_EXTENSION_FIRST_USER_DEFINED
>> +} WaitEventExtension;
>> +
>> +extern void WaitEventExtensionShmemInit(void);
>> +extern Size WaitEventExtensionShmemSize(void);
>> +
>> +extern uint32 WaitEventExtensionNewTranche(void);
>> +extern void WaitEventExtensionRegisterTranche(uint32 wait_event_info,
> 
>> -slock_t    *ShmemLock;            /* spinlock for shared memory and LWLock
>> +slock_t    *ShmemLock;            /* spinlock for shared memory, LWLock
>> +                                 * allocation, and named extension wait event
>>                                   * allocation */
> 
> I'm doubtful that it's a good idea to reuse the spinlock further. Given 
> that
> the patch adds WaitEventExtensionShmemInit(), why not just have a lock 
> in
> there?

OK, I'll create a new spinlock for the purpose.


>> +/*
>> + * Allocate a new event ID and return the wait event info.
>> + */
>> +uint32
>> +WaitEventExtensionNewTranche(void)
>> +{
>> +    uint16        eventId;
>> +
>> +    SpinLockAcquire(ShmemLock);
>> +    eventId = (*WaitEventExtensionCounter)++;
>> +    SpinLockRelease(ShmemLock);
>> +
>> +    return PG_WAIT_EXTENSION | eventId;
>> +}
> 
> It seems quite possible to run out space in WaitEventExtensionCounter, 
> so this
> should error out in that case.

OK, I'll do so.


>> +/*
>> + * Register a dynamic tranche name in the lookup table of the current 
>> process.
>> + *
>> + * This routine will save a pointer to the wait event tranche name 
>> passed
>> + * as an argument, so the name should be allocated in a 
>> backend-lifetime context
>> + * (shared memory, TopMemoryContext, static constant, or similar).
>> + *
>> + * The "wait_event_name" will be user-visible as a wait event name, 
>> so try to
>> + * use a name that fits the style for those.
>> + */
>> +void
>> +WaitEventExtensionRegisterTranche(uint32 wait_event_info,
>> +                                  const char *wait_event_name)
>> +{
>> +    uint16        eventId;
>> +
>> +    /* Check wait event class. */
>> +    Assert((wait_event_info & 0xFF000000) == PG_WAIT_EXTENSION);
>> +
>> +    eventId = wait_event_info & 0x0000FFFF;
>> +
>> +    /* This should only be called for user-defined tranches. */
>> +    if (eventId < NUM_BUILTIN_WAIT_EVENT_EXTENSION)
>> +        return;
> 
> Why not assert out in that case then?

OK, I'll add the assertion for eventID.


>> +/*
>> + * Return the name of an Extension wait event ID.
>> + */
>> +static const char *
>> +GetWaitEventExtensionIdentifier(uint16 eventId)
>> +{
>> +    /* Build-in tranche? */
> 
> *built

I will fix it.


>> +    if (eventId < NUM_BUILTIN_WAIT_EVENT_EXTENSION)
>> +        return "Extension";
>> +
>> +    /*
>> +     * It's an extension tranche, so look in 
>> WaitEventExtensionTrancheNames[].
>> +     * However, it's possible that the tranche has never been registered 
>> by
>> +     * calling WaitEventExtensionRegisterTranche() in the current 
>> process, in
>> +     * which case give up and return "Extension".
>> +     */
>> +    eventId -= NUM_BUILTIN_WAIT_EVENT_EXTENSION;
>> +
>> +    if (eventId >= WaitEventExtensionTrancheNamesAllocated ||
>> +        WaitEventExtensionTrancheNames[eventId] == NULL)
>> +        return "Extension";
> 
> I'd return something different here, otherwise something that's 
> effectively a
> bug is not distinguishable from the built

It is a good idea. It would be good to name it "unknown wait event", the 
same as
pgstat_get_wait_activity(), etc.


>> +++ b/src/test/modules/test_custom_wait_events/t/001_basic.pl
>> @@ -0,0 +1,34 @@
>> +# Copyright (c) 2023, PostgreSQL Global Development Group
>> +
>> +use strict;
>> +use warnings;
>> +
>> +use PostgreSQL::Test::Cluster;
>> +use PostgreSQL::Test::Utils;
>> +use Test::More;
>> +
>> +my $node = PostgreSQL::Test::Cluster->new('main');
>> +
>> +$node->init;
>> +$node->append_conf(
>> +    'postgresql.conf',
>> +    "shared_preload_libraries = 'test_custom_wait_events'"
>> +);
>> +$node->start;
> 
> I think this should also test registering a wait event later.

I see. I wasn't expecting that.


>> @@ -0,0 +1,188 @@
>> +/*--------------------------------------------------------------------------
>> + *
>> + * test_custom_wait_events.c
>> + *        Code for testing custom wait events
>> + *
>> + * This code initializes a custom wait event in shmem_request_hook() 
>> and
>> + * provide a function to launch a background worker waiting forever
>> + * with the custom wait event.
> 
> Isn't this vast overkill?  Why not just have a simple C function that 
> waits
> with a custom wait event, until cancelled? That'd maybe 1/10th of the 
> LOC.

Are you saying that processing in the background worker is overkill?

If my understanding is correct, it is difficult to implement the test
without a background worker for this purpose. This is because the test
will execute commands serially, while a function waiting is executed in
a backend process, it is not possible to connect to another backend and
check the wait events on pg_stat_activity view.

Please let me know if my understanding is wrong.


Regards,
-- 
Masahiro Ikeda
NTT DATA CORPORATION



В списке pgsql-hackers по дате отправления:

Предыдущее
От: Michael Paquier
Дата:
Сообщение: Re: 'ERROR: attempted to update invisible tuple' from 'ALTER INDEX ... ATTACH PARTITION' on parent index
Следующее
От: Masahiko Sawada
Дата:
Сообщение: Re: Performance degradation on concurrent COPY into a single relation in PG16.