Some marginal additional hacking to shave a few more cycles off
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 26 Nov 2005 05:03:06 +0000 (05:03 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 26 Nov 2005 05:03:06 +0000 (05:03 +0000)
heapgettup.

src/backend/access/heap/heapam.c

index 0b750e72a7d53408b95a4cf5728f6ac720b65892..eeacff56c9d82a0d09eb7d953cea0d64f378a8c8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.204 2005/11/26 03:03:07 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.205 2005/11/26 05:03:06 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -194,9 +194,7 @@ heapgettup(HeapScanDesc scan,
                   ScanKey key)
 {
        HeapTuple       tuple = &(scan->rs_ctup);
-       ItemPointer tid = &(tuple->t_self);
        Snapshot        snapshot = scan->rs_snapshot;
-       BlockNumber     pages = scan->rs_nblocks;
        BlockNumber page;
        Page            dp;
        int                     lines;
@@ -204,52 +202,45 @@ heapgettup(HeapScanDesc scan,
        int                     linesleft;
        ItemId          lpp;
 
-       if (!scan->rs_inited)
-       {
-               /*
-                * return null immediately if relation is empty
-                */
-               if (pages == 0)
-               {
-                       Assert(!BufferIsValid(scan->rs_cbuf));
-                       tuple->t_data = NULL;
-                       return;
-               }
-       }
-       else
-       {
-               /* resuming scan from tuple indicated by scan->rs_ctup.t_self */
-               Assert(ItemPointerIsValid(tid));
-       }
-
        /*
         * calculate next starting lineoff, given scan direction
         */
-       if (dir == 0)
+       if (dir > 0)
        {
                /*
-                * ``no movement'' scan direction: refetch prior tuple
+                * forward scan direction
                 */
                if (!scan->rs_inited)
                {
-                       Assert(!BufferIsValid(scan->rs_cbuf));
-                       tuple->t_data = NULL;
-                       return;
+                       /*
+                        * return null immediately if relation is empty
+                        */
+                       if (scan->rs_nblocks == 0)
+                       {
+                               Assert(!BufferIsValid(scan->rs_cbuf));
+                               tuple->t_data = NULL;
+                               return;
+                       }
+                       page = 0;                                                       /* first page */
+                       heapgetpage(scan, page);
+                       lineoff = FirstOffsetNumber;            /* first offnum */
+                       scan->rs_inited = true;
+               }
+               else
+               {
+                       /* continue from previously returned page/tuple */
+                       page = scan->rs_cblock;                         /* current page */
+                       lineoff =                                                       /* next offnum */
+                               OffsetNumberNext(ItemPointerGetOffsetNumber(&(tuple->t_self)));
                }
 
-               page = ItemPointerGetBlockNumber(tid);
-               if (page != scan->rs_cblock)
-                       heapgetpage(scan, page);
+               LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
 
-               /* Since the tuple was previously fetched, needn't lock page here */
                dp = (Page) BufferGetPage(scan->rs_cbuf);
-               lineoff = ItemPointerGetOffsetNumber(tid);
-               lpp = PageGetItemId(dp, lineoff);
-
-               tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
-               tuple->t_len = ItemIdGetLength(lpp);
+               lines = PageGetMaxOffsetNumber(dp);
+               /* page and lineoff now reference the physically next tid */
 
-               return;
+               linesleft = lines - lineoff + 1;
        }
        else if (dir < 0)
        {
@@ -257,12 +248,24 @@ heapgettup(HeapScanDesc scan,
                 * reverse scan direction
                 */
                if (!scan->rs_inited)
-                       page = pages - 1;       /* final page */
-               else
-                       page = ItemPointerGetBlockNumber(tid);          /* current page */
-
-               if (page != scan->rs_cblock)
+               {
+                       /*
+                        * return null immediately if relation is empty
+                        */
+                       if (scan->rs_nblocks == 0)
+                       {
+                               Assert(!BufferIsValid(scan->rs_cbuf));
+                               tuple->t_data = NULL;
+                               return;
+                       }
+                       page = scan->rs_nblocks - 1;            /* final page */
                        heapgetpage(scan, page);
+               }
+               else
+               {
+                       /* continue from previously returned page/tuple */
+                       page = scan->rs_cblock;                         /* current page */
+               }
 
                LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
 
@@ -271,53 +274,44 @@ heapgettup(HeapScanDesc scan,
 
                if (!scan->rs_inited)
                {
-                       lineoff = lines;        /* final offnum */
+                       lineoff = lines;                                        /* final offnum */
                        scan->rs_inited = true;
                }
                else
                {
-                       lineoff =                       /* previous offnum */
-                               OffsetNumberPrev(ItemPointerGetOffsetNumber(tid));
+                       lineoff =                                                       /* previous offnum */
+                               OffsetNumberPrev(ItemPointerGetOffsetNumber(&(tuple->t_self)));
                }
                /* page and lineoff now reference the physically previous tid */
+
+               linesleft = lineoff;
        }
        else
        {
                /*
-                * forward scan direction
+                * ``no movement'' scan direction: refetch prior tuple
                 */
                if (!scan->rs_inited)
                {
-                       page = 0;                       /* first page */
-                       lineoff = FirstOffsetNumber;            /* first offnum */
-                       scan->rs_inited = true;
-               }
-               else
-               {
-                       page = ItemPointerGetBlockNumber(tid);          /* current page */
-                       lineoff =                       /* next offnum */
-                               OffsetNumberNext(ItemPointerGetOffsetNumber(tid));
+                       Assert(!BufferIsValid(scan->rs_cbuf));
+                       tuple->t_data = NULL;
+                       return;
                }
 
+               page = ItemPointerGetBlockNumber(&(tuple->t_self));
                if (page != scan->rs_cblock)
                        heapgetpage(scan, page);
 
-               LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
-
+               /* Since the tuple was previously fetched, needn't lock page here */
                dp = (Page) BufferGetPage(scan->rs_cbuf);
-               lines = PageGetMaxOffsetNumber(dp);
-               /* page and lineoff now reference the physically next tid */
-       }
+               lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));
+               lpp = PageGetItemId(dp, lineoff);
 
-       /* 'dir' is now non-zero */
+               tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
+               tuple->t_len = ItemIdGetLength(lpp);
 
-       /*
-        * calculate number of remaining items to check on this page
-        */
-       if (dir < 0)
-               linesleft = lineoff;
-       else
-               linesleft = lines - lineoff + 1;
+               return;
+       }
 
        /*
         * advance the scan until we find a qualifying tuple or run out of stuff
@@ -379,7 +373,7 @@ heapgettup(HeapScanDesc scan,
                /*
                 * return NULL if we've exhausted all the pages
                 */
-               if ((dir < 0) ? (page == 0) : (page + 1 >= pages))
+               if ((dir < 0) ? (page == 0) : (page + 1 >= scan->rs_nblocks))
                {
                        if (BufferIsValid(scan->rs_cbuf))
                                ReleaseBuffer(scan->rs_cbuf);
@@ -432,8 +426,6 @@ heapgettup_pagemode(HeapScanDesc scan,
                                        ScanKey key)
 {
        HeapTuple       tuple = &(scan->rs_ctup);
-       ItemPointer tid = &(tuple->t_self);
-       BlockNumber     pages = scan->rs_nblocks;
        BlockNumber page;
        Page            dp;
        int                     lines;
@@ -442,56 +434,42 @@ heapgettup_pagemode(HeapScanDesc scan,
        int                     linesleft;
        ItemId          lpp;
 
-       if (!scan->rs_inited)
-       {
-               /*
-                * return null immediately if relation is empty
-                */
-               if (pages == 0)
-               {
-                       Assert(!BufferIsValid(scan->rs_cbuf));
-                       tuple->t_data = NULL;
-                       return;
-               }
-       }
-       else
-       {
-               /* resuming scan from tuple indicated by scan->rs_ctup.t_self */
-               Assert(ItemPointerIsValid(tid));
-       }
-
        /*
         * calculate next starting lineindex, given scan direction
         */
-       if (dir == 0)
+       if (dir > 0)
        {
                /*
-                * ``no movement'' scan direction: refetch prior tuple
+                * forward scan direction
                 */
                if (!scan->rs_inited)
                {
-                       Assert(!BufferIsValid(scan->rs_cbuf));
-                       tuple->t_data = NULL;
-                       return;
-               }
-
-               page = ItemPointerGetBlockNumber(tid);
-               if (page != scan->rs_cblock)
+                       /*
+                        * return null immediately if relation is empty
+                        */
+                       if (scan->rs_nblocks == 0)
+                       {
+                               Assert(!BufferIsValid(scan->rs_cbuf));
+                               tuple->t_data = NULL;
+                               return;
+                       }
+                       page = 0;                                                       /* first page */
                        heapgetpage(scan, page);
+                       lineindex = 0;
+                       scan->rs_inited = true;
+               }
+               else
+               {
+                       /* continue from previously returned page/tuple */
+                       page = scan->rs_cblock;                         /* current page */
+                       lineindex = scan->rs_cindex + 1;
+               }
 
-               /* Since the tuple was previously fetched, needn't lock page here */
                dp = (Page) BufferGetPage(scan->rs_cbuf);
-               lineoff = ItemPointerGetOffsetNumber(tid);
-               lpp = PageGetItemId(dp, lineoff);
-
-               tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, 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]);
+               lines = scan->rs_ntuples;
+               /* page and lineindex now reference the next visible tid */
 
-               return;
+               linesleft = lines - lineindex;
        }
        else if (dir < 0)
        {
@@ -499,12 +477,24 @@ heapgettup_pagemode(HeapScanDesc scan,
                 * reverse scan direction
                 */
                if (!scan->rs_inited)
-                       page = pages - 1;       /* final page */
-               else
-                       page = ItemPointerGetBlockNumber(tid);          /* current page */
-
-               if (page != scan->rs_cblock)
+               {
+                       /*
+                        * return null immediately if relation is empty
+                        */
+                       if (scan->rs_nblocks == 0)
+                       {
+                               Assert(!BufferIsValid(scan->rs_cbuf));
+                               tuple->t_data = NULL;
+                               return;
+                       }
+                       page = scan->rs_nblocks - 1;            /* final page */
                        heapgetpage(scan, page);
+               }
+               else
+               {
+                       /* continue from previously returned page/tuple */
+                       page = scan->rs_cblock;                         /* current page */
+               }
 
                dp = (Page) BufferGetPage(scan->rs_cbuf);
                lines = scan->rs_ntuples;
@@ -519,41 +509,39 @@ heapgettup_pagemode(HeapScanDesc scan,
                        lineindex = scan->rs_cindex - 1;
                }
                /* page and lineindex now reference the previous visible tid */
+
+               linesleft = lineindex + 1;
        }
        else
        {
                /*
-                * forward scan direction
+                * ``no movement'' scan direction: refetch prior tuple
                 */
                if (!scan->rs_inited)
                {
-                       page = 0;                       /* first page */
-                       lineindex = 0;
-                       scan->rs_inited = true;
-               }
-               else
-               {
-                       page = ItemPointerGetBlockNumber(tid);          /* current page */
-                       lineindex = scan->rs_cindex + 1;
+                       Assert(!BufferIsValid(scan->rs_cbuf));
+                       tuple->t_data = NULL;
+                       return;
                }
 
+               page = ItemPointerGetBlockNumber(&(tuple->t_self));
                if (page != scan->rs_cblock)
                        heapgetpage(scan, page);
 
+               /* Since the tuple was previously fetched, needn't lock page here */
                dp = (Page) BufferGetPage(scan->rs_cbuf);
-               lines = scan->rs_ntuples;
-               /* page and lineindex now reference the next visible tid */
-       }
+               lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));
+               lpp = PageGetItemId(dp, lineoff);
 
-       /* 'dir' is now non-zero */
+               tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
+               tuple->t_len = ItemIdGetLength(lpp);
 
-       /*
-        * calculate number of remaining items to check on this page
-        */
-       if (dir < 0)
-               linesleft = lineindex + 1;
-       else
-               linesleft = lines - lineindex;
+               /* 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
@@ -614,7 +602,7 @@ heapgettup_pagemode(HeapScanDesc scan,
                /*
                 * return NULL if we've exhausted all the pages
                 */
-               if ((dir < 0) ? (page == 0) : (page + 1 >= pages))
+               if ((dir < 0) ? (page == 0) : (page + 1 >= scan->rs_nblocks))
                {
                        if (BufferIsValid(scan->rs_cbuf))
                                ReleaseBuffer(scan->rs_cbuf);
@@ -2743,6 +2731,7 @@ heap_restrpos(HeapScanDesc scan)
                        ReleaseBuffer(scan->rs_cbuf);
                scan->rs_cbuf = InvalidBuffer;
                scan->rs_cblock = InvalidBlockNumber;
+               scan->rs_inited = false;
        }
        else
        {