Re: A little COPY speedup - Mailing list pgsql-patches

From Heikki Linnakangas
Subject Re: A little COPY speedup
Date
Msg-id 45E75182.8040502@enterprisedb.com
Whole thread Raw
In response to Re: A little COPY speedup  (Heikki Linnakangas <heikki@enterprisedb.com>)
Responses Re: A little COPY speedup
List pgsql-patches
Heikki Linnakangas wrote:
> Tom Lane wrote:
>> I'm not sure whether I like your flag approach better than the
>> last-used-offset one.  The previous patch probably buys some teeny
>> amount more performance, but the flag seems more robust (noting in
>> passing that neither patch attempts to WAL-log its changes, so we really
>> need to treat the values as hints).  And a change as sketched here would
>> leave us 15 free bits for future expansion, which might be nice.
>
> I'll post a patch along those lines.

Here it is.

I'm not fond of the macro names for the flag, but couldn't think of
anything shorter yet descriptive.

--
   Heikki Linnakangas
   EnterpriseDB   http://www.enterprisedb.com
Index: src/backend/access/heap/heapam.c
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/heap/heapam.c,v
retrieving revision 1.228
diff -c -r1.228 heapam.c
*** src/backend/access/heap/heapam.c    9 Feb 2007 03:35:33 -0000    1.228
--- src/backend/access/heap/heapam.c    1 Mar 2007 21:29:14 -0000
***************
*** 3327,3332 ****
--- 3327,3335 ----

      PageRepairFragmentation(page, NULL);

+     /* clear the hint flag since we just freed some line pointers */
+     HeapPageClearNoFreeLinePointers(page);
+
      PageSetLSN(page, lsn);
      PageSetTLI(page, ThisTimeLineID);
      MarkBufferDirty(buffer);
Index: src/backend/access/heap/hio.c
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/access/heap/hio.c,v
retrieving revision 1.65
diff -c -r1.65 hio.c
*** src/backend/access/heap/hio.c    5 Feb 2007 04:22:18 -0000    1.65
--- src/backend/access/heap/hio.c    1 Mar 2007 21:33:14 -0000
***************
*** 33,51 ****
                       HeapTuple tuple)
  {
      Page        pageHeader;
!     OffsetNumber offnum;
      ItemId        itemId;
      Item        item;

-     /* Add the tuple to the page */
      pageHeader = BufferGetPage(buffer);

      offnum = PageAddItem(pageHeader, (Item) tuple->t_data,
!                          tuple->t_len, InvalidOffsetNumber, LP_USED);

      if (offnum == InvalidOffsetNumber)
          elog(PANIC, "failed to add tuple to page");

      /* Update tuple->t_self to the actual position where it was stored */
      ItemPointerSet(&(tuple->t_self), BufferGetBlockNumber(buffer), offnum);

--- 33,65 ----
                       HeapTuple tuple)
  {
      Page        pageHeader;
!     OffsetNumber offnum, maxoff;
      ItemId        itemId;
      Item        item;

      pageHeader = BufferGetPage(buffer);
+     maxoff = PageGetMaxOffsetNumber(pageHeader);
+
+     /* If we know there's no free line pointers, don't waste cycles
+      * searching for one. We'll set the flag to save work for future
+      * inserts when that happens.
+      */
+     if(HeapPageNoFreeLinePointers(pageHeader))
+         offnum = OffsetNumberNext(maxoff);
+     else
+         offnum = InvalidOffsetNumber;
+
+     /* Add the tuple to the page */

      offnum = PageAddItem(pageHeader, (Item) tuple->t_data,
!                          tuple->t_len, offnum, LP_USED);

      if (offnum == InvalidOffsetNumber)
          elog(PANIC, "failed to add tuple to page");

+     if(offnum > maxoff)
+         HeapPageSetNoFreeLinePointers(pageHeader);
+
      /* Update tuple->t_self to the actual position where it was stored */
      ItemPointerSet(&(tuple->t_self), BufferGetBlockNumber(buffer), offnum);

Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.346
diff -c -r1.346 vacuum.c
*** src/backend/commands/vacuum.c    15 Feb 2007 23:23:22 -0000    1.346
--- src/backend/commands/vacuum.c    1 Mar 2007 21:41:20 -0000
***************
*** 2453,2458 ****
--- 2453,2460 ----
              START_CRIT_SECTION();

              uncnt = PageRepairFragmentation(page, unused);
+             if(uncnt > 0)
+                 HeapPageClearNoFreeLinePointers(page);

              MarkBufferDirty(buf);

***************
*** 2920,2925 ****
--- 2922,2929 ----
      }

      uncnt = PageRepairFragmentation(page, unused);
+     if(uncnt > 0)
+         HeapPageClearNoFreeLinePointers(page);

      MarkBufferDirty(buffer);

Index: src/backend/commands/vacuumlazy.c
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/backend/commands/vacuumlazy.c,v
retrieving revision 1.85
diff -c -r1.85 vacuumlazy.c
*** src/backend/commands/vacuumlazy.c    21 Feb 2007 22:47:45 -0000    1.85
--- src/backend/commands/vacuumlazy.c    1 Mar 2007 21:27:15 -0000
***************
*** 605,610 ****
--- 605,612 ----
      }

      uncnt = PageRepairFragmentation(page, unused);
+     if(uncnt > 0)
+         HeapPageClearNoFreeLinePointers(page);

      MarkBufferDirty(buffer);

Index: src/include/access/htup.h
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/access/htup.h,v
retrieving revision 1.92
diff -c -r1.92 htup.h
*** src/include/access/htup.h    27 Feb 2007 23:48:09 -0000    1.92
--- src/include/access/htup.h    1 Mar 2007 22:13:25 -0000
***************
*** 17,22 ****
--- 17,42 ----
  #include "storage/itemptr.h"
  #include "storage/relfilenode.h"

+ /* We use the pd_amprivate field in the page header to store flags.
+  * At the moment, there's just one flag.
+  */
+
+ /* HP_NOFREELINEPOINTERS flag should be set as a hint when there definitely
+  * isn't any free line pointers left on the page. However, absence of the
+  * flag doesn't necessarily mean that there is a free line pointer.
+  */
+ #define HP_NOFREELINEPOINTERS    (1 << 0)
+
+ #define HeapPageNoFreeLinePointers(page) \
+         (((PageHeader)page)->pd_amprivate & HP_NOFREELINEPOINTERS)
+
+ #define HeapPageSetNoFreeLinePointers(page) \
+         (((PageHeader)page)->pd_amprivate |= HP_NOFREELINEPOINTERS)
+
+ #define HeapPageClearNoFreeLinePointers(page) \
+         (((PageHeader)page)->pd_amprivate &= ~HP_NOFREELINEPOINTERS)
+
+
  /*
   * MaxTupleAttributeNumber limits the number of (user) columns in a tuple.
   * The key limit on this value is that the size of the fixed overhead for
Index: src/include/storage/bufpage.h
===================================================================
RCS file: /home/hlinnaka/pgcvsrepository/pgsql/src/include/storage/bufpage.h,v
retrieving revision 1.71
diff -c -r1.71 bufpage.h
*** src/include/storage/bufpage.h    21 Feb 2007 20:02:17 -0000    1.71
--- src/include/storage/bufpage.h    1 Mar 2007 22:14:37 -0000
***************
*** 68,74 ****
   * space"; each AM has an "opaque" structure defined somewhere that is
   * stored as the page trailer.    an access method should always
   * initialize its pages with PageInit and then set its own opaque
!  * fields.
   */

  typedef Pointer Page;
--- 68,76 ----
   * space"; each AM has an "opaque" structure defined somewhere that is
   * stored as the page trailer.    an access method should always
   * initialize its pages with PageInit and then set its own opaque
!  * fields.  In addition to the special space, there's a 16-bit
!  * pd_amprivate field in the page header itself reserved for AM-specific
!  * use.
   */

  typedef Pointer Page;
***************
*** 90,95 ****
--- 92,98 ----
   *
   *        pd_lsn        - identifies xlog record for last change to this page.
   *        pd_tli        - ditto.
+  *        pd_amprivate - reserved for AM-specific use
   *        pd_lower    - offset to start of free space.
   *        pd_upper    - offset to end of free space.
   *        pd_special    - offset to start of special space.
***************
*** 98,105 ****
   * The LSN is used by the buffer manager to enforce the basic rule of WAL:
   * "thou shalt write xlog before data".  A dirty buffer cannot be dumped
   * to disk until xlog has been flushed at least as far as the page's LSN.
!  * We also store the TLI for identification purposes (it is not clear that
!  * this is actually necessary, but it seems like a good idea).
   *
   * The page version number and page size are packed together into a single
   * uint16 field.  This is for historical reasons: before PostgreSQL 7.3,
--- 101,109 ----
   * The LSN is used by the buffer manager to enforce the basic rule of WAL:
   * "thou shalt write xlog before data".  A dirty buffer cannot be dumped
   * to disk until xlog has been flushed at least as far as the page's LSN.
!  * We also store the 16 least significant bits of the TLI for identification
!  * purposes (it is not clear that this is actually necessary, but it seems
!  * like a good idea).
   *
   * The page version number and page size are packed together into a single
   * uint16 field.  This is for historical reasons: before PostgreSQL 7.3,
***************
*** 119,125 ****
      /* XXX LSN is member of *any* block, not only page-organized ones */
      XLogRecPtr    pd_lsn;            /* LSN: next byte after last byte of xlog
                                   * record for last change to this page */
!     TimeLineID    pd_tli;            /* TLI of last change */
      LocationIndex pd_lower;        /* offset to start of free space */
      LocationIndex pd_upper;        /* offset to end of free space */
      LocationIndex pd_special;    /* offset to start of special space */
--- 123,131 ----
      /* XXX LSN is member of *any* block, not only page-organized ones */
      XLogRecPtr    pd_lsn;            /* LSN: next byte after last byte of xlog
                                   * record for last change to this page */
!     uint16        pd_tli;            /* least significant bits of the TLI
!                                  * corresponding the LSN. */
!     uint16        pd_amprivate;    /* am-specific information */
      LocationIndex pd_lower;        /* offset to start of free space */
      LocationIndex pd_upper;        /* offset to end of free space */
      LocationIndex pd_special;    /* offset to start of special space */
***************
*** 304,313 ****
  #define PageSetLSN(page, lsn) \
      (((PageHeader) (page))->pd_lsn = (lsn))

  #define PageGetTLI(page) \
      (((PageHeader) (page))->pd_tli)
  #define PageSetTLI(page, tli) \
!     (((PageHeader) (page))->pd_tli = (tli))

  /* ----------------------------------------------------------------
   *        extern declarations
--- 310,320 ----
  #define PageSetLSN(page, lsn) \
      (((PageHeader) (page))->pd_lsn = (lsn))

+ /* NOTE: only the 16 least significant bits are stored */
  #define PageGetTLI(page) \
      (((PageHeader) (page))->pd_tli)
  #define PageSetTLI(page, tli) \
!     (((PageHeader) (page))->pd_tli = (tli) & 0x0000FFFF)

  /* ----------------------------------------------------------------
   *        extern declarations

pgsql-patches by date:

Previous
From: Heikki Linnakangas
Date:
Subject: Re: A little COPY speedup
Next
From: Tom Lane
Date:
Subject: Re: A little COPY speedup