Re: pgsql: Avoid improbable PANIC during heap_update.

From: Jeff Davis <pgsql(at)j-davis(dot)com>
To: Peter Geoghegan <pg(at)bowt(dot)ie>, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: Jaime Casanova <jcasanov(at)systemguards(dot)com(dot)ec>, pgsql-committers(at)lists(dot)postgresql(dot)org
Subject: Re: pgsql: Avoid improbable PANIC during heap_update.
Date: 2022-10-01 16:35:31
Message-ID: baa25a6fc7c725d28ec5d0b7787230180b45a275.camel@j-davis.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-committers pgsql-hackers

On Fri, 2022-09-30 at 21:23 -0700, Peter Geoghegan wrote:
> 2490     page = BufferGetPage(buffer);
> 2491
> 2492     /*
> 2493      * Before locking the buffer, pin the visibility map page if
> it appears to
> 2494      * be necessary.  Since we haven't got the lock yet, someone
> else might be
> 2495      * in the middle of changing this, so we'll need to recheck
> after we have
> 2496      * the lock.
> 2497      */
> 2498     if (PageIsAllVisible(page))
> 2499         visibilitymap_pin(relation, block, &vmbuffer);
>
> So we're calling visibilitymap_pin() having just acquired a buffer
> pin
> on a heap page buffer for the first time, and without acquiring a
> buffer lock on the same heap page (we don't hold one now, and we've
> never held one at some earlier point).
>
> Without Jeff's bugfix, nothing stops heap_delete() from getting a pin
> on a heap page that happens to have already been cleanup locked by
> another session running VACUUM. The same session could then
> (correctly) observe that the page does not have PD_ALL_VISIBLE set --
> not yet. 

With you so far; I had considered this code path and was still unable
to repro.

> VACUUM might then set PD_ALL_VISIBLE, without having to
> acquire any kind of interlock that heap_delete() will reliably
> notice.
> After all, VACUUM had a cleanup lock before the other session's call
> to heap_delete() even began -- so the responsibility has to lie with
> heap_delete().

Directly after the code you reference above, there is (in 5f9dda4c06,
right before my patch):

2501 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
2502
2503 /*
2504 * If we didn't pin the visibility map page and the page has
become all
2505 * visible while we were busy locking the buffer, we'll have
to unlock and
2506 * re-lock, to avoid holding the buffer lock across an I/O.
That's a bit
2507 * unfortunate, but hopefully shouldn't happen often.
2508 */
2509 if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
2510 {
2511 LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
2512 visibilitymap_pin(relation, block, &vmbuffer);
2513 LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
2514 }

Doesn't that deal with the case you brought up directly? heap_delete()
can't get the exclusive lock until VACUUM releases its cleanup lock, at
which point all-visible will be set. Then heap_delete() should notice
in line 2509 and then pin the VM buffer. Right?

And I don't think a similar issue exists when the locks are briefly
released on lines 2563 or 2606. The pin is held until after the VM bit
is cleared (aside from an error path and an early return):

2489 buffer = ReadBuffer(relation, block);
...
2717 if (PageIsAllVisible(page))
2718 {
2719 all_visible_cleared = true;
2720 PageClearAllVisible(page);
...
2835 ReleaseBuffer(buffer);

If VACCUM hasn't acquired the cleanup lock before 2489, it can't get
one until heap_delete() is done looking at the all-visible bit anyway.
So I don't see how my patch would have fixed it even if that was the
problem.

Of course, I must be wrong somewhere, because the bug seems to exist.

--
Jeff Davis
PostgreSQL Contributor Team - AWS

In response to

Responses

Browse pgsql-committers by date

  From Date Subject
Next Message Peter Geoghegan 2022-10-01 16:53:59 Re: pgsql: Avoid improbable PANIC during heap_update.
Previous Message Peter Eisentraut 2022-10-01 10:52:05 pgsql: Fix tiny memory leaks

Browse pgsql-hackers by date

  From Date Subject
Next Message Peter Geoghegan 2022-10-01 16:53:59 Re: pgsql: Avoid improbable PANIC during heap_update.
Previous Message Arne Roland 2022-10-01 16:34:16 Re: missing indexes in indexlist with partitioned tables