From ea484faccc2d5de554f9a5c8e8559657b36a619d Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Tue, 3 Jan 2023 15:00:04 -0500 Subject: [PATCH v4 1/6] Add no movement scan helper No movement scan can be handled first in heapgettup() and heapgettup_pagemode(). Refactor this case into its own helper function to improve readability. --- src/backend/access/heap/heapam.c | 118 +++++++++++++++---------------- 1 file changed, 56 insertions(+), 62 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index bad2a89e4f..36f14a0a9e 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -483,6 +483,46 @@ heapgetpage(TableScanDesc sscan, BlockNumber block) scan->rs_ntuples = ntup; } +/* + * ``no movement'' scan direction: refetch prior tuple + */ +static pg_noinline void +heapgettup_no_movement(HeapScanDesc scan) +{ + ItemId lpp; + OffsetNumber lineoff; + BlockNumber page; + Page dp; + HeapTuple tuple = &(scan->rs_ctup); + + /* The scan must be init'd for there to be a current tuple (rs_ctup) */ + Assert(scan->rs_inited); + + /* Since the tuple was previously fetched, needn't lock page here */ + page = ItemPointerGetBlockNumber(&(tuple->t_self)); + if (page != scan->rs_cblock) + heapgetpage((TableScanDesc) scan, page); + + /* Since the tuple was previously fetched, needn't lock page here */ + dp = BufferGetPage(scan->rs_cbuf); + TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, dp); + lineoff = scan->rs_cindex; + lpp = PageGetItemId(dp, lineoff); + Assert(ItemIdIsNormal(lpp)); + + tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp); + tuple->t_len = ItemIdGetLength(lpp); + + /* check that rs_cindex is in sync if in pagemode */ + Assert(!(scan->rs_base.rs_flags & SO_ALLOW_PAGEMODE) || + (scan->rs_cindex < scan->rs_ntuples)); + + Assert(!(scan->rs_base.rs_flags & SO_ALLOW_PAGEMODE) || + (lineoff == scan->rs_vistuples[scan->rs_cindex])); + + return; +} + /* ---------------- * heapgettup - fetch next heap tuple * @@ -523,6 +563,12 @@ heapgettup(HeapScanDesc scan, int linesleft; ItemId lpp; + if (unlikely(ScanDirectionIsNoMovement(dir))) + { + heapgettup_no_movement(scan); + return; + } + /* * calculate next starting lineoff, given scan direction */ @@ -583,8 +629,9 @@ heapgettup(HeapScanDesc scan, linesleft = lines - lineoff + 1; } - else if (backward) + else { + Assert(backward); /* backward parallel scan not supported */ Assert(scan->rs_base.rs_parallel == NULL); @@ -653,34 +700,6 @@ heapgettup(HeapScanDesc scan, linesleft = lineoff; } - else - { - /* - * ``no movement'' scan direction: refetch prior tuple - */ - if (!scan->rs_inited) - { - Assert(!BufferIsValid(scan->rs_cbuf)); - tuple->t_data = NULL; - return; - } - - block = ItemPointerGetBlockNumber(&(tuple->t_self)); - if (block != scan->rs_cblock) - heapgetpage((TableScanDesc) scan, block); - - /* Since the tuple was previously fetched, needn't lock page here */ - page = BufferGetPage(scan->rs_cbuf); - TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page); - lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self)); - lpp = PageGetItemId(page, lineoff); - Assert(ItemIdIsNormal(lpp)); - - tuple->t_data = (HeapTupleHeader) PageGetItem(page, lpp); - tuple->t_len = ItemIdGetLength(lpp); - - return; - } /* * advance the scan until we find a qualifying tuple or run out of stuff @@ -861,6 +880,12 @@ heapgettup_pagemode(HeapScanDesc scan, int linesleft; ItemId lpp; + if (unlikely(ScanDirectionIsNoMovement(dir))) + { + heapgettup_no_movement(scan); + return; + } + /* * calculate next starting lineindex, given scan direction */ @@ -918,8 +943,9 @@ heapgettup_pagemode(HeapScanDesc scan, linesleft = lines - lineindex; } - else if (backward) + else { + Assert(backward); /* backward parallel scan not supported */ Assert(scan->rs_base.rs_parallel == NULL); @@ -978,38 +1004,6 @@ heapgettup_pagemode(HeapScanDesc scan, linesleft = lineindex + 1; } - else - { - /* - * ``no movement'' scan direction: refetch prior tuple - */ - if (!scan->rs_inited) - { - Assert(!BufferIsValid(scan->rs_cbuf)); - tuple->t_data = NULL; - return; - } - - block = ItemPointerGetBlockNumber(&(tuple->t_self)); - if (block != scan->rs_cblock) - heapgetpage((TableScanDesc) scan, block); - - /* Since the tuple was previously fetched, needn't lock page here */ - page = BufferGetPage(scan->rs_cbuf); - TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page); - lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self)); - lpp = PageGetItemId(page, lineoff); - Assert(ItemIdIsNormal(lpp)); - - tuple->t_data = (HeapTupleHeader) PageGetItem(page, lpp); - tuple->t_len = ItemIdGetLength(lpp); - - /* check that rs_cindex is in sync */ - Assert(scan->rs_cindex < scan->rs_ntuples); - Assert(lineoff == scan->rs_vistuples[scan->rs_cindex]); - - return; - } /* * advance the scan until we find a qualifying tuple or run out of stuff -- 2.38.1