postgres.git / summary / log / commit / refs

commit    e4f251be70ac792df79ed22a01bb1f05911984ef
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 792aeb5ad62..ccecd00a7e6 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -524,7 +524,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: b9cf9d7d3bed]