diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index bcf5dd368a6..a300ab856eb 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -848,9 +848,8 @@ _bt_compare(Relation rel, /* * _bt_read_parent_for_prefetch - read parent page and extract references to children for prefetch. - * This functions returns offset of first item. */ -static int +static void _bt_read_parent_for_prefetch(IndexScanDesc scan, BlockNumber parent, ScanDirection dir) { Relation rel = scan->indexRelation; @@ -880,6 +879,7 @@ _bt_read_parent_for_prefetch(IndexScanDesc scan, BlockNumber parent, ScanDirecti so->next_parent = opaque->btpo_next; if (so->next_parent == P_NONE) next_parent_prefetch_index = -1; + for (i = 0, j = 0; i < n_child; i++) { ItemId itemid = PageGetItemId(page, offnum + i); @@ -894,6 +894,7 @@ _bt_read_parent_for_prefetch(IndexScanDesc scan, BlockNumber parent, ScanDirecti so->next_parent = opaque->btpo_prev; if (so->next_parent == P_NONE) next_parent_prefetch_index = -1; + for (i = 0, j = 0; i < n_child; i++) { ItemId itemid = PageGetItemId(page, offnum + n_child - i - 1); @@ -906,7 +907,6 @@ _bt_read_parent_for_prefetch(IndexScanDesc scan, BlockNumber parent, ScanDirecti so->n_prefetch_blocks = j; so->last_prefetch_index = 0; _bt_relbuf(rel, buf); - return offnum; } /* @@ -1472,16 +1472,30 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) /* Start prefetching for index only scan */ if (so->prefetch_maximum > 0 && stack != NULL && scan->xs_want_itup) /* index only scan */ { - int first_offset = _bt_read_parent_for_prefetch(scan, stack->bts_blkno, dir); - int skip = ScanDirectionIsForward(dir) - ? stack->bts_offset - first_offset - : first_offset + so->n_prefetch_blocks - 1 - stack->bts_offset; - Assert(so->n_prefetch_blocks >= skip); - so->current_prefetch_distance = INCREASE_PREFETCH_DISTANCE_STEP; - so->n_prefetch_requests = Min(so->current_prefetch_distance, so->n_prefetch_blocks - skip); - so->last_prefetch_index = skip + so->n_prefetch_requests; - for (int i = skip; i < so->last_prefetch_index; i++) - PrefetchBuffer(rel, MAIN_FORKNUM, so->prefetch_blocks[i]); + BlockNumber leaf = BufferGetBlockNumber(buf); + + _bt_read_parent_for_prefetch(scan, stack->bts_blkno, dir); + + /* + * We can not use stack->bts_offset because once parent page is unlocked, it can be updated and state captured by + * by _bt_read_parent_for_prefetch may not match with _bt_search + */ + + for (int j = 0; j < so->n_prefetch_blocks; j++) + { + if (so->prefetch_blocks[j] == leaf) + { + so->current_prefetch_distance = INCREASE_PREFETCH_DISTANCE_STEP; + so->n_prefetch_requests = Min(so->current_prefetch_distance, so->n_prefetch_blocks - j); + so->last_prefetch_index = j + so->n_prefetch_requests; + + do { + PrefetchBuffer(rel, MAIN_FORKNUM, so->prefetch_blocks[j]); + } while (++j < so->last_prefetch_index); + + break; + } + } } /* don't need to keep the stack around... */