Subject: Make pg_prewarm, autoprewarm yield for waiting DDL

From: SATYANARAYANA NARLAPURAM <[email-masked]>
Date: Wed, 25 Mar 2026 14:32:23 -0700

Both pg_prewarm() and the autoprewarm background worker hold
AccessShareLock on the target relation for the entire duration of
prewarming. On large tables this can take a long time, which means
that any DDL that needs a stronger lock (TRUNCATE, DROP TABLE, ALTER TABLE,
etc.) is blocked for the full duration.

VACUUM already solves this same problem during heap truncation: it
periodically calls LockHasWaitersRelation() and backs off when a
conflicting waiter is detected (see lazy_truncate_heap()).

The attached patch applies the same pattern to pg_prewarm and autoprewarm.
Every 1024 blocks, each code path checks for a waiter and if found then the
lock is released so that the DDL can proceed. Patch handles the relation
truncation, drop cases by emitting an error message. If the relation was
only partially truncated, the endpoint is adjusted downward and prewarming
continues.
When no DDL is waiting, the only overhead is one lock-table probe per 1024
blocks.

While developing this patch I discovered that LockHasWaiters() crashes with
a segfault when the lock in question was acquired via the fast-path
optimization, details in [1].

The patch includes a TAP test (t/002_lock_yield.pl) that exercises the
TRUNCATE and DROP TABLE scenarios using injection points.

Thanks,
Satya

[1]:
https://www.postgresql.org/message-id/CAHg%2BQDe_%3DZahnRx37bzrqYenKn_S5YDQ00fTfwe-ZUmjqO%3DqLg%40mail.gmail.com

---

From: Ashutosh Sharma <[email-masked]>
Date: Mon, 30 Mar 2026 16:41:08 +0530

Hi Satya,

On Thu, Mar 26, 2026 at 3:02 AM SATYANARAYANA NARLAPURAM
<[email-masked]> wrote:
>
> Both pg_prewarm() and the autoprewarm background worker hold AccessShareLock on the target relation for the entire duration of prewarming. On large tables this can take a long time, which means
> that any DDL that needs a stronger lock (TRUNCATE, DROP TABLE, ALTER TABLE, etc.) is blocked for the full duration.
>

This indeed seems like a valid concern.

> VACUUM already solves this same problem during heap truncation: it periodically calls LockHasWaitersRelation() and backs off when a conflicting waiter is detected (see lazy_truncate_heap()).
>

Yes, in the current design, waiter-aware backoff logic is present in
some code paths (like VACUUM) that acquire the strongest lock
(AccessExclusiveLock), but is largely absent from paths that hold
weaker locks.

While AccessShareLock conflicts with only one lock mode
(AccessExclusiveLock), a long-held AccessShareLock, as in the
pg_prewarm case you mentioned, can still cause meaningful delays for
DDL or maintenance operations that require AccessExclusiveLock. So
despite its narrow conflict set, the practical impact can be quite
significant in some cases. On that basis, extending waiter-aware
behavior to places like pg_prewarm (or similar long-running lock
holders) seems reasonable, though it would be worth seeing how others
think about it.

--
With Regards,
Ashutosh Sharma.