postgres.git / summary / log / commit / refs

commit    847612fda6f6da88441f4c823ebcbf8474bfe0b7
Author:   Tomas Vondra <tomas.vondra@postgresql.org>
Date:     Wed Apr 07 13:58:35 2021 +0000
First released in: 14.0, 9.6.22, 10.17, 11.12, 12.7, 13.3

    Don't add non-existent pages to bitmap from BRIN
    
    The code in bringetbitmap() simply added the whole matching page range
    to the TID bitmap, as determined by pages_per_range, even if some of the
    pages were beyond the end of the heap. The query then might fail with
    an error like this:
    
      ERROR:  could not open file "base/20176/20228.2" (target block
              262144): previous segment is only 131021 blocks
    
    In this case, the relation has 262093 pages (131072 and 131021 pages),
    but we're trying to acess block 262144, i.e. first block of the 3rd
    segment. At that point _mdfd_getseg() notices the preceding segment is
    incomplete, and fails.
    
    Hitting this in practice is rather unlikely, because:
    
    * Most indexes use power-of-two ranges, so segments and page ranges
      align perfectly (segment end is also a page range end).
    
    * The table size has to be just right, with the last segment being
      almost full - less than one page range from full segment, so that the
      last page range actually crosses the segment boundary.
    
    * Prefetch has to be enabled. The regular page access checks that
      pages are not beyond heap end, but prefetch does not. On older
      releases (before 12) the execution stops after hitting the first
      non-existent page, so the prefetch distance has to be sufficient
      to reach the first page in the next segment to trigger the issue.
      Since 12 it's enough to just have prefetch enabled, the prefetch
      distance does not matter.
    
    Fixed by not adding non-existent pages to the TID bitmap. Backpatch
    all the way back to 9.6 (BRIN indexes were introduced in 9.5, but that
    release is EOL).
    
    Backpatch-through: 9.6


src/backend/access/brin/brin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index ae7b729edd9..c7b403bff15 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -530,7 +530,7 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) BlockNumber pageno; for (pageno = heapBlk; - pageno <= heapBlk + opaque->bo_pagesPerRange - 1; + pageno <= Min(nblocks, heapBlk + opaque->bo_pagesPerRange) - 1; pageno++) { MemoryContextSwitchTo(oldcxt); [parent: 92273d48771a]