Re: SV: Problem with pg_notify / listen
Tom Lane <tgl@sss.pgh.pa.us>
From: Tom Lane <tgl@sss.pgh.pa.us>
To: Noah Misch <noah@leadboat.com>
Cc: Gustavsson Mikael <mikael.gustavsson@smhi.se>,
pgsql-bugs@lists.postgresql.org,
Svensson Peter <peter.svensson@smhi.se>,
Almen Anders <anders.almen@smhi.se>
Date: 2020-11-27T22:13:28Z
Lists: pgsql-bugs
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Fix a recently-introduced race condition in LISTEN/NOTIFY handling.
- f6324bbbe63c 10.16 landed
- f5de090cc175 13.2 landed
- cbc7a7a10c2d 12.6 landed
- 9c83b54a9ccd 14.0 landed
- 8a4069766079 9.6.21 landed
- 60d6c71430f9 9.5.25 landed
- 40f2fbe71ad6 11.11 landed
-
Prevent concurrent SimpleLruTruncate() for any given SLRU.
- d4031d78460c 11.10 cited
Attachments
- fix-notify-race-conditions.patch (text/x-diff) patch
I wrote: > * Change the code back to being atomic, ie go ahead and update > QUEUE_TAIL immediately, and truncate the SLRU only afterward. > Why is it necessary, or even safe, to perform the SLRU truncation > before changing QUEUE_TAIL? (IOW, I wonder if there isn't a bug > there in HEAD too.) After thinking more about that, I'm pretty sure there is a bug there: a newly-arriving backend could attempt to scan the queue starting at QUEUE_TAIL, concurrently with SimpleLruTruncate removing the page(s) it wants to scan. In typical cases no failure will occur because Exec_ListenPreCommit could advance its queue pointer to a safe place by observing the pointers of other backends. However, if the new listener were the only one in its database, we'd have trouble. What seems like the most expedient way to fix this is to separate QUEUE_TAIL into two variables, one that is the "logical" tail position from which new backends may start to scan the queue, and one that is the "physical" tail position, ie, the oldest page we have not yet truncated. The physical tail need only be tracked to page accuracy, so it can be a plain int not a QUEUE_POS. asyncQueueAdvanceTail should update QUEUE_TAIL immediately, which restores correct behavior pre-v13 and also dodges the race condition described above. But we don't update the physical tail pointer until we've completed SimpleLruTruncate, keeping things honest with respect to asyncQueueIsFull. As a minor side benefit, asyncQueueAdvanceTail doesn't have to take the NotifyQueueLock twice unless it actually does an SLRU truncation. In short, I propose the attached patch (against HEAD, but the same logic changes should work in the back branches). regards, tom lane