diff --git a/src/backend/access/heap/heapam_indexscan.c b/src/backend/access/heap/heapam_indexscan.c index c36b804d1e3..bbd8a165ddc 100644 --- a/src/backend/access/heap/heapam_indexscan.c +++ b/src/backend/access/heap/heapam_indexscan.c @@ -32,6 +32,7 @@ heapam_index_fetch_begin(Relation rel, uint32 flags) hscan->xs_base.rel = rel; hscan->xs_base.flags = flags; hscan->xs_cbuf = InvalidBuffer; + hscan->xs_blk = InvalidBlockNumber; hscan->xs_vmbuffer = InvalidBuffer; return &hscan->xs_base; @@ -46,6 +47,7 @@ heapam_index_fetch_reset(IndexFetchTableData *scan) { ReleaseBuffer(hscan->xs_cbuf); hscan->xs_cbuf = InvalidBuffer; + hscan->xs_blk = InvalidBlockNumber; } if (BufferIsValid(hscan->xs_vmbuffer)) @@ -240,25 +242,30 @@ heapam_index_fetch_tuple(struct IndexFetchTableData *scan, Assert(TTS_IS_BUFFERTUPLE(slot)); - /* We can skip the buffer-switching logic if we're in mid-HOT chain. */ - if (!*heap_continue) + /* We can skip the buffer-switching logic if we're on the same page. */ + if (hscan->xs_blk != ItemPointerGetBlockNumber(tid)) { - /* Switch to correct buffer if we don't have it already */ - Buffer prev_buf = hscan->xs_cbuf; + Assert(!*heap_continue); - hscan->xs_cbuf = ReleaseAndReadBuffer(hscan->xs_cbuf, - hscan->xs_base.rel, - ItemPointerGetBlockNumber(tid)); + /* Remember this buffer's block number for next time */ + hscan->xs_blk = ItemPointerGetBlockNumber(tid); + + if (BufferIsValid(hscan->xs_cbuf)) + ReleaseBuffer(hscan->xs_cbuf); + + hscan->xs_cbuf = ReadBuffer(hscan->xs_base.rel, hscan->xs_blk); /* - * Prune page, but only if we weren't already on this page + * Prune page when it is pinned for the first time */ - if (prev_buf != hscan->xs_cbuf) - heap_page_prune_opt(hscan->xs_base.rel, hscan->xs_cbuf, - &hscan->xs_vmbuffer, - hscan->xs_base.flags & SO_HINT_REL_READ_ONLY); + heap_page_prune_opt(hscan->xs_base.rel, hscan->xs_cbuf, + &hscan->xs_vmbuffer, + hscan->xs_base.flags & SO_HINT_REL_READ_ONLY); } + Assert(BufferGetBlockNumber(hscan->xs_cbuf) == hscan->xs_blk); + Assert(hscan->xs_blk == ItemPointerGetBlockNumber(tid)); + /* Obtain share-lock on the buffer so we can examine visibility */ LockBuffer(hscan->xs_cbuf, BUFFER_LOCK_SHARE); got_heap_tuple = heap_hot_search_buffer(tid, diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index cc90c821be5..5176478c295 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -122,10 +122,11 @@ typedef struct IndexFetchHeapData IndexFetchTableData xs_base; /* AM independent part of the descriptor */ /* - * Current heap buffer in scan, if any. NB: if xs_cbuf is not - * InvalidBuffer, we hold a pin on that buffer. + * Current heap buffer in scan (and its block number), if any. NB: if + * xs_blk is not InvalidBlockNumber, we hold a pin in xs_cbuf. */ Buffer xs_cbuf; + BlockNumber xs_blk; /* Current heap block's corresponding page in the visibility map */ Buffer xs_vmbuffer;