Re: Optimize LISTEN/NOTIFY - Mailing list pgsql-hackers

From Joel Jacobson
Subject Re: Optimize LISTEN/NOTIFY
Date
Msg-id b4795171-da6f-43bd-a85a-a4e1c7b1b0b5@app.fastmail.com
Whole thread Raw
In response to Re: Optimize LISTEN/NOTIFY  ("Joel Jacobson" <joel@compiler.org>)
List pgsql-hackers
On Tue, Jan 13, 2026, at 13:10, Joel Jacobson wrote:
> On Tue, Jan 13, 2026, at 06:46, Joel Jacobson wrote:
>> On Wed, Jan 7, 2026, at 21:29, Tom Lane wrote:
>>> That seems a little weird: surely such usage is not something we need
>>> to optimize.  Maybe it can be justified because it makes the code
>>> simpler, but that's not immediately obvious to me.
>>
>> The reason for not sticking to the two-boolean approach (staged/current)
>> like in v32 was to minimize shared dshash operations in favor of local
>> hash table operations.

I made a closer comparison between v32 and v34, adopting the same naming
in v32 to allow for easier comparison. This exercise paid off; I now
remember another important reason why I looked for alternatives to the
two-boolean approach.  There is a significant difference for UNLISTEN *.

In v32, we need to scan the *entire* global hash table while holding an
exclusive lock.

In v34, we only need to scan our own local hash tables.

v32 (naming adopted to match v34):
```
static void
PrepareTableEntriesForUnlistenAll(void)
{
    dshash_seq_status status;
    GlobalChannelEntry *entry;

    dshash_seq_init(&status, globalChannelTable, true);
    while ((entry = dshash_seq_next(&status)) != NULL)
    {
        if (entry->key.dboid == MyDatabaseId)
        {
            ListenerEntry *listeners = (ListenerEntry *) dsa_get_address(globalChannelDSA,
                                                                         entry->listenersArray);

            for (int i = 0; i < entry->numListeners; i++)
            {
                if (listeners[i].procNo == MyProcNumber && listeners[i].staged)
                {
                    listeners[i].staged = false;
                    pendingListenChannels = lappend(pendingListenChannels,
                                                    pstrdup(entry->key.channel));
                }
            }
        }
    }
    dshash_seq_term(&status);
}
```

v34:
```
static void
PrepareTableEntriesForUnlistenAll(void)
{
    HASH_SEQ_STATUS seq;
    struct ChannelName *channelEntry;
    struct PendingListenEntry *pending;

    hash_seq_init(&seq, pendingListenActions);
    while ((pending = (struct PendingListenEntry *) hash_seq_search(&seq)) != NULL)
        pending->action = PENDING_UNLISTEN;

    if (localChannelTable != NULL)
    {
        hash_seq_init(&seq, localChannelTable);
        while ((channelEntry = (struct ChannelName *) hash_seq_search(&seq)) != NULL)
        {
            bool        found;

            pending = (struct PendingListenEntry *)
                hash_search(pendingListenActions, channelEntry->channel, HASH_ENTER, &found);
            pending->action = PENDING_UNLISTEN;
        }
    }
}
```

/Joel



pgsql-hackers by date:

Previous
From: Robert Haas
Date:
Subject: Re: CREATE TABLE LIKE INCLUDING TRIGGERS
Next
From: Joe Conway
Date:
Subject: Re: how to gate experimental features (SQL/PGQ)