]> granicus.if.org Git - postgresql/commitdiff
Suppress useless searches for unused line pointers in PageAddItem. To do
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 2 Mar 2007 00:48:44 +0000 (00:48 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 2 Mar 2007 00:48:44 +0000 (00:48 +0000)
this, add a 16-bit "flags" field to page headers by stealing some bits from
pd_tli.  We use one flag bit as a hint to indicate whether there are any
unused line pointers; the remaining 15 are available for future use.

This is a cut-down form of an idea proposed by Hiroki Kataoka in July 2005.
At the time it was rejected because the original patch increased the size of
page headers and it wasn't clear that the benefit outweighed the distributed
cost.  The flag-bit approach gets most of the benefit without requiring an
increase in the page header size.

Heikki Linnakangas and Tom Lane

doc/src/sgml/storage.sgml
src/backend/storage/page/bufpage.c
src/include/catalog/catversion.h
src/include/storage/bufpage.h

index c20b2ebfe1bc6081ef4c0d549a5f33ba99ea1ffc..8a2e7929e621edfcc8d854c29cce8b834d47e0e5 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/storage.sgml,v 1.14 2007/01/31 20:56:19 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/storage.sgml,v 1.15 2007/03/02 00:48:44 tgl Exp $ -->
 
 <chapter id="storage">
 
@@ -427,8 +427,8 @@ data. Empty in ordinary tables.</entry>
   The first 20 bytes of each page consists of a page header
   (PageHeaderData). Its format is detailed in <xref
   linkend="pageheaderdata-table">. The first two fields track the most
-  recent WAL entry related to this page. They are followed by three 2-byte
-  integer fields
+  recent WAL entry related to this page. Next is a 2-byte field
+  containing flag bits. This is followed by three 2-byte integer fields
   (<structfield>pd_lower</structfield>, <structfield>pd_upper</structfield>,
   and <structfield>pd_special</structfield>). These contain byte offsets
   from the page start to the start
@@ -437,12 +437,13 @@ data. Empty in ordinary tables.</entry>
   The last 2 bytes of the page header,
   <structfield>pd_pagesize_version</structfield>, store both the page size
   and a version indicator.  Beginning with
-  <productname>PostgreSQL</productname> 8.1 the version number is 3;
+  <productname>PostgreSQL</productname> 8.3 the version number is 4;
+  <productname>PostgreSQL</productname> 8.1 and 8.2 used version number 3;
   <productname>PostgreSQL</productname> 8.0 used version number 2;
   <productname>PostgreSQL</productname> 7.3 and 7.4 used version number 1;
   prior releases used version number 0.
-  (The basic page layout and header format has not changed in these versions,
-  but the layout of heap row headers has.)  The page size
+  (The basic page layout and header format has not changed in most of these
+  versions, but the layout of heap row headers has.)  The page size
   is basically only present as a cross-check; there is no support for having
   more than one page size in an installation.
   
@@ -470,9 +471,15 @@ data. Empty in ordinary tables.</entry>
   </row>
   <row>
    <entry>pd_tli</entry>
-   <entry>TimeLineID</entry>
-   <entry>4 bytes</entry>
-   <entry>TLI of last change</entry>
+   <entry>uint16</entry>
+   <entry>2 bytes</entry>
+   <entry>TimeLineID of last change (only its lowest 16 bits)</entry>
+  </row>
+  <row>
+   <entry>pd_flags</entry>
+   <entry>uint16</entry>
+   <entry>2 bytes</entry>
+   <entry>Flag bits</entry>
   </row>
   <row>
    <entry>pd_lower</entry>
index 8299f550d6e02303db13c289565832367003758e..b246b0afeb87bc2a053723c7e8e0fe8a68356411 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/storage/page/bufpage.c,v 1.71 2007/02/21 20:02:17 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/storage/page/bufpage.c,v 1.72 2007/03/02 00:48:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,6 +39,7 @@ PageInit(Page page, Size pageSize, Size specialSize)
        /* Make sure all fields of page are zero, as well as unused space */
        MemSet(p, 0, pageSize);
 
+       /* p->pd_flags = 0;                                     done by above MemSet */
        p->pd_lower = SizeOfPageHeaderData;
        p->pd_upper = pageSize - specialSize;
        p->pd_special = pageSize - specialSize;
@@ -73,6 +74,7 @@ PageHeaderIsValid(PageHeader page)
        /* Check normal case */
        if (PageGetPageSize(page) == BLCKSZ &&
                PageGetPageLayoutVersion(page) == PG_PAGE_LAYOUT_VERSION &&
+               (page->pd_flags & ~PD_VALID_FLAG_BITS) == 0 &&
                page->pd_lower >= SizeOfPageHeaderData &&
                page->pd_lower <= page->pd_upper &&
                page->pd_upper <= page->pd_special &&
@@ -165,14 +167,27 @@ PageAddItem(Page page,
        else
        {
                /* offsetNumber was not passed in, so find a free slot */
-               /* look for "recyclable" (unused & deallocated) ItemId */
-               for (offsetNumber = 1; offsetNumber < limit; offsetNumber++)
+               /* if no free slot, we'll put it at limit (1st open slot) */
+               if (PageHasFreeLinePointers(phdr))
+               {
+                       /* look for "recyclable" (unused & deallocated) ItemId */
+                       for (offsetNumber = 1; offsetNumber < limit; offsetNumber++)
+                       {
+                               itemId = PageGetItemId(phdr, offsetNumber);
+                               if (!ItemIdIsUsed(itemId) && ItemIdGetLength(itemId) == 0)
+                                       break;
+                       }
+                       if (offsetNumber >= limit)
+                       {
+                               /* the hint is wrong, so reset it */
+                               PageClearHasFreeLinePointers(phdr);
+                       }
+               }
+               else
                {
-                       itemId = PageGetItemId(phdr, offsetNumber);
-                       if (!ItemIdIsUsed(itemId) && ItemIdGetLength(itemId) == 0)
-                               break;
+                       /* don't bother searching if hint says there's no free slot */
+                       offsetNumber = limit;
                }
-               /* if no free slot, we'll put it at limit (1st open slot) */
        }
 
        if (offsetNumber > limit)
@@ -413,13 +428,19 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
                pfree(itemidbase);
        }
 
+       /* Set hint bit for PageAddItem */
+       if (nused < nline)
+               PageSetHasFreeLinePointers(page);
+       else
+               PageClearHasFreeLinePointers(page);
+
        return (nline - nused);
 }
 
 /*
  * PageGetFreeSpace
  *             Returns the size of the free (allocatable) space on a page,
- *             deducted by the space needed for a new line pointer.
+ *             reduced by the space needed for a new line pointer.
  */
 Size
 PageGetFreeSpace(Page page)
index 8c53a2df2ac7be441278ef63288094beb31cdacc..51263557f9ef73b9ecafbab03b990604e7a812e9 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.388 2007/02/20 17:32:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.389 2007/03/02 00:48:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200702202
+#define CATALOG_VERSION_NO     200703011
 
 #endif
index 44ab48c9b8f6d8daf33630067febcb3bf246c6bd..d38544e3f0570b51310a95219db95a9ee0cc1e73 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/bufpage.h,v 1.71 2007/02/21 20:02:17 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/bufpage.h,v 1.72 2007/03/02 00:48:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -90,6 +90,7 @@ typedef uint16 LocationIndex;
  *
  *             pd_lsn          - identifies xlog record for last change to this page.
  *             pd_tli          - ditto.
+ *             pd_flags        - flag bits.
  *             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,8 +99,9 @@ typedef uint16 LocationIndex;
  * 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).
+ * 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,7 +121,9 @@ typedef struct PageHeaderData
        /* 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 */
+       uint16          pd_tli;                 /* least significant bits of the TimeLineID
+                                                                * containing the LSN */
+       uint16          pd_flags;               /* flag bits, see below */
        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 */
@@ -129,12 +133,25 @@ typedef struct PageHeaderData
 
 typedef PageHeaderData *PageHeader;
 
+/*
+ * pd_flags contains the following flag bits.  Undefined bits are initialized
+ * to zero and may be used in the future.
+ *
+ * PD_HAS_FREE_LINES is set if there are any not-LP_USED line pointers before
+ * pd_lower.  This should be considered a hint rather than the truth, since
+ * changes to it are not WAL-logged.
+ */
+#define PD_HAS_FREE_LINES      0x0001  /* are there any unused line pointers? */
+
+#define PD_VALID_FLAG_BITS     0x0001  /* OR of all valid pd_flags bits */
+
 /*
  * Page layout version number 0 is for pre-7.3 Postgres releases.
  * Releases 7.3 and 7.4 use 1, denoting a new HeapTupleHeader layout.
  * Release 8.0 uses 2; it changed the HeapTupleHeader layout again.
  * Release 8.1 uses 3; it redefined HeapTupleHeader infomask bits.
- * Release 8.3 uses 4; it changed the HeapTupleHeader layout again.
+ * Release 8.3 uses 4; it changed the HeapTupleHeader layout again, and
+ * added the pd_flags field (by stealing some bits from pd_tli).
  */
 #define PG_PAGE_LAYOUT_VERSION         4
 
@@ -299,15 +316,27 @@ typedef PageHeaderData *PageHeader;
         ((((PageHeader) (page))->pd_lower - SizeOfPageHeaderData) \
          / sizeof(ItemIdData)))
 
+/*
+ * Additional macros for access to page headers
+ */
 #define PageGetLSN(page) \
        (((PageHeader) (page))->pd_lsn)
 #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))
+       (((PageHeader) (page))->pd_tli = (uint16) (tli))
+
+#define PageHasFreeLinePointers(page) \
+       (((PageHeader) (page))->pd_flags & PD_HAS_FREE_LINES)
+#define PageSetHasFreeLinePointers(page) \
+       (((PageHeader) (page))->pd_flags |= PD_HAS_FREE_LINES)
+#define PageClearHasFreeLinePointers(page) \
+       (((PageHeader) (page))->pd_flags &= ~PD_HAS_FREE_LINES)
+
 
 /* ----------------------------------------------------------------
  *             extern declarations