Hash index bucket split bug

From: Peter Geoghegan <pg(at)bowt(dot)ie>
To: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Cc: Amit Kapila <amit(dot)kapila16(at)gmail(dot)com>, Robert Haas <robertmhaas(at)gmail(dot)com>
Subject: Hash index bucket split bug
Date: 2026-07-08 20:39:42
Message-ID: CAH2-Wz=4CJK9ysZzbzxBGGTkgAg9ib8cJyCx=9q_d1r8tf0ang@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

There's a bug in the logic for hash index scans: we fail to fully
account for concurrent bucket splits. This can lead to incorrect
results, as an affected scan may fail to return all matching rows.
This is due to an oversight in commit 7c75ef57, so all stable branches
are affected.

The underlying problem is that _hash_next fails to step from one
bucket of an in-progress to the other. In other words, it lacks the
required transition logic that _hash_readnext already has (and
_hash_readprev along with it). Note that the transition ordinarily
happens anyway, inside _hash_readpage's no-matches loop, which is why
this went unnoticed for so long: _hash_next only fails to make the
transition when the last page it reads in the first bucket contains at
least one matching tuple. In practice that means a tuple inserted into
the bucket being populated after the split began.

The attached bug fix patch v1-0001-* simply adds the missing handling
to _hash_next (copied from _hash_readnext and _hash_readprev).

I stumbled upon this bug when I asked Claude code to review a patch of
mine that adds support for the new amgetbatch interface to the hash
index AM (allowing hash indexes to perform I/O prefetching of heap
blocks). I had Claude rewrite its original reproducer into a
regression test and an isolation test, both of which appear in the
second patch.

Both tests are useful in their own way. The regression test runs
quickly and so might be worth committing alongside the fix -- but it
depends on leaving behind an incomplete split. The isolation test
demonstrates that the bug doesn't hinge upon an incomplete split. The
incomplete split case is particularly nasty, though, because the
potential for wrong answers persists until an inserter completes the
split.

--
Peter Geoghegan

Attachment Content-Type Size
v1-0001-Fix-hash-index-scans-concurrent-with-bucket-split.patch application/octet-stream 2.7 KB
v1-0002-Add-tests-for-hash-index-scans-concurrent-with-bu.patch application/octet-stream 16.9 KB

Browse pgsql-hackers by date

  From Date Subject
Next Message Nathan Bossart 2026-07-08 21:24:35 Re: Remove the refint contrib module (for v20)
Previous Message Peter Eisentraut 2026-07-08 19:24:51 Re: Add bms_offset_members() function for bitshifting Bitmapsets