Commit bb5ae8f6 authored by Tom Lane's avatar Tom Lane

Use a hash table to de-duplicate NOTIFY events faster.

Previously, async.c got rid of duplicate notifications by scanning
the list of pending events to compare each one to the proposed new
event.  This works okay for very small numbers of distinct events,
but degrades as O(N^2) for many events.  We can improve matters by
using a hash table to probe for duplicates.  So as not to add a
lot of overhead for the simple cases that the code did handle well
before, create the hash table only once a (sub)transaction has
queued more than 16 distinct notify events.

A downside is that we now have to do per-event work to propagate
a successful subtransaction's notify events up to its parent.
(But this isn't significant unless the subtransaction had many
events, in which case the O(N^2) behavior would have been in
play already, so we still come out ahead.)

We can make some lemonade out of this lemon, though: since we must
examine each event anyway, it's now possible to de-duplicate events
fully, rather than skipping that for events merged up from
subtransactions.  Hence, remove the old weasel wording in notify.sgml
about whether de-duplication happens or not, and adjust the test
case in async-notify.spec that exhibited the old behavior.

While at it, rearrange the definition of struct Notification to make
it more compact and require just one palloc per event, rather than
two or three.  This saves space when there are a lot of events,
in fact more than enough to buy back the space needed for the hash
table.

Patch by me, based on discussions around a different patch
submitted by Filip Rembiałkowski.

Discussion: https://postgr.es/m/17822.1564186806@sss.pgh.pa.us
parent 45aaaa42
...@@ -94,9 +94,9 @@ NOTIFY <replaceable class="parameter">channel</replaceable> [ , <replaceable cla ...@@ -94,9 +94,9 @@ NOTIFY <replaceable class="parameter">channel</replaceable> [ , <replaceable cla
</para> </para>
<para> <para>
If the same channel name is signaled multiple times from the same If the same channel name is signaled multiple times with identical
transaction with identical payload strings, the payload strings within the same transaction, only one instance of the
database server can decide to deliver a single notification only. notification event is delivered to listeners.
On the other hand, notifications with distinct payload strings will On the other hand, notifications with distinct payload strings will
always be delivered as distinct notifications. Similarly, notifications from always be delivered as distinct notifications. Similarly, notifications from
different transactions will never get folded into one notification. different transactions will never get folded into one notification.
......
This diff is collapsed.
...@@ -40,8 +40,6 @@ step notifys1: ...@@ -40,8 +40,6 @@ step notifys1:
ROLLBACK TO SAVEPOINT s2; ROLLBACK TO SAVEPOINT s2;
COMMIT; COMMIT;
notifier: NOTIFY "c1" with payload "payload" from notifier
notifier: NOTIFY "c2" with payload "payload" from notifier
notifier: NOTIFY "c1" with payload "payload" from notifier notifier: NOTIFY "c1" with payload "payload" from notifier
notifier: NOTIFY "c2" with payload "payload" from notifier notifier: NOTIFY "c2" with payload "payload" from notifier
notifier: NOTIFY "c1" with payload "payloads" from notifier notifier: NOTIFY "c1" with payload "payloads" from notifier
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment