Re: [GSoC 2026] - B-tree Index Bloat Reduction - Approach & Questions

From: Yao Feng <fengyao0087(at)gmail(dot)com>
To: Salma El-Sayed <salmasayed182003(at)gmail(dot)com>
Cc: pgsql-hackers(at)postgresql(dot)org
Subject: Re: [GSoC 2026] - B-tree Index Bloat Reduction - Approach & Questions
Date: 2026-09-22 11:49:00
Message-ID: CAAU0Mh0k3ay2AYQagxXtF4Ofx_EAHfAf5-GpxG2h4gNKz_mwCA@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi Salma,

While testing v3, I noticed a crash in _bt_killitems() triggered by
concurrent bt_merge().

The problem
-----------

An index scan reads leaf page L, drops its content lock (keeping the
pin), and visits the heap. Finding dead tuples, it records them in
so->killedItems[]. Concurrently, bt_merge() acquires BT_WRITE on L,
moves all tuples to R, and calls BTPageSetMergedAway(), which sets
pd_lower to 32 and marks L as BTP_MERGED_AWAY.

When the scanner calls _bt_killitems() in !so->dropPin mode, it
re-acquires BT_READ and proceeds without checking page flags.
PageGetMaxOffsetNumber() returns (32 - 24) / 4 = 2, because the
8-byte safemergexid at bytes 24..31 overlaps with pd_linp[0..1].
The function then interprets safemergexid bits as ItemIdData, causing
Assert(ItemIdHasStorage) failures in debug builds or SIGSEGV in
production.

The so->dropPin path is not affected -- it checks LSN first and gives
up if the page was modified. The !so->dropPin path assumes the pin
keeps page contents stable, which holds for standard VACUUM (cleanup
lock required) but not for bt_merge() (regular BT_WRITE by design).

Proposed fix
------------

Add a check for P_ISMERGEDAWAY after acquiring the lock:

+ /*
+ * bt_merge() can convert a page to BTP_MERGED_AWAY while we hold a
+ * pin but no lock. The original tuples are gone; give up on hinting.
+ */
+ if (P_ISMERGEDAWAY(opaque))
+ goto unlock_page;

Abandoning LP_DEAD hints is harmless -- a subsequent VACUUM will clean
up the dead tuples.

Any thoughts on this?

Best regards,
Yao Feng

Attachment Content-Type Size
0002-test-injection-point.patch application/x-patch 696 bytes
test_killitems_crash.sh application/x-sh 4.0 KB
0001-nbtree-Guard-_bt_killitems-against-concurrent-page-m.patch application/x-patch 1.0 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Etsuro Fujita 2026-09-22 11:50:46 Re: Several issues with postgres_fdw stats import
Previous Message Etsuro Fujita 2026-09-22 11:38:52 Re: Several issues with postgres_fdw stats import