Re: Connections hang indefinitely while taking a gin index's LWLock buffer_content lock
Peter Geoghegan <pg@bowt.ie>
From: Peter Geoghegan <pg@bowt.ie>
To: chjischj@163.com
Cc: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Date: 2018-11-07T20:52:42Z
Lists: pgsql-hackers
On Tue, Nov 6, 2018 at 10:05 AM chenhj <chjischj@163.com> wrote: > I analyzed the btree block where lwlock deadlock occurred, as follows: Thank you for doing this important work. You're using Postgres 10.2. While that version isn't current with all GIN bug fixes, it does have this important one: "Ensure that vacuum will always clean up the pending-insertions list of a GIN index (Masahiko Sawada)" Later GIN fixes seem unlikely to be relevant to your issue. I think that this is probably a genuine, new bug. > The ginInsertValue() function above gets the lwlock in the order described in the README. > However, ginScanToDelete() depth-first scans the btree and gets the EXCLUSIVE lock, which creates a deadlock. > Is the above statement correct? If so, deadlocks should easily happen. I have been suspicious of deadlock hazards in the code for some time -- particularly around pending list cleanup. I go into a lot of detail on my suspicions here: https://www.postgresql.org/message-id/flat/CAH2-WzmfUpRjWcUq3%2B9ijyum4AJ%2Bk-meGT8_HnxBMpKz1aNS-g%40mail.gmail.com#ea5af1088adfacb3d0ba88313be1a5e3 I note that your first deadlock involve the following kinds of backends: * ginInsertCleanup() calls from a regular backend, which will have a backend do things that VACUUM generally only gets to do, like call RecordFreeIndexPage(). * (auto)VACUUM processes. Your second/recovery deadlock involves: * Regular read-only queries. * Recovery code. Quite a lot of stuff is involved here! The code in this area is way too complicated, and I haven't thought about it in about a year, so it's hard for me to be sure of anything at the moment. My guess is that there is confusion about the type of page expected within one or more blocks (e.g. entry tree vs. pending list), due to a race condition in block deletion and/or recycling -- again, I've suspected something like this could happen for some time. The fact that you get a distinct deadlock during recovery is consistent with that theory. It's safe to say that promoting the asserts on gin page type into "can't happen" elog errors in places like scanPendingInsert() and ginInsertCleanup() would be a good start. Note that we already did similar Assert-elog(ERROR) promotion this for posting tree code, when similar bugs appeared way back in 2013. -- Peter Geoghegan
Commits
-
Fix WAL format incompatibility introduced by backpatching of 52ac6cd2d0
- d1166af192ed 9.4.22 landed
- cda5f6575306 9.5.17 landed
- f8a69a68a087 9.6.13 landed
- e23d44016d51 10.8 landed
- 89f39736f484 11.3 landed
-
Fix wrong backpatching of ginRedoDeletePage() deadlock fix
- bf0e5a73be20 9.4.21 landed
-
Fix deadlock in GIN vacuum introduced by 218f51584d5
- fd83c83d0943 12.0 landed
- 2e3bd064e530 10.7 landed
- 9aa94d8536f8 11.2 landed
-
Prevent GIN deleted pages from being reclaimed too early
- 52ac6cd2d0cd 12.0 landed
- ad6ebcfcbb88 9.5.16 landed
- 1cf175c74f10 9.4.21 landed
- cd24b4eaece3 9.6.12 landed
- a0696d29551b 10.7 landed
- dd951dc34a2e 11.2 landed
-
Prevent deadlock in ginRedoDeletePage()
- c6ade7a8cd31 12.0 landed
- 19cf52e6cc33 9.4.21 landed
- f6c44e1b55c1 9.5.16 landed
- 865870374aff 10.7 landed
- 80d4d8d71d57 9.6.12 landed
- 225b5c9c480f 11.2 landed
-
Reduce page locking in GIN vacuum
- 218f51584d5a 10.0 cited
-
Fix race condition in GIN posting tree page deletion.
- ac4ab97ec05e 9.4.0 cited