Move EXPLAIN counter increment to heapam_scan_bitmap_next_block

Increment the lossy and exact page counters for EXPLAIN of bitmap heap
scans in heapam_scan_bitmap_next_block(). Note that other table AMs will
need to do this as well

Pushing the counters into heapam_scan_bitmap_next_block() is required to
be able to use the read stream API for bitmap heap scans. The bitmap
iterator must be advanced from inside the read stream callback, so
TBMIterateResults cannot be used as a flow control mechanism in
BitmapHeapNext().

Author: Melanie Plageman
Reviewed-by: Tomas Vondra, Heikki Linnakangas
Discussion: https://postgr.es/m/063e4eb4-32d9-439e-a0b1-75565a9835a8%40iki.fi
This commit is contained in:
Melanie Plageman 2024-10-25 10:11:46 -04:00
parent 8e7e672cda
commit 7bd7aa4d30
3 changed files with 27 additions and 14 deletions

View File

@ -2115,7 +2115,8 @@ heapam_estimate_rel_size(Relation rel, int32 *attr_widths,
static bool static bool
heapam_scan_bitmap_next_block(TableScanDesc scan, heapam_scan_bitmap_next_block(TableScanDesc scan,
TBMIterateResult *tbmres) TBMIterateResult *tbmres,
uint64 *lossy_pages, uint64 *exact_pages)
{ {
HeapScanDesc hscan = (HeapScanDesc) scan; HeapScanDesc hscan = (HeapScanDesc) scan;
BlockNumber block = tbmres->blockno; BlockNumber block = tbmres->blockno;
@ -2243,6 +2244,11 @@ heapam_scan_bitmap_next_block(TableScanDesc scan,
Assert(ntup <= MaxHeapTuplesPerPage); Assert(ntup <= MaxHeapTuplesPerPage);
hscan->rs_ntuples = ntup; hscan->rs_ntuples = ntup;
if (tbmres->ntuples >= 0)
(*exact_pages)++;
else
(*lossy_pages)++;
return ntup > 0; return ntup > 0;
} }

View File

@ -212,8 +212,6 @@ BitmapHeapNext(BitmapHeapScanState *node)
for (;;) for (;;)
{ {
bool valid_block;
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
/* /*
@ -233,14 +231,9 @@ BitmapHeapNext(BitmapHeapScanState *node)
BitmapAdjustPrefetchIterator(node, tbmres->blockno); BitmapAdjustPrefetchIterator(node, tbmres->blockno);
valid_block = table_scan_bitmap_next_block(scan, tbmres); if (!table_scan_bitmap_next_block(scan, tbmres,
&node->stats.lossy_pages,
if (tbmres->ntuples >= 0) &node->stats.exact_pages))
node->stats.exact_pages++;
else
node->stats.lossy_pages++;
if (!valid_block)
{ {
/* AM doesn't think this block is valid, skip */ /* AM doesn't think this block is valid, skip */
continue; continue;

View File

@ -796,6 +796,10 @@ typedef struct TableAmRoutine
* on the page have to be returned, otherwise the tuples at offsets in * on the page have to be returned, otherwise the tuples at offsets in
* `tbmres->offsets` need to be returned. * `tbmres->offsets` need to be returned.
* *
* `lossy_pages` and `exact_pages` are EXPLAIN counters that can be
* incremented by the table AM to indicate whether or not the block's
* representation in the bitmap is lossy.
*
* XXX: Currently this may only be implemented if the AM uses md.c as its * XXX: Currently this may only be implemented if the AM uses md.c as its
* storage manager, and uses ItemPointer->ip_blkid in a manner that maps * storage manager, and uses ItemPointer->ip_blkid in a manner that maps
* blockids directly to the underlying storage. nodeBitmapHeapscan.c * blockids directly to the underlying storage. nodeBitmapHeapscan.c
@ -811,7 +815,9 @@ typedef struct TableAmRoutine
* scan_bitmap_next_tuple need to exist, or neither. * scan_bitmap_next_tuple need to exist, or neither.
*/ */
bool (*scan_bitmap_next_block) (TableScanDesc scan, bool (*scan_bitmap_next_block) (TableScanDesc scan,
struct TBMIterateResult *tbmres); struct TBMIterateResult *tbmres,
uint64 *lossy_pages,
uint64 *exact_pages);
/* /*
* Fetch the next tuple of a bitmap table scan into `slot` and return true * Fetch the next tuple of a bitmap table scan into `slot` and return true
@ -1954,12 +1960,18 @@ table_relation_estimate_size(Relation rel, int32 *attr_widths,
* table_beginscan_bm(). Returns false if there are no tuples to be found on * table_beginscan_bm(). Returns false if there are no tuples to be found on
* the page, true otherwise. * the page, true otherwise.
* *
* `lossy_pages` and `exact_pages` are EXPLAIN counters that can be
* incremented by the table AM to indicate whether or not the block's
* representation in the bitmap is lossy.
*
* Note, this is an optionally implemented function, therefore should only be * Note, this is an optionally implemented function, therefore should only be
* used after verifying the presence (at plan time or such). * used after verifying the presence (at plan time or such).
*/ */
static inline bool static inline bool
table_scan_bitmap_next_block(TableScanDesc scan, table_scan_bitmap_next_block(TableScanDesc scan,
struct TBMIterateResult *tbmres) struct TBMIterateResult *tbmres,
uint64 *lossy_pages,
uint64 *exact_pages)
{ {
/* /*
* We don't expect direct calls to table_scan_bitmap_next_block with valid * We don't expect direct calls to table_scan_bitmap_next_block with valid
@ -1970,7 +1982,9 @@ table_scan_bitmap_next_block(TableScanDesc scan,
elog(ERROR, "unexpected table_scan_bitmap_next_block call during logical decoding"); elog(ERROR, "unexpected table_scan_bitmap_next_block call during logical decoding");
return scan->rs_rd->rd_tableam->scan_bitmap_next_block(scan, return scan->rs_rd->rd_tableam->scan_bitmap_next_block(scan,
tbmres); tbmres,
lossy_pages,
exact_pages);
} }
/* /*