Re: BUG #19620: pg_class index corruption caused by statement_timeout during VACUUM FULL

From: Zheng Hacker <hackerzheng666(at)gmail(dot)com>
To: Andrey Borodin <x4mmm(at)yandex-team(dot)ru>
Cc: PostgreSQL mailing lists <pgsql-bugs(at)lists(dot)postgresql(dot)org>
Subject: Re: BUG #19620: pg_class index corruption caused by statement_timeout during VACUUM FULL
Date: 2026-08-17 02:20:21
Message-ID: CAJedcCxyNVGt9sb5KtJBt=1HweyJ8VdDxcE-_sLiGVoDSZGzKg@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

Hi Andrey,

Thanks for pointing that out.

We re-ran the reproducer for 2,000 rounds with autovacuum=off,
together with max_worker_processes=0,
max_parallel_workers_per_gather=0, and
max_parallel_maintenance_workers=0. We saw no corruption or crashes,
and autovacuum_count for pg_class stayed at 0 throughout the test.

So it looks like the issue only reproduces when autovacuum can run
concurrently with the index build, which matches the behavior
described in #18490 and #17386.

Thanks again for the clarification.

Best,
Zheng Wang

Andrey Borodin <x4mmm(at)yandex-team(dot)ru> 于2026年8月17日周一 00:01写道:
>
>
>
> > On 15 Aug 2026, at 05:37, PG Bug reporting form <noreply(at)postgresql(dot)org> wrote:
> >
> > What is new: all known reports require concurrency (parallel workers,
> > concurrent connections, concurrent REINDEX). This reproducer triggers
> > the same corruption in a single session with all parallelism disabled,
> > via statement cancellation alone. This is an interrupt-safety bug in
> > catalog index maintenance, distinct from the concurrency races in the
> > known reports.
>
>
> Hi Zheng,
>
> Thanks for the report. This is worth fixing for sure, thanks for raising
> attention to this.
>
> I believe this is a known bug, unfixed since July 2020 [0]. Justin
> Pryzby hit the same duplicate-TID corruption in a pg_class index, and
> Peter Geoghegan and Tom Lane diagnosed it there; Peter also pointed at
> that thread when BUG #18490 arrived in 2024 [1]. The mechanism is in
> heapam_index_build_range_scan(): for a HEAPTUPLE_INSERT_IN_PROGRESS
> tuple inserted by another transaction, the build waits only when it is
> checking uniqueness. So for a non-unique index our opinion of which HOT
> chain member is live can change mid-scan, and the build emits two
> entries for one chain, both carrying the chain root's TID.
>
> Worth adding, since that thread only ever discussed the assertion: this
> is not confined to assert builds. I reproduced on REL_18_STABLE with
> two sessions, one looping REINDEX INDEX
> pg_class_tblspc_relfilenode_index and one looping CREATE TABLE /
> CREATE INDEX / DROP TABLE, with no statement_timeout anywhere. A
> cassert build trips comparetup_index_btree_tiebreak() in 0.4 seconds. A
> build without assertions completes the rebuild and leaves the catalog
> index corrupt on disk, where amcheck finds it after 23 iterations:
>
> ERROR: posting list contains misplaced TID in index
> "pg_class_tblspc_relfilenode_index"
> DETAIL: Index tid=(1,210) posting list offset=1 page lsn=0/1C2A950.
>
> So bt_index_check() on catalog indexes seems worth running in
> production....
>
> Now the thing to check. I suspect your reproducer is concurrent after
> all, which would make this the same bug rather than a new one.
> max_worker_processes = 0 does not turn autovacuum off. With that
> setting autovacuum and autoanalyze are still running, I see 6
> on pg_class itself within half a minute. Some of those updates
> a pg_class row without touching an indexed column, which is a HOT
> update on pg_class, and that is precisely the concurrent writer the
> 2020 mechanism needs. The code also seems to require one: both branches
> that can emit a second entry for a chain sit inside
> "if (!TransactionIdIsCurrentTransactionId(xwait))", so a backend acting
> alone should not be able to reach them.
>
> Could you set autovacuum = off in postgresql.conf, rather than relying
> on max_worker_processes, and re-run your loop? If it still corrupts,
> then you do have something new and I would very much like to see it. It
> would also help to know the xmin of the two heap tuples your duplicate
> pointers reference, and whether that XID belongs to your session.
>
> I could not reproduce a single-session failure myself, but that is weak
> evidence either way, so I would rather have your answer than my guess.
>
> Thank you!
>
> Best regards, Andrey Borodin.
>
> [0] https://www.postgresql.org/message-id/20200728151002.GE20393%40telsasoft.com
> [1] https://www.postgresql.org/message-id/CAH2-WzkaOCUV_0JYmbv%3DZKH5cs6X27eKZLouWq0d6_meGyNJtg%40mail.gmail.com

In response to

Browse pgsql-bugs by date

  From Date Subject
Next Message Zexin Li 2026-08-17 03:23:10 Re: BUG #19598: pg_waldump: -s/-e accept out-of-range WAL locations and silently use the low 32 bits
Previous Message Zexin Li 2026-08-16 23:36:01 Re: BUG #19583: macaddr input accepts octet fields longer than 8 hex digits