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: