Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit fb27643

Browse files
committed
Suppress useless searches for unused line pointers in PageAddItem. To do
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
1 parent 44f72c6 commit fb27643

File tree

4 files changed

+82
-25
lines changed

4 files changed

+82
-25
lines changed

doc/src/sgml/storage.sgml

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/storage.sgml,v 1.14 2007/01/31 20:56:19 momjian Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/storage.sgml,v 1.15 2007/03/02 00:48:44 tgl Exp $ -->
22

33
<chapter id="storage">
44

@@ -427,8 +427,8 @@ data. Empty in ordinary tables.</entry>
427427
The first 20 bytes of each page consists of a page header
428428
(PageHeaderData). Its format is detailed in <xref
429429
linkend="pageheaderdata-table">. The first two fields track the most
430-
recent WAL entry related to this page. They are followed by three 2-byte
431-
integer fields
430+
recent WAL entry related to this page. Next is a 2-byte field
431+
containing flag bits. This is followed by three 2-byte integer fields
432432
(<structfield>pd_lower</structfield>, <structfield>pd_upper</structfield>,
433433
and <structfield>pd_special</structfield>). These contain byte offsets
434434
from the page start to the start
@@ -437,12 +437,13 @@ data. Empty in ordinary tables.</entry>
437437
The last 2 bytes of the page header,
438438
<structfield>pd_pagesize_version</structfield>, store both the page size
439439
and a version indicator. Beginning with
440-
<productname>PostgreSQL</productname> 8.1 the version number is 3;
440+
<productname>PostgreSQL</productname> 8.3 the version number is 4;
441+
<productname>PostgreSQL</productname> 8.1 and 8.2 used version number 3;
441442
<productname>PostgreSQL</productname> 8.0 used version number 2;
442443
<productname>PostgreSQL</productname> 7.3 and 7.4 used version number 1;
443444
prior releases used version number 0.
444-
(The basic page layout and header format has not changed in these versions,
445-
but the layout of heap row headers has.) The page size
445+
(The basic page layout and header format has not changed in most of these
446+
versions, but the layout of heap row headers has.) The page size
446447
is basically only present as a cross-check; there is no support for having
447448
more than one page size in an installation.
448449

@@ -470,9 +471,15 @@ data. Empty in ordinary tables.</entry>
470471
</row>
471472
<row>
472473
<entry>pd_tli</entry>
473-
<entry>TimeLineID</entry>
474-
<entry>4 bytes</entry>
475-
<entry>TLI of last change</entry>
474+
<entry>uint16</entry>
475+
<entry>2 bytes</entry>
476+
<entry>TimeLineID of last change (only its lowest 16 bits)</entry>
477+
</row>
478+
<row>
479+
<entry>pd_flags</entry>
480+
<entry>uint16</entry>
481+
<entry>2 bytes</entry>
482+
<entry>Flag bits</entry>
476483
</row>
477484
<row>
478485
<entry>pd_lower</entry>

src/backend/storage/page/bufpage.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/storage/page/bufpage.c,v 1.71 2007/02/21 20:02:17 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/storage/page/bufpage.c,v 1.72 2007/03/02 00:48:44 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -39,6 +39,7 @@ PageInit(Page page, Size pageSize, Size specialSize)
3939
/* Make sure all fields of page are zero, as well as unused space */
4040
MemSet(p, 0, pageSize);
4141

42+
/* p->pd_flags = 0; done by above MemSet */
4243
p->pd_lower = SizeOfPageHeaderData;
4344
p->pd_upper = pageSize - specialSize;
4445
p->pd_special = pageSize - specialSize;
@@ -73,6 +74,7 @@ PageHeaderIsValid(PageHeader page)
7374
/* Check normal case */
7475
if (PageGetPageSize(page) == BLCKSZ &&
7576
PageGetPageLayoutVersion(page) == PG_PAGE_LAYOUT_VERSION &&
77+
(page->pd_flags & ~PD_VALID_FLAG_BITS) == 0 &&
7678
page->pd_lower >= SizeOfPageHeaderData &&
7779
page->pd_lower <= page->pd_upper &&
7880
page->pd_upper <= page->pd_special &&
@@ -165,14 +167,27 @@ PageAddItem(Page page,
165167
else
166168
{
167169
/* offsetNumber was not passed in, so find a free slot */
168-
/* look for "recyclable" (unused & deallocated) ItemId */
169-
for (offsetNumber = 1; offsetNumber < limit; offsetNumber++)
170+
/* if no free slot, we'll put it at limit (1st open slot) */
171+
if (PageHasFreeLinePointers(phdr))
172+
{
173+
/* look for "recyclable" (unused & deallocated) ItemId */
174+
for (offsetNumber = 1; offsetNumber < limit; offsetNumber++)
175+
{
176+
itemId = PageGetItemId(phdr, offsetNumber);
177+
if (!ItemIdIsUsed(itemId) && ItemIdGetLength(itemId) == 0)
178+
break;
179+
}
180+
if (offsetNumber >= limit)
181+
{
182+
/* the hint is wrong, so reset it */
183+
PageClearHasFreeLinePointers(phdr);
184+
}
185+
}
186+
else
170187
{
171-
itemId = PageGetItemId(phdr, offsetNumber);
172-
if (!ItemIdIsUsed(itemId) && ItemIdGetLength(itemId) == 0)
173-
break;
188+
/* don't bother searching if hint says there's no free slot */
189+
offsetNumber = limit;
174190
}
175-
/* if no free slot, we'll put it at limit (1st open slot) */
176191
}
177192

178193
if (offsetNumber > limit)
@@ -413,13 +428,19 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
413428
pfree(itemidbase);
414429
}
415430

431+
/* Set hint bit for PageAddItem */
432+
if (nused < nline)
433+
PageSetHasFreeLinePointers(page);
434+
else
435+
PageClearHasFreeLinePointers(page);
436+
416437
return (nline - nused);
417438
}
418439

419440
/*
420441
* PageGetFreeSpace
421442
* Returns the size of the free (allocatable) space on a page,
422-
* deducted by the space needed for a new line pointer.
443+
* reduced by the space needed for a new line pointer.
423444
*/
424445
Size
425446
PageGetFreeSpace(Page page)

src/include/catalog/catversion.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
3838
* Portions Copyright (c) 1994, Regents of the University of California
3939
*
40-
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.388 2007/02/20 17:32:17 tgl Exp $
40+
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.389 2007/03/02 00:48:44 tgl Exp $
4141
*
4242
*-------------------------------------------------------------------------
4343
*/
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 200702202
56+
#define CATALOG_VERSION_NO 200703011
5757

5858
#endif

src/include/storage/bufpage.h

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/storage/bufpage.h,v 1.71 2007/02/21 20:02:17 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/storage/bufpage.h,v 1.72 2007/03/02 00:48:44 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -90,6 +90,7 @@ typedef uint16 LocationIndex;
9090
*
9191
* pd_lsn - identifies xlog record for last change to this page.
9292
* pd_tli - ditto.
93+
* pd_flags - flag bits.
9394
* pd_lower - offset to start of free space.
9495
* pd_upper - offset to end of free space.
9596
* pd_special - offset to start of special space.
@@ -98,8 +99,9 @@ typedef uint16 LocationIndex;
9899
* The LSN is used by the buffer manager to enforce the basic rule of WAL:
99100
* "thou shalt write xlog before data". A dirty buffer cannot be dumped
100101
* to disk until xlog has been flushed at least as far as the page's LSN.
101-
* We also store the TLI for identification purposes (it is not clear that
102-
* this is actually necessary, but it seems like a good idea).
102+
* We also store the 16 least significant bits of the TLI for identification
103+
* purposes (it is not clear that this is actually necessary, but it seems
104+
* like a good idea).
103105
*
104106
* The page version number and page size are packed together into a single
105107
* uint16 field. This is for historical reasons: before PostgreSQL 7.3,
@@ -119,7 +121,9 @@ typedef struct PageHeaderData
119121
/* XXX LSN is member of *any* block, not only page-organized ones */
120122
XLogRecPtr pd_lsn; /* LSN: next byte after last byte of xlog
121123
* record for last change to this page */
122-
TimeLineID pd_tli; /* TLI of last change */
124+
uint16 pd_tli; /* least significant bits of the TimeLineID
125+
* containing the LSN */
126+
uint16 pd_flags; /* flag bits, see below */
123127
LocationIndex pd_lower; /* offset to start of free space */
124128
LocationIndex pd_upper; /* offset to end of free space */
125129
LocationIndex pd_special; /* offset to start of special space */
@@ -129,12 +133,25 @@ typedef struct PageHeaderData
129133

130134
typedef PageHeaderData *PageHeader;
131135

136+
/*
137+
* pd_flags contains the following flag bits. Undefined bits are initialized
138+
* to zero and may be used in the future.
139+
*
140+
* PD_HAS_FREE_LINES is set if there are any not-LP_USED line pointers before
141+
* pd_lower. This should be considered a hint rather than the truth, since
142+
* changes to it are not WAL-logged.
143+
*/
144+
#define PD_HAS_FREE_LINES 0x0001 /* are there any unused line pointers? */
145+
146+
#define PD_VALID_FLAG_BITS 0x0001 /* OR of all valid pd_flags bits */
147+
132148
/*
133149
* Page layout version number 0 is for pre-7.3 Postgres releases.
134150
* Releases 7.3 and 7.4 use 1, denoting a new HeapTupleHeader layout.
135151
* Release 8.0 uses 2; it changed the HeapTupleHeader layout again.
136152
* Release 8.1 uses 3; it redefined HeapTupleHeader infomask bits.
137-
* Release 8.3 uses 4; it changed the HeapTupleHeader layout again.
153+
* Release 8.3 uses 4; it changed the HeapTupleHeader layout again, and
154+
* added the pd_flags field (by stealing some bits from pd_tli).
138155
*/
139156
#define PG_PAGE_LAYOUT_VERSION 4
140157

@@ -299,15 +316,27 @@ typedef PageHeaderData *PageHeader;
299316
((((PageHeader) (page))->pd_lower - SizeOfPageHeaderData) \
300317
/ sizeof(ItemIdData)))
301318

319+
/*
320+
* Additional macros for access to page headers
321+
*/
302322
#define PageGetLSN(page) \
303323
(((PageHeader) (page))->pd_lsn)
304324
#define PageSetLSN(page, lsn) \
305325
(((PageHeader) (page))->pd_lsn = (lsn))
306326

327+
/* NOTE: only the 16 least significant bits are stored */
307328
#define PageGetTLI(page) \
308329
(((PageHeader) (page))->pd_tli)
309330
#define PageSetTLI(page, tli) \
310-
(((PageHeader) (page))->pd_tli = (tli))
331+
(((PageHeader) (page))->pd_tli = (uint16) (tli))
332+
333+
#define PageHasFreeLinePointers(page) \
334+
(((PageHeader) (page))->pd_flags & PD_HAS_FREE_LINES)
335+
#define PageSetHasFreeLinePointers(page) \
336+
(((PageHeader) (page))->pd_flags |= PD_HAS_FREE_LINES)
337+
#define PageClearHasFreeLinePointers(page) \
338+
(((PageHeader) (page))->pd_flags &= ~PD_HAS_FREE_LINES)
339+
311340

312341
/* ----------------------------------------------------------------
313342
* extern declarations

0 commit comments

Comments
 (0)