From e96746d07b8dfcdb17082b54524505163f5e237a Mon Sep 17 00:00:00 2001 From: Hari Babu Date: Tue, 24 Jul 2018 23:18:15 +1000 Subject: [PATCH 2/2] New API to get heap page tuples This API is used in bitmap scan to get all the visible tuples from the page. --- src/backend/access/heap/heapam_handler.c | 105 ++++++++++++++++++++++ src/backend/executor/nodeBitmapHeapscan.c | 100 ++------------------- src/include/access/tableam.h | 20 +++++ 3 files changed, 131 insertions(+), 94 deletions(-) diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index 42eec2a2ab..a3fe110efe 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -33,9 +33,13 @@ #include "storage/bufpage.h" #include "storage/bufmgr.h" +#include "storage/predicate.h" #include "access/xact.h" +static bool heapam_fetch_tuple_from_offset(TableScanDesc sscan, BlockNumber blkno, + OffsetNumber offset, TupleTableSlot *slot); + /* ---------------------------------------------------------------- * storage AM support routines for heapam * ---------------------------------------------------------------- @@ -462,6 +466,106 @@ heapam_get_heappagescandesc(TableScanDesc sscan) return &scan->rs_pagescan; } +static void +heapam_scan_get_page_tuples(TableScanDesc scan, + HeapPageScanDesc pagescan, + TupleTableSlot *slot, + BlockNumber page, + int ntuples, + OffsetNumber *offsets) +{ + Buffer buffer; + Snapshot snapshot; + int ntup; + + /* + * Acquire pin on the target heap page, trading in any pin we held before. + */ + Assert(page < pagescan->rs_nblocks); + + scan->rs_cbuf = ReleaseAndReadBuffer(scan->rs_cbuf, + scan->rs_rd, + page); + buffer = scan->rs_cbuf; + snapshot = scan->rs_snapshot; + + ntup = 0; + + /* + * Prune and repair fragmentation for the whole page, if possible. + */ + heap_page_prune_opt(scan->rs_rd, buffer); + + /* + * We must hold share lock on the buffer content while examining tuple + * visibility. Afterwards, however, the tuples we have found to be + * visible are guaranteed good as long as we hold the buffer pin. + */ + LockBuffer(buffer, BUFFER_LOCK_SHARE); + + /* + * We need two separate strategies for lossy and non-lossy cases. + */ + if (ntuples >= 0) + { + /* + * Bitmap is non-lossy, so we just look through the offsets listed in + * tbmres; but we have to follow any HOT chain starting at each such + * offset. + */ + int curslot; + + for (curslot = 0; curslot < ntuples; curslot++) + { + OffsetNumber offnum = offsets[curslot]; + ItemPointerData tid; + HeapTupleData heapTuple; + + ItemPointerSet(&tid, page, offnum); + if (heap_hot_search_buffer(&tid, scan->rs_rd, buffer, snapshot, + &heapTuple, NULL, true)) + pagescan->rs_vistuples[ntup++] = ItemPointerGetOffsetNumber(&tid); + } + } + else + { + /* + * Bitmap is lossy, so we must examine each item pointer on the page. + * But we can ignore HOT chains, since we'll check each tuple anyway. + */ + Page dp = (Page) BufferGetPage(buffer); + OffsetNumber maxoff = PageGetMaxOffsetNumber(dp); + OffsetNumber offnum; + + for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum)) + { + ItemId lp; + bool valid; + BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot; + + lp = PageGetItemId(dp, offnum); + if (!ItemIdIsNormal(lp)) + continue; + + /* FIXME: unnecessarily pins */ + heapam_fetch_tuple_from_offset(scan, page, offnum, slot); + valid = HeapTupleSatisfies(bslot->base.tuple, snapshot, bslot->buffer); + if (valid) + { + pagescan->rs_vistuples[ntup++] = offnum; + PredicateLockTuple(scan->rs_rd, bslot->base.tuple, snapshot); + } + CheckForSerializableConflictOut(valid, scan->rs_rd, bslot->base.tuple, + buffer, snapshot); + } + } + + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); + + Assert(ntup <= MaxHeapTuplesPerPage); + pagescan->rs_ntuples = ntup; +} + static bool heapam_fetch_tuple_from_offset(TableScanDesc sscan, BlockNumber blkno, OffsetNumber offset, TupleTableSlot *slot) { @@ -683,6 +787,7 @@ heap_tableam_handler(PG_FUNCTION_ARGS) * BitmapHeap and Sample Scans */ amroutine->scan_get_heappagescandesc = heapam_get_heappagescandesc; + amroutine->scan_get_page_tuples = heapam_scan_get_page_tuples; amroutine->sync_scan_report_location = ss_report_location; amroutine->tuple_fetch_row_version = heapam_fetch_row_version; diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index 8521e45132..be123728eb 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -371,100 +371,12 @@ BitmapHeapNext(BitmapHeapScanState *node) static void bitgetpage(BitmapHeapScanState *node, TBMIterateResult *tbmres) { - TableScanDesc scan = node->ss.ss_currentScanDesc; - HeapPageScanDesc pagescan = node->pagescan; - TupleTableSlot *slot = node->ss.ss_ScanTupleSlot; - BlockNumber page = tbmres->blockno; - Buffer buffer; - Snapshot snapshot; - int ntup; - - /* - * Acquire pin on the target heap page, trading in any pin we held before. - */ - Assert(page < pagescan->rs_nblocks); - - scan->rs_cbuf = ReleaseAndReadBuffer(scan->rs_cbuf, - scan->rs_rd, - page); - buffer = scan->rs_cbuf; - snapshot = scan->rs_snapshot; - - ntup = 0; - - /* - * Prune and repair fragmentation for the whole page, if possible. - */ - heap_page_prune_opt(scan->rs_rd, buffer); - - /* - * We must hold share lock on the buffer content while examining tuple - * visibility. Afterwards, however, the tuples we have found to be - * visible are guaranteed good as long as we hold the buffer pin. - */ - LockBuffer(buffer, BUFFER_LOCK_SHARE); - - /* - * We need two separate strategies for lossy and non-lossy cases. - */ - if (tbmres->ntuples >= 0) - { - /* - * Bitmap is non-lossy, so we just look through the offsets listed in - * tbmres; but we have to follow any HOT chain starting at each such - * offset. - */ - int curslot; - - for (curslot = 0; curslot < tbmres->ntuples; curslot++) - { - OffsetNumber offnum = tbmres->offsets[curslot]; - ItemPointerData tid; - HeapTupleData heapTuple; - - ItemPointerSet(&tid, page, offnum); - if (heap_hot_search_buffer(&tid, scan->rs_rd, buffer, snapshot, - &heapTuple, NULL, true)) - pagescan->rs_vistuples[ntup++] = ItemPointerGetOffsetNumber(&tid); - } - } - else - { - /* - * Bitmap is lossy, so we must examine each item pointer on the page. - * But we can ignore HOT chains, since we'll check each tuple anyway. - */ - Page dp = (Page) BufferGetPage(buffer); - OffsetNumber maxoff = PageGetMaxOffsetNumber(dp); - OffsetNumber offnum; - - for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum)) - { - ItemId lp; - bool valid; - BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot; - - lp = PageGetItemId(dp, offnum); - if (!ItemIdIsNormal(lp)) - continue; - - /* FIXME: unnecessarily pins */ - table_tuple_fetch_from_offset(scan, page, offnum, slot); - valid = HeapTupleSatisfies(bslot->base.tuple, snapshot, bslot->buffer); - if (valid) - { - pagescan->rs_vistuples[ntup++] = offnum; - PredicateLockTuple(scan->rs_rd, bslot->base.tuple, snapshot); - } - CheckForSerializableConflictOut(valid, scan->rs_rd, bslot->base.tuple, - buffer, snapshot); - } - } - - LockBuffer(buffer, BUFFER_LOCK_UNLOCK); - - Assert(ntup <= MaxHeapTuplesPerPage); - pagescan->rs_ntuples = ntup; + table_scan_get_page_tuples(node->ss.ss_currentScanDesc, + node->pagescan, + node->ss.ss_ScanTupleSlot, + tbmres->blockno, + tbmres->ntuples, + tbmres->offsets); } /* diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h index bf675ff881..df60ba3316 100644 --- a/src/include/access/tableam.h +++ b/src/include/access/tableam.h @@ -172,6 +172,13 @@ typedef bool (*TupleFetchFollow_function)(struct IndexFetchTableData *scan, TupleTableSlot *slot, bool *call_again, bool *all_dead); +typedef void (*ScanGetPageTuples_function)(TableScanDesc scan, + HeapPageScanDesc pagescan, + TupleTableSlot *slot, + BlockNumber page, + int ntuples, + OffsetNumber *offsets); + /* * API struct for a table AM. Note this must be stored in a single palloc'd * chunk of memory. @@ -224,6 +231,7 @@ typedef struct TableAmRoutine ScanGetpage_function scan_getpage; ScanRescan_function scan_rescan; ScanUpdateSnapshot_function scan_update_snapshot; + ScanGetPageTuples_function scan_get_page_tuples; BeginIndexFetchTable_function begin_index_fetch; EndIndexFetchTable_function reset_index_fetch; @@ -472,6 +480,18 @@ table_scan_update_snapshot(TableScanDesc scan, Snapshot snapshot) scan->rs_rd->rd_tableamroutine->scan_update_snapshot(scan, snapshot); } +static inline void +table_scan_get_page_tuples(TableScanDesc scan, + HeapPageScanDesc pagescan, + TupleTableSlot *slot, + BlockNumber page, + int ntuples, + OffsetNumber *offsets) +{ + scan->rs_rd->rd_tableamroutine->scan_get_page_tuples(scan, pagescan, slot, page, ntuples, offsets); +} + + static inline TupleTableSlot * table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot) { -- 2.18.0.windows.1