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


Reply via email to