Further refactor of heapgettup and heapgettup_pagemode
authorDavid Rowley <drowley@postgresql.org>
Thu, 2 Feb 2023 22:48:39 +0000 (11:48 +1300)
committerDavid Rowley <drowley@postgresql.org>
Thu, 2 Feb 2023 22:48:39 +0000 (11:48 +1300)
Backward and forward scans share much of the same page acquisition code.
Here we consolidate that code to reduce some duplication.

Additionally, add a new rs_coffset field to HeapScanDescData to track the
offset of the current tuple.  The new field fits nicely into the padding
between a bool and BlockNumber field and saves having to look at the last
returned tuple to figure out which offset we should be looking at for the
current tuple.

Author: Melanie Plageman
Reviewed-by: David Rowley
Discussion: https://postgr.es/m/CAAKRu_bvkhka0CZQun28KTqhuUh5ZqY=_T8QEqZqOL02rpi2bw@mail.gmail.com

src/backend/access/heap/heapam.c
src/include/access/heapam.h

index b34e20a71ff0e69b075e7f9e2b1ea6c2a3ad52bd..ec6b7962c50f848c2aac41495d1a3ff482fc7db0 100644 (file)
@@ -576,101 +576,67 @@ heapgettup(HeapScanDesc scan,
        BlockNumber block;
        bool            finished;
        Page            page;
-       int                     lines;
        OffsetNumber lineoff;
        int                     linesleft;
        ItemId          lpp;
 
-       /*
-        * calculate next starting lineoff, given scan direction
-        */
-       if (ScanDirectionIsForward(dir))
+       if (unlikely(!scan->rs_inited))
        {
-               if (!scan->rs_inited)
-               {
-                       block = heapgettup_initial_block(scan, dir);
+               block = heapgettup_initial_block(scan, dir);
 
-                       /*
-                        * Check if we have reached the end of the scan already. This
-                        * could happen if the table is empty or if the parallel workers
-                        * have already finished the scan before we did anything ourselves
-                        */
-                       if (block == InvalidBlockNumber)
-                       {
-                               Assert(!BufferIsValid(scan->rs_cbuf));
-                               tuple->t_data = NULL;
-                               return;
-                       }
-                       heapgetpage((TableScanDesc) scan, block);
-                       lineoff = FirstOffsetNumber;    /* first offnum */
-                       scan->rs_inited = true;
-               }
-               else
+               /*
+                * Check if we have reached the end of the scan already. This could
+                * happen if the table is empty or if the parallel workers have
+                * already finished the scan before we did anything ourselves
+                */
+               if (block == InvalidBlockNumber)
                {
-                       /* continue from previously returned page/tuple */
-                       block = scan->rs_cblock;        /* current page */
-                       lineoff =                       /* next offnum */
-                               OffsetNumberNext(ItemPointerGetOffsetNumber(&(tuple->t_self)));
+                       Assert(!BufferIsValid(scan->rs_cbuf));
+                       tuple->t_data = NULL;
+                       return;
                }
 
-               LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
+               heapgetpage((TableScanDesc) scan, block);
 
+               LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
                page = BufferGetPage(scan->rs_cbuf);
                TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page);
-               lines = PageGetMaxOffsetNumber(page);
-               /* block and lineoff now reference the physically next tid */
 
-               linesleft = lines - lineoff + 1;
+               linesleft = PageGetMaxOffsetNumber(page) - FirstOffsetNumber + 1;
+
+               if (ScanDirectionIsForward(dir))
+                       lineoff = FirstOffsetNumber;    /* first offnum */
+               else
+                       lineoff = (OffsetNumber) linesleft;
+
+               scan->rs_inited = true;
        }
        else
        {
-               if (!scan->rs_inited)
-               {
-                       block = heapgettup_initial_block(scan, dir);
-
-                       /*
-                        * Check if we have reached the end of the scan already. This
-                        * could happen if the table is empty.
-                        */
-                       if (block == InvalidBlockNumber)
-                       {
-                               Assert(!BufferIsValid(scan->rs_cbuf));
-                               tuple->t_data = NULL;
-                               return;
-                       }
+               /* continue from previously returned page/tuple */
+               block = scan->rs_cblock;
 
-                       heapgetpage((TableScanDesc) scan, block);
-                       LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
+               LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
+               page = BufferGetPage(scan->rs_cbuf);
+               TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page);
 
-                       page = BufferGetPage(scan->rs_cbuf);
-                       TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page);
-                       lines = PageGetMaxOffsetNumber(page);
-                       lineoff = lines;        /* final offnum */
-                       scan->rs_inited = true;
+               if (ScanDirectionIsForward(dir))
+               {
+                       lineoff = OffsetNumberNext(scan->rs_coffset);
+                       linesleft = PageGetMaxOffsetNumber(page) - lineoff + 1;
                }
                else
                {
-                       /* continue from previously returned page/tuple */
-                       block = scan->rs_cblock;        /* current page */
-                       LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
-
-                       page = BufferGetPage(scan->rs_cbuf);
-                       TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page);
-                       lines = PageGetMaxOffsetNumber(page);
-
                        /*
                         * The previous returned tuple may have been vacuumed since the
                         * previous scan when we use a non-MVCC snapshot, so we must
                         * re-establish the lineoff <= PageGetMaxOffsetNumber(page)
                         * invariant
                         */
-                       lineoff =                       /* previous offnum */
-                               Min(lines,
-                                       OffsetNumberPrev(ItemPointerGetOffsetNumber(&(tuple->t_self))));
+                       lineoff = Min(PageGetMaxOffsetNumber(page),
+                                                 OffsetNumberPrev(scan->rs_coffset));
+                       linesleft = lineoff;
                }
-               /* block and lineoff now reference the physically previous tid */
-
-               linesleft = lineoff;
        }
 
        /*
@@ -715,6 +681,7 @@ heapgettup(HeapScanDesc scan,
                                if (valid)
                                {
                                        LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
+                                       scan->rs_coffset = lineoff;
                                        return;
                                }
                        }
@@ -807,12 +774,11 @@ heapgettup(HeapScanDesc scan,
 
                page = BufferGetPage(scan->rs_cbuf);
                TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page);
-               lines = PageGetMaxOffsetNumber(page);
-               linesleft = lines;
+               linesleft = PageGetMaxOffsetNumber(page);
                if (backward)
                {
-                       lineoff = lines;
-                       lpp = PageGetItemId(page, lines);
+                       lineoff = linesleft;
+                       lpp = PageGetItemId(page, linesleft);
                }
                else
                {
@@ -846,87 +812,46 @@ heapgettup_pagemode(HeapScanDesc scan,
        BlockNumber block;
        bool            finished;
        Page            page;
-       int                     lines;
        int                     lineindex;
        OffsetNumber lineoff;
        int                     linesleft;
        ItemId          lpp;
 
-       /*
-        * calculate next starting lineindex, given scan direction
-        */
-       if (ScanDirectionIsForward(dir))
+       if (unlikely(!scan->rs_inited))
        {
-               if (!scan->rs_inited)
-               {
-                       block = heapgettup_initial_block(scan, dir);
+               block = heapgettup_initial_block(scan, dir);
 
-                       /*
-                        * Check if we have reached the end of the scan already. This
-                        * could happen if the table is empty or if the parallel workers
-                        * have already finished the scan before we did anything ourselves
-                        */
-                       if (block == InvalidBlockNumber)
-                       {
-                               Assert(!BufferIsValid(scan->rs_cbuf));
-                               tuple->t_data = NULL;
-                               return;
-                       }
-                       heapgetpage((TableScanDesc) scan, block);
-                       lineindex = 0;
-                       scan->rs_inited = true;
-               }
-               else
+               /*
+                * Check if we have reached the end of the scan already. This could
+                * happen if the table is empty or if the other workers in a parallel
+                * scan have already finished the scan.
+                */
+               if (block == InvalidBlockNumber)
                {
-                       /* continue from previously returned page/tuple */
-                       block = scan->rs_cblock;        /* current page */
-                       lineindex = scan->rs_cindex + 1;
+                       Assert(!BufferIsValid(scan->rs_cbuf));
+                       tuple->t_data = NULL;
+                       return;
                }
 
+               heapgetpage((TableScanDesc) scan, block);
                page = BufferGetPage(scan->rs_cbuf);
                TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
-               lines = scan->rs_ntuples;
-               /* block and lineindex now reference the next visible tid */
-
-               linesleft = lines - lineindex;
+               linesleft = scan->rs_ntuples;
+               lineindex = ScanDirectionIsForward(dir) ? 0 : linesleft - 1;
+               scan->rs_inited = true;
        }
        else
        {
-               if (!scan->rs_inited)
-               {
-                       block = heapgettup_initial_block(scan, dir);
-
-                       /*
-                        * Check if we have reached the end of the scan already. This
-                        * could happen if the table is empty.
-                        */
-                       if (block == InvalidBlockNumber)
-                       {
-                               Assert(!BufferIsValid(scan->rs_cbuf));
-                               tuple->t_data = NULL;
-                               return;
-                       }
+               /* continue from previously returned page/tuple */
+               block = scan->rs_cblock;        /* current page */
+               page = BufferGetPage(scan->rs_cbuf);
+               TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
 
-                       heapgetpage((TableScanDesc) scan, block);
-                       page = BufferGetPage(scan->rs_cbuf);
-                       TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
-                       lines = scan->rs_ntuples;
-                       lineindex = lines - 1;
-                       scan->rs_inited = true;
-               }
+               lineindex = scan->rs_cindex + dir;
+               if (ScanDirectionIsForward(dir))
+                       linesleft = scan->rs_ntuples - lineindex;
                else
-               {
-                       /* continue from previously returned page/tuple */
-                       block = scan->rs_cblock;        /* current page */
-
-                       page = BufferGetPage(scan->rs_cbuf);
-                       TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
-                       lines = scan->rs_ntuples;
-                       lineindex = scan->rs_cindex - 1;
-               }
-               /* block and lineindex now reference the previous visible tid */
-
-               linesleft = lineindex + 1;
+                       linesleft = scan->rs_cindex;
        }
 
        /*
@@ -1041,10 +966,9 @@ heapgettup_pagemode(HeapScanDesc scan,
 
                page = BufferGetPage(scan->rs_cbuf);
                TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
-               lines = scan->rs_ntuples;
-               linesleft = lines;
+               linesleft = scan->rs_ntuples;
                if (backward)
-                       lineindex = lines - 1;
+                       lineindex = linesleft - 1;
                else
                        lineindex = 0;
        }
index 417108f1e01c7d4bd407e7d4b3547399de1f71c4..8d28bc93ef4bfc755cead35593f9e73451733b9d 100644 (file)
@@ -57,6 +57,7 @@ typedef struct HeapScanDescData
 
        /* scan current state */
        bool            rs_inited;              /* false = scan not init'd yet */
+       OffsetNumber rs_coffset;        /* current offset # in non-page-at-a-time mode */
        BlockNumber rs_cblock;          /* current block # in scan, if any */
        Buffer          rs_cbuf;                /* current buffer in scan, if any */
        /* NB: if rs_cbuf is not InvalidBuffer, we hold a pin on that buffer */