diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index 016ce22..1115afc 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -487,6 +487,19 @@ _bt_log_reuse_page(Relation rel, BlockNumber blkno, TransactionId latestRemovedX } /* + * _bt_prefetchbuf() -- Prefetch a buffer by block number + */ +void +_bt_prefetchbuf(Relation rel, BlockNumber blkno) +{ + if (blkno != P_NEW && blkno != P_NONE) + { + /* Just prefetch an existing block of the relation */ + PrefetchBuffer(rel, MAIN_FORKNUM, blkno); + } +} + +/* * _bt_getbuf() -- Get a buffer by block number for read or write. * * blkno == P_NEW means to get an unallocated index page. The page diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index e0c9523..22c6d34 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -28,7 +28,8 @@ static bool _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum); static void _bt_saveitem(BTScanOpaque so, int itemIndex, OffsetNumber offnum, IndexTuple itup); -static bool _bt_steppage(IndexScanDesc scan, ScanDirection dir); +static bool _bt_steppage(IndexScanDesc scan, ScanDirection dir, + bool prefetch); static Buffer _bt_walk_left(Relation rel, Buffer buf); static bool _bt_endpoint(IndexScanDesc scan, ScanDirection dir); @@ -961,7 +962,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) * There's no actually-matching data on this page. Try to advance to * the next page. Return false if there's no matching data at all. */ - if (!_bt_steppage(scan, dir)) + if (!_bt_steppage(scan, dir, false)) return false; } @@ -1008,7 +1009,7 @@ _bt_next(IndexScanDesc scan, ScanDirection dir) /* We must acquire lock before applying _bt_steppage */ Assert(BufferIsValid(so->currPos.buf)); LockBuffer(so->currPos.buf, BT_READ); - if (!_bt_steppage(scan, dir)) + if (!_bt_steppage(scan, dir, target_prefetch_pages > 0)) return false; /* Drop the lock, but not pin, on the new page */ LockBuffer(so->currPos.buf, BUFFER_LOCK_UNLOCK); @@ -1021,7 +1022,7 @@ _bt_next(IndexScanDesc scan, ScanDirection dir) /* We must acquire lock before applying _bt_steppage */ Assert(BufferIsValid(so->currPos.buf)); LockBuffer(so->currPos.buf, BT_READ); - if (!_bt_steppage(scan, dir)) + if (!_bt_steppage(scan, dir, target_prefetch_pages > 0)) return false; /* Drop the lock, but not pin, on the new page */ LockBuffer(so->currPos.buf, BUFFER_LOCK_UNLOCK); @@ -1180,7 +1181,7 @@ _bt_saveitem(BTScanOpaque so, int itemIndex, * locks and pins, set so->currPos.buf to InvalidBuffer, and return FALSE. */ static bool -_bt_steppage(IndexScanDesc scan, ScanDirection dir) +_bt_steppage(IndexScanDesc scan, ScanDirection dir, bool prefetch) { BTScanOpaque so = (BTScanOpaque) scan->opaque; Relation rel; @@ -1243,8 +1244,17 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir) PredicateLockPage(rel, blkno, scan->xs_snapshot); /* see if there are any matches on this page */ /* note that this will clear moreRight if we can stop */ - if (_bt_readpage(scan, dir, P_FIRSTDATAKEY(opaque))) + if (_bt_readpage(scan, dir, P_FIRSTDATAKEY(opaque))) { + if (prefetch && so->currPos.moreRight + && (opaque->btpo_next != (blkno+1))) + { + /* start prefetch on next page, but not + if we're reading sequentially already, + as it's counterproductive in those cases */ + _bt_prefetchbuf(rel, opaque->btpo_next); + } break; + } } /* nope, keep going */ blkno = opaque->btpo_next; @@ -1291,8 +1301,13 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir) PredicateLockPage(rel, BufferGetBlockNumber(so->currPos.buf), scan->xs_snapshot); /* see if there are any matches on this page */ /* note that this will clear moreLeft if we can stop */ - if (_bt_readpage(scan, dir, PageGetMaxOffsetNumber(page))) + if (_bt_readpage(scan, dir, PageGetMaxOffsetNumber(page))) { + if (prefetch && so->currPos.moreLeft) { + /* start prefetch on next page */ + _bt_prefetchbuf(rel, opaque->btpo_prev); + } break; + } } } } @@ -1587,7 +1602,7 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir) * There's no actually-matching data on this page. Try to advance to * the next page. Return false if there's no matching data at all. */ - if (!_bt_steppage(scan, dir)) + if (!_bt_steppage(scan, dir, false)) return false; } diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index d4941e0..3360b6b 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -628,6 +628,7 @@ extern Buffer _bt_getroot(Relation rel, int access); extern Buffer _bt_gettrueroot(Relation rel); extern void _bt_checkpage(Relation rel, Buffer buf); extern Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access); +extern void _bt_prefetchbuf(Relation rel, BlockNumber blkno); extern Buffer _bt_relandgetbuf(Relation rel, Buffer obuf, BlockNumber blkno, int access); extern void _bt_relbuf(Relation rel, Buffer buf);