Thread
Commits
-
Unpin buffer before inplace update waits for an XID to end.
- c2139db11b16 12.21 landed
- 2a912bc1abdb 13.17 landed
- 11e3f288f3db 14.14 landed
- 0fe002d0c9a5 15.9 landed
- 9aef6f19ac27 17.1 landed
- 370bc7740286 16.5 landed
- 30d47ec8c6c7 18.0 landed
-
For inplace update durability, make heap_update() callers wait.
- aac2c9b4fde8 18.0 cited
-
heap_inplace_lock vs. autovacuum w/ LOCKTAG_TUPLE
Noah Misch <noah@leadboat.com> — 2024-10-26T18:49:36Z
intra-grant-inplace-db.spec got a novel failure today: https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=sarus&dt=2024-10-26%2014%3A08%3A58 The isolationtester_waiting query is supposed to detect that step vac2 is blocked. vac2 didn't finish within the timeout, but isolationtester_waiting never considered it blocked. Most-relevant postmaster.log lines: === 2024-10-26 14:22:51.791 UTC [2444667:6] isolation/intra-grant-inplace-db/s1 LOG: statement: BEGIN; 2024-10-26 14:22:51.791 UTC [2444667:7] isolation/intra-grant-inplace-db/s1 LOG: statement: GRANT TEMP ON DATABASE isolation_regression TO regress_temp_grantee; 2024-10-26 14:22:51.791 UTC [2444668:6] isolation/intra-grant-inplace-db/s2 LOG: statement: VACUUM (FREEZE); 2024-10-26 14:22:51.813 UTC [2444663:1] LOG: skipping analyze of "pg_attribute" --- lock not available 2024-10-26 14:22:51.815 UTC [2444666:7] isolation/intra-grant-inplace-db/control connection LOG: execute isolationtester_waiting: SELECT pg_catalog.pg_isolation_test_session_is_blocked($1, '{2444667,2444668,2444669}') 2024-10-26 14:22:51.815 UTC [2444666:8] isolation/intra-grant-inplace-db/control connection DETAIL: Parameters: $1 = '2444668' [... omitting most other lines from PID 2444666: >37000 isolationtester_waiting calls ...] 2024-10-26 14:22:51.851 UTC [2444663:2] LOG: skipping analyze of "pg_class" --- lock not available 2024-10-26 14:22:51.892 UTC [2444663:3] LOG: skipping analyze of "pg_depend" --- lock not available 2024-10-26 14:23:52.833 UTC [2444663:4] ERROR: canceling autovacuum task 2024-10-26 14:23:52.833 UTC [2444663:5] CONTEXT: while updating tuple (0,20) in relation "pg_database" 2024-10-26 14:24:52.768 UTC [2447791:1] ERROR: canceling autovacuum task 2024-10-26 14:24:52.768 UTC [2447791:2] CONTEXT: while updating tuple (0,20) in relation "pg_database" 2024-10-26 14:25:52.777 UTC [2451018:1] ERROR: canceling autovacuum task 2024-10-26 14:25:52.777 UTC [2451018:2] CONTEXT: while updating tuple (0,20) in relation "pg_database" 2024-10-26 14:26:52.789 UTC [2454071:1] ERROR: canceling autovacuum task 2024-10-26 14:26:52.789 UTC [2454071:2] CONTEXT: while updating tuple (0,20) in relation "pg_database" 2024-10-26 14:27:16.322 UTC [2442306:1] LOG: checkpoint starting: time 2024-10-26 14:27:52.798 UTC [2457311:1] ERROR: canceling autovacuum task 2024-10-26 14:27:52.798 UTC [2457311:2] CONTEXT: while updating tuple (0,20) in relation "pg_database" 2024-10-26 14:28:51.755 UTC [2444666:37889] isolation/intra-grant-inplace-db/control connection LOG: execute isolationtester_waiting: SELECT pg_catalog.pg_isolation_test_session_is_blocked($1, '{2444667,2444668,2444669}') 2024-10-26 14:28:51.755 UTC [2444666:37890] isolation/intra-grant-inplace-db/control connection DETAIL: Parameters: $1 = '2444668' 2024-10-26 14:28:51.810 UTC [2463672:1] [unknown] LOG: connection received: host=[local] 2024-10-26 14:28:51.812 UTC [2444668:7] isolation/intra-grant-inplace-db/s2 ERROR: canceling statement due to user request 2024-10-26 14:28:51.812 UTC [2444668:8] isolation/intra-grant-inplace-db/s2 CONTEXT: while scanning block 0 of relation "pg_catalog.pg_database" 2024-10-26 14:28:51.812 UTC [2444668:9] isolation/intra-grant-inplace-db/s2 STATEMENT: VACUUM (FREEZE); === I would have expected these locking-relevant events: - GRANT stamped a pg_database tuple with an xmax. - auto-analyze sought to update the same tuple, so it acquired LOCKTAG_TUPLE and entered XactLockTableWait(xmax-from-GRANT). - Non-auto VACUUM from step vac2 blocked on acquiring LOCKTAG_TUPLE. pg_isolation_test_session_is_blocked() considers this not blocked, since blocking on autovacuum doesn't count for test output purposes. - Deadlock detector notices auto-analyze is blocking vac2, hence "canceling autovacuum task" after 1s. - vac2 finishes its LOCKTAG_TUPLE acquisition and enters XactLockTableWait(xmax-from-GRANT). - pg_isolation_test_session_is_blocked() now considers vac2 blocked. The timeout suggests some subset of that didn't happen. It's odd that a new auto-analyze starts every minute, each of which exits due to blocking vac2. I likely got something wrong in commit aac2c9b or its parent (2024-09-24). I'll work on reproducing this. Thanks, nm -
Re: heap_inplace_lock vs. autovacuum w/ LOCKTAG_TUPLE
Noah Misch <noah@leadboat.com> — 2024-10-27T04:09:28Z
On Sat, Oct 26, 2024 at 11:49:36AM -0700, Noah Misch wrote: > intra-grant-inplace-db.spec got a novel failure today: > https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=sarus&dt=2024-10-26%2014%3A08%3A58 > > The isolationtester_waiting query is supposed to detect that step vac2 is > blocked. vac2 didn't finish within the timeout, but isolationtester_waiting > never considered it blocked. > ... work on reproducing this. I'm running loops of three workloads that might reproduce this, on s390x: - A buildfarm config like buildfarm member sarus. - A workload where autovacuum vac_update_datfrozenxid() takes >10s, but non-auto "VACUUM (ONLY_DATABASE_STATS)" runs in a loop under lock_timeout=5s. This notices if the non-auto VACUUM ever fails to cancel autovacuum. I apply the attached inplace200-bench-vac-v0.1.patch, then run contrib/amcheck/t/089_vac.pl. - A workload to make vac2's deadlock detector run when an autovacuum worker is starting. That's one of my candidate explanations of the events behind the failure log. I apply the attached inplace190-repro-autovacuum-v0.1.patch, then run intra-grant-inplace-db.spec with debug_parallel_query=regress and autovacuum_naptime=1s. This regularly gets vac2 to cancel autovacuum. So far, those have seen nothing like the failed run. I'm inclined to make isolationtester log pg_stat_activity and pg_locks whenever a step times out. That would have ruled out many explanations for what happened on sarus. However, logging on timeout won't help much until something can reproduce the timeout. > It's odd that a new > auto-analyze starts every minute, each of which exits due to blocking vac2. Every autovacuum_naptime, a new worker cancels the old one due to wanting the old worker's LOCKTAG_DATABASE_FROZEN_IDS. One can see this with "BEGIN; GRANT TEMP ON DATABASE postgres TO pg_monitor;". That open transaction's xmax prevents vac_update_datfrozenxid() from finishing. While that transaction remains open, every autovacuum_naptime after the first will log a cancellation of the previous autovacuum worker. (This assumes each autovacuum worker, having negligible real work to do, reaches vac_update_datfrozenxid() before the next autovacuum_naptime.) That's likely not ideal, but it doesn't explain the sarus failure.
-
Re: heap_inplace_lock vs. autovacuum w/ LOCKTAG_TUPLE
Alexander Law <exclusion@gmail.com> — 2024-10-27T05:00:00Z
Hello Noah, 27.10.2024 07:09, Noah Misch wrote: > On Sat, Oct 26, 2024 at 11:49:36AM -0700, Noah Misch wrote: >> intra-grant-inplace-db.spec got a novel failure today: >> https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=sarus&dt=2024-10-26%2014%3A08%3A58 >> >> The isolationtester_waiting query is supposed to detect that step vac2 is >> blocked. vac2 didn't finish within the timeout, but isolationtester_waiting >> never considered it blocked. >> ... work on reproducing this. FWIW, there was a similar failure in August: [1], and I also could not reproduce that locally, yet wrote a preliminary analysis at [2] in the Unsorted section, in the hope to see it again and continue investigation. [1] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=iguana&dt=2024-08-29%2013%3A57%3A57 [2] https://wiki.postgresql.org/wiki/Known_Buildfarm_Test_Failures Best regards, Alexander
-
Re: heap_inplace_lock vs. autovacuum w/ LOCKTAG_TUPLE
Noah Misch <noah@leadboat.com> — 2024-10-27T21:40:35Z
On Sun, Oct 27, 2024 at 08:00:00AM +0300, Alexander Lakhin wrote: > 27.10.2024 07:09, Noah Misch wrote: > > On Sat, Oct 26, 2024 at 11:49:36AM -0700, Noah Misch wrote: > > > intra-grant-inplace-db.spec got a novel failure today: > > > https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=sarus&dt=2024-10-26%2014%3A08%3A58 > > > > > > The isolationtester_waiting query is supposed to detect that step vac2 is > > > blocked. vac2 didn't finish within the timeout, but isolationtester_waiting > > > never considered it blocked. > > > ... work on reproducing this. The attached demo reproduces $SUBJECT for me. The clue was 'CONTEXT: while scanning block 0 of relation "pg_catalog.pg_database"'. That vacuum_error_callback() message indicated VACUUM_ERRCB_PHASE_SCAN_HEAP as the current phase. That implies vac2 had not reached any inplace update, any LOCKTAG_TUPLE, or any part of vac_update_datfrozenxid(). I bet vac2 was stuck in LockBufferForCleanup(). Concurrently, a sequence of autovacuum workers held a buffer pin blocking that cleanup. The demo makes two changes: a. Start intra-grant-inplace-db.spec step vac2 just after some autovacuum worker is blocked on the xid of the uncommitted GRANT. While blocked, the worker holds a pin on the one pg_database page. vac2 needs LockBufferForCleanup($THAT_PAGE). b. Make LockBufferForCleanup() sleep 10ms after WAIT_EVENT_BUFFER_PIN, to give the next autovacuum worker time to win the pinning race. LockBufferForCleanup() waits for a pin count to fall to 1. While waiting, its techniques are less sophisticated than what we have for lock.c heavyweight locks. UnpinBufferNoOwner() notifies the cleanup waiter, but nothing stops another backend from pinning before the cleanup waiter reacts. We have code to cancel an autovacuum for the purpose of liberating a heavyweight lock, but we don't have code like that to free a pin. pg_isolation_test_session_is_blocked() doesn't detect buffer pin blockages. Two fix candidates look most promising: 1. Unpin before heap_inplace_lock() sleeps. 2. Change intra-grant-inplace-db.spec to test freezing only MXIDs, not XIDs. Let's do (1), as attached. Apart from some arguably-convoluted call stacks, this has no disadvantages. An earlier version did unpin. postgr.es/m/20240822073200.4f.nmisch@google.com stopped that, arguing, "heap_update() doesn't optimize that way". In light of $SUBJECT, I no longer see heap_update() as the applicable standard. Since autovacuum can run anytime, it has an extra duty to be non-disruptive. heap_update() during auto-analyze won't wait much, because analyze takes a self-exclusive table lock and is the sole writer of stats tables. Inplace updates during autovacuum are different. They do contend with other transactions. Since we lack code to cancel an autovacuum to free a pin, a long-lived pin in autovacuum is more disruptive than a long-lived lock in autovacuum. While I've not tried it, I expect (2) would work as follows. pg_database won't contain MXIDs, so lazy_scan_noprune() would approve continuing without the cleanup lock. Unlike (1), this wouldn't help concurrency outside the test. > FWIW, there was a similar failure in August: [1], and I also could not > reproduce that locally, yet wrote a preliminary analysis at [2] in the > Unsorted section, in the hope to see it again and continue investigation. > > [1] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=iguana&dt=2024-08-29%2013%3A57%3A57 > [2] https://wiki.postgresql.org/wiki/Known_Buildfarm_Test_Failures Thanks. I had not known about iguana's failure. What are the chances that the buffer pin could explain that one?