Re: Buffer locking is special (hints, checksums, AIO writes)

From: Andres Freund <andres(at)anarazel(dot)de>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Peter Geoghegan <pg(at)bowt(dot)ie>
Cc: Alexander Lakhin <exclusion(at)gmail(dot)com>, Chao Li <li(dot)evan(dot)chao(at)gmail(dot)com>, Kirill Reshke <reshkekirill(at)gmail(dot)com>, Heikki Linnakangas <hlinnaka(at)iki(dot)fi>, Melanie Plageman <melanieplageman(at)gmail(dot)com>, Matthias van de Meent <boekewurm+postgres(at)gmail(dot)com>, pgsql-hackers(at)postgresql(dot)org, Thomas Munro <thomas(dot)munro(at)gmail(dot)com>, Noah Misch <noah(at)leadboat(dot)com>, Robert Haas <robertmhaas(at)gmail(dot)com>, Michael Paquier <michael(dot)paquier(at)gmail(dot)com>
Subject: Re: Buffer locking is special (hints, checksums, AIO writes)
Date: 2026-01-29 17:42:41
Message-ID: crnjqun44wknh6dnd6a5deyanb2rlcec6mkrbe7pzt6o6ksjwd@ezbur3bhtlmh
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

On 2026-01-29 12:27:10 -0500, Andres Freund wrote:
> In the crashes due to Alexander's repro that I have looked at, the page is
> returned by SpGistNewBuffer()->GetFreeIndexPage(). Which afaict should only
> contain empty pages. It's easy to see how that could happen with concurrency,
> but there's none in the test.

I think I see how that happens - we reenter the page into the FSM during the
VACUUM that's part of the repro, but we previously also "recorded" it with
SpGistSetLastUsedPage(), presumably before it was emptied during vacuum. The
we reuse the page first via the "last used page" cache, making it not
empty. Then we get the same page via the FSM, which wasn't updated when we
started filling the page via the last-used-page mechanism.

> I was just trying to repro this again while writing this message, and
> interestingly I got the same issue in nbtree this time. Which a) confirms
> Peter's statement that the "conditionally locking a buffer we already locked"
> issue exists for nbtree b) makes me suspect something odd is happening around
> indexfsm.

Not sure how that happens in a single threaded workload yet, though.

> diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
> index 6f935648ae9..f5602f4e7e1 100644
> --- a/src/backend/storage/buffer/bufmgr.c
> +++ b/src/backend/storage/buffer/bufmgr.c
> @@ -5895,6 +5895,13 @@ BufferLockUnlock(Buffer buffer, BufferDesc *buf_hdr)
>
> /*
> * Acquire the content lock for the buffer, but only if we don't have to wait.
> + *
> + * It is allowed to try to conditionally acquire a lock on a buffer that this
> + * backend has already locked, but the lock acquisition will always fail, even
> + * if the new lock acquisition does not conflict with an already held lock
> + * (e.g. two share locks). This is because we don't track per-backend
> + * ownership of multiple lock levels. That is ok for the current uses of
> + * BufferLockConditional().
> */
> static bool
> BufferLockConditional(Buffer buffer, BufferDesc *buf_hdr, BufferLockMode mode)
> @@ -5902,11 +5909,16 @@ BufferLockConditional(Buffer buffer, BufferDesc *buf_hdr, BufferLockMode mode)
> PrivateRefCountEntry *entry = GetPrivateRefCountEntry(buffer, true);
> bool mustwait;
>
> - /*
> - * We better not already hold a lock on the buffer.
> - */
> Assert(entry->data.lockmode == BUFFER_LOCK_UNLOCK);
>

Err, this should have been removed, I accidentally re-added the hunk while
experimenting.

Greetings,

Andres Freund

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Álvaro Herrera 2026-01-29 17:45:12 Re: Consistently use the XLogRecPtrIsInvalid() macro
Previous Message Andres Freund 2026-01-29 17:27:10 Re: Buffer locking is special (hints, checksums, AIO writes)