• Tomas Vondra's avatar
    Don't add non-existent pages to bitmap from BRIN · 23607a81
    Tomas Vondra authored
    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
    23607a81
brin.c 50.2 KB