doc: document LISTEN/NOTIFY commit-time serialization#83
Draft
NikolayS wants to merge 1 commit into
Draft
Conversation
A transaction that has executed NOTIFY takes a cluster-wide heavyweight lock during commit (PreCommit_Notify, async.c), held until after the commit completes. The serialized region therefore includes the WAL flush and, where configured, the synchronous replication wait, so notifying transactions cannot group-commit with one another and their aggregate rate is bounded by roughly one commit round trip at a time regardless of client concurrency. None of this was documented, and users have had to read async.c to discover it. Add a Performance Considerations section to the NOTIFY reference page covering the serialization and its scope, that the cost is per notifying transaction rather than per notification (so batching helps and NOTIFY in a row-level trigger is an anti-pattern), how to diagnose the contention, and when to prefer a queue table or logical decoding instead. Note that log_lock_waits only reports waits exceeding deadlock_timeout, whose one-second default is far longer than a typical wait for this lock, so the diagnosis guidance leads with pg_stat_activity. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01M3RLizCyeXBBFJdBHGDvKW
NikolayS
force-pushed
the
claude/notify-global-lock-bottleneck-29bpn5
branch
from
July 25, 2026 06:42
57ef5a6 to
24e8480
Compare
This was referenced Jul 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Single documentation commit, intended for upstream submission. Context and analysis: #82. The measurement harness that produced the supporting numbers is deliberately kept out of this PR — see #84.
What it adds
A
Performance Considerationssection on theNOTIFYreference page, covering:NOTIFYtransaction takes a heavyweight lock that serializes it against every other committingNOTIFYtransaction. The lock is cluster-wide, not per-database — notifiers in different databases of the same cluster contend. Transactions that did not executeNOTIFY, andLISTEN/UNLISTEN, do not take it.synchronous_commit=on, withsynchronous_standby_namesset, or on high-latency storage.NOTIFYfrom a row-level trigger.SKIP LOCKEDor logical decoding is the better tool.Revisions vs. the July 2025 proposal
This is a corrected version of CAM527d8…, which was never committed. Two claims in it do not survive checking against the tree:
The blanket O(N²) duplicate-checking claim is dropped. Duplicate elimination has not been quadratic since PG13:
AsyncExistsPendingNotify()probes a hash table once a list reachesMIN_HASHABLE_NOTIFIES(16), built byAddEventToPendingNotifies()— present in v18 and master. The subtransaction merge probes the parent list, which is hashed too, so it is effectively linear as well. This was the easiest part of the original patch to reject on accuracy.The diagnosis guidance now leads with
pg_stat_activity.proc.c:1631gateslog_lock_waitsbehinddeadlock_state != DS_NOT_YET_CHECKED, set only oncedeadlock_timeoutfires. At its 1 s default, waits for this lock — measured here at 1–70 ms — are never logged. The original advice did not work at default settings. The section now says so and tells the reader to reducedeadlock_timeoutif they want server-log reporting.Backpatchability
Restricted to behaviour true on all supported branches (14–18) and master. It deliberately says nothing about the v19 shared channel map or direct advancement (
282b1cde), which are listener-side and version-specific. Note v13 reached EOL in Nov 2025.It also deliberately avoids restating or sharpening the existing ordering guarantee at
notify.sgml:104-107, so that it does not constrain any future change to the locking.Validation
xmllint --nooutwell-formed with the file's entities declared; no tabs, no non-breaking spaces; all sevenlinkendtargets resolve (guc-synchronous-commit,guc-synchronous-standby-names,guc-log-lock-waits,guc-deadlock-timeout,sql-select,logicaldecoding,monitoring-pg-stat-activity-view).Full DTD validation has not been run — the DocBook 4.5 DTD is not installed in this environment and network fetch is blocked, so
make -C doc/src/sgml checkfails on the DTD rather than on this patch. It should be run before submission to -hackers.🤖 Generated with Claude Code
https://claude.ai/code/session_01M3RLizCyeXBBFJdBHGDvKW