I finished first prototype of new page API. It contains several new functions 
like:

Pointer PageGetUpperPointer(Page page);

void PageClearPrunable(Page page);
bool PageIsComprimable(Page page);

void PageReserveLinp(Page page);
void PageReleaseLinp(Page page);

LocationIndex PageGetLower(Page page);
LocationIndex PageGetUpper(Page page);
LocationIndex PageGetSpecial(Page page);
void PageSetLower(Page page, LocationIndex lower);
void PageSetUpper(Page page, LocationIndex lower);

Page PageGetTempPage(Page page, bool copy);
Page PageGetTempPageCopySpecial(Page page);
void PageRestoreTempPage(Page tempPage, Page oldPage);

Size PageGetSpecialSize(Page page);
Size PageGetDataSize(Page page);

bool PageLayoutIsValid(Page page);


The main point of the new API is to handle multi page layout versions. The current implementation don't uses any speed optimization and performance gap is about 5% (big thanks to Paul van den Bogaard for benchmarking). Finally I plan to implement hottest function like macro (or inline fn ;-) ) and because most structure members are located on same place I will remove extra switch in the code.

I also grab number of calls by DTrace and I got following result:

<snip>
  PageGetHeapFreeSpace                                            984
  PageGetSpecialSize                                             1170
  PageGetFreeSpace                                               1200
  PageGetExactFreeSpace                                          1399
  PageGetUpper                                                   1419
  PageGetLower                                                   1618
  PageGetLSN                                                     2936
  PageGetMaxOffsetNumber                                         5504
  PageGetSpecialPointer                                         13534
  PageGetItemId                                                 71074
  PageGetItem                                                   76629

I plan to remove PageGetItemId and replace it with any other function like PageGetHeapTuple and so on. The reason is that ItemId flags has been changed between version 3 and 4. And on many times it is called like

itemId = PageGetItemId();
PageGetItem(itemId);

I'm also thinking about add following function:

PageSetXLOG(page,TLI,LSN) - it should replace PageSetLSN();PageSetTLI(); sequence in code

I'm not happy with PageSetLower() function which is used in nbtree, but no idea yet how to improve it.

Please, let me know your comments. I attached prototype patch.

        Thanks Zdenek


--
Zdenek Kotala              Sun Microsystems
Prague, Czech Republic     http://sun.com/postgresql

diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/gin/gindatapage.c
--- a/src/backend/access/gin/gindatapage.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/gin/gindatapage.c	Mon Aug 11 15:58:27 2008 +0200
@@ -445,7 +445,7 @@
 	char	   *ptr;
 	OffsetNumber separator;
 	ItemPointer bound;
-	Page		lpage = GinPageGetCopyPage(BufferGetPage(lbuf));
+	Page		lpage = PageGetTempPage(BufferGetPage(lbuf), true);
 	ItemPointerData oldbound = *GinDataPageGetRightBound(lpage);
 	int			sizeofitem = GinSizeOfItem(lpage);
 	OffsetNumber maxoff = GinPageGetOpaque(lpage)->maxoff;
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/gin/ginentrypage.c
--- a/src/backend/access/gin/ginentrypage.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/gin/ginentrypage.c	Mon Aug 11 15:58:27 2008 +0200
@@ -458,7 +458,7 @@
 				leftrightmost = NULL;
 	static ginxlogSplit data;
 	Page		page;
-	Page		lpage = GinPageGetCopyPage(BufferGetPage(lbuf));
+	Page		lpage = PageGetTempPage(BufferGetPage(lbuf), true);
 	Page		rpage = BufferGetPage(rbuf);
 	Size		pageSize = PageGetPageSize(lpage);
 
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/gin/ginutil.c
--- a/src/backend/access/gin/ginutil.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/gin/ginutil.c	Mon Aug 11 15:58:27 2008 +0200
@@ -309,21 +309,6 @@
 	return entries;
 }
 
-/*
- * It's analog of PageGetTempPage(), but copies whole page
- */
-Page
-GinPageGetCopyPage(Page page)
-{
-	Size		pageSize = PageGetPageSize(page);
-	Page		tmppage;
-
-	tmppage = (Page) palloc(pageSize);
-	memcpy(tmppage, page, pageSize);
-
-	return tmppage;
-}
-
 Datum
 ginoptions(PG_FUNCTION_ARGS)
 {
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/gin/ginvacuum.c
--- a/src/backend/access/gin/ginvacuum.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/gin/ginvacuum.c	Mon Aug 11 15:58:27 2008 +0200
@@ -529,7 +529,7 @@
 					 * On first difference we create temporary page in memory
 					 * and copies content in to it.
 					 */
-					tmppage = GinPageGetCopyPage(origpage);
+					tmppage = PageGetTempPage(origpage, true);
 
 					if (newN > 0)
 					{
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/gist/gist.c
--- a/src/backend/access/gist/gist.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/gist/gist.c	Mon Aug 11 15:58:27 2008 +0200
@@ -339,7 +339,7 @@
 			 * we must create temporary page to operate
 			 */
 			dist->buffer = state->stack->buffer;
-			dist->page = PageGetTempPage(BufferGetPage(dist->buffer), sizeof(GISTPageOpaqueData));
+			dist->page = PageGetTempPageCopySpecial(BufferGetPage(dist->buffer));
 
 			/* clean all flags except F_LEAF */
 			GistPageGetOpaque(dist->page)->flags = (is_leaf) ? F_LEAF : 0;
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/gist/gistvacuum.c
--- a/src/backend/access/gist/gistvacuum.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/gist/gistvacuum.c	Mon Aug 11 15:58:27 2008 +0200
@@ -140,18 +140,6 @@
 	END_CRIT_SECTION();
 
 	UnlockReleaseBuffer(buffer);
-}
-
-static Page
-GistPageGetCopyPage(Page page)
-{
-	Size		pageSize = PageGetPageSize(page);
-	Page		tmppage;
-
-	tmppage = (Page) palloc(pageSize);
-	memcpy(tmppage, page, pageSize);
-
-	return tmppage;
 }
 
 static ArrayTuple
@@ -322,7 +310,7 @@
 		addon = (IndexTuple *) palloc(sizeof(IndexTuple) * lenaddon);
 
 		/* get copy of page to work */
-		tempPage = GistPageGetCopyPage(page);
+		tempPage = PageGetTempPage(page, true);
 
 		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 		{
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/hash/hash.c
--- a/src/backend/access/hash/hash.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/hash/hash.c	Mon Aug 11 15:58:27 2008 +0200
@@ -527,7 +527,7 @@
 	 * each bucket.
 	 */
 	metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
-	metap = (HashMetaPage) BufferGetPage(metabuf);
+	metap =  HashPageGetMeta(BufferGetPage(metabuf));
 	orig_maxbucket = metap->hashm_maxbucket;
 	orig_ntuples = metap->hashm_ntuples;
 	memcpy(&local_metapage, metap, sizeof(local_metapage));
@@ -629,7 +629,7 @@
 
 	/* Write-lock metapage and check for split since we started */
 	metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_WRITE, LH_META_PAGE);
-	metap = (HashMetaPage) BufferGetPage(metabuf);
+	metap = HashPageGetMeta(BufferGetPage(metabuf));
 
 	if (cur_maxbucket != metap->hashm_maxbucket)
 	{
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/hash/hashinsert.c
--- a/src/backend/access/hash/hashinsert.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/hash/hashinsert.c	Mon Aug 11 15:58:27 2008 +0200
@@ -69,7 +69,7 @@
 
 	/* Read the metapage */
 	metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
-	metap = (HashMetaPage) BufferGetPage(metabuf);
+	metap = HashPageGetMeta(BufferGetPage(metabuf));
 
 	/*
 	 * Check whether the item can fit on a hash page at all. (Eventually, we
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/hash/hashovfl.c
--- a/src/backend/access/hash/hashovfl.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/hash/hashovfl.c	Mon Aug 11 15:58:27 2008 +0200
@@ -187,7 +187,7 @@
 	_hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE);
 
 	_hash_checkpage(rel, metabuf, LH_META_PAGE);
-	metap = (HashMetaPage) BufferGetPage(metabuf);
+	metap = HashPageGetMeta(BufferGetPage(metabuf));
 
 	/* start search at hashm_firstfree */
 	orig_firstfree = metap->hashm_firstfree;
@@ -450,7 +450,7 @@
 
 	/* Read the metapage so we can determine which bitmap page to use */
 	metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
-	metap = (HashMetaPage) BufferGetPage(metabuf);
+	metap = HashPageGetMeta(BufferGetPage(metabuf));
 
 	/* Identify which bit to set */
 	ovflbitno = blkno_to_bitno(metap, ovflblkno);
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/hash/hashpage.c
--- a/src/backend/access/hash/hashpage.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/hash/hashpage.c	Mon Aug 11 15:58:27 2008 +0200
@@ -395,20 +395,18 @@
 	pageopaque->hasho_flag = LH_META_PAGE;
 	pageopaque->hasho_page_id = HASHO_PAGE_ID;
 
-	metap = (HashMetaPage) pg;
+	metap = HashPageGetMeta(pg);
 
 	metap->hashm_magic = HASH_MAGIC;
 	metap->hashm_version = HASH_VERSION;
 	metap->hashm_ntuples = 0;
 	metap->hashm_nmaps = 0;
 	metap->hashm_ffactor = ffactor;
-	metap->hashm_bsize = BufferGetPageSize(metabuf);
+	metap->hashm_bsize = HashGetMaxBitmapSize(pg);
 	/* find largest bitmap array size that will fit in page size */
 	for (i = _hash_log2(metap->hashm_bsize); i > 0; --i)
 	{
-		if ((1 << i) <= (metap->hashm_bsize -
-						 (MAXALIGN(sizeof(PageHeaderData)) +
-						  MAXALIGN(sizeof(HashPageOpaqueData)))))
+		if ((1 << i) <= metap->hashm_bsize)
 			break;
 	}
 	Assert(i > 0);
@@ -532,7 +530,7 @@
 	_hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE);
 
 	_hash_checkpage(rel, metabuf, LH_META_PAGE);
-	metap = (HashMetaPage) BufferGetPage(metabuf);
+	metap = HashPageGetMeta(BufferGetPage(metabuf));
 
 	/*
 	 * Check to see if split is still needed; someone else might have already
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/hash/hashsearch.c
--- a/src/backend/access/hash/hashsearch.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/hash/hashsearch.c	Mon Aug 11 15:58:27 2008 +0200
@@ -186,7 +186,7 @@
 
 	/* Read the metapage */
 	metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
-	metap = (HashMetaPage) BufferGetPage(metabuf);
+	metap = HashPageGetMeta(BufferGetPage(metabuf));
 
 	/*
 	 * Compute the target bucket number, and convert to block number.
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/hash/hashutil.c
--- a/src/backend/access/hash/hashutil.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/hash/hashutil.c	Mon Aug 11 15:58:27 2008 +0200
@@ -190,7 +190,7 @@
 	 */
 	if (flags == LH_META_PAGE)
 	{
-		HashMetaPage metap = (HashMetaPage) page;
+		HashMetaPage metap = HashPageGetMeta(page);
 
 		if (metap->hashm_magic != HASH_MAGIC)
 			ereport(ERROR,
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/heap/pruneheap.c
--- a/src/backend/access/heap/pruneheap.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/heap/pruneheap.c	Mon Aug 11 15:58:27 2008 +0200
@@ -236,7 +236,10 @@
 		 * Update the page's pd_prune_xid field to either zero, or the lowest
 		 * XID of any soon-prunable tuple.
 		 */
-		((PageHeader) page)->pd_prune_xid = prstate.new_prune_xid;
+		if( prstate.new_prune_xid != InvalidTransactionId)
+			PageSetPrunable(page, prstate.new_prune_xid);
+		else 
+			PageClearPrunable(page);
 
 		/*
 		 * Also clear the "page is full" flag, since there's no point in
@@ -275,10 +278,10 @@
 		 * point in repeating the prune/defrag process until something else
 		 * happens to the page.
 		 */
-		if (((PageHeader) page)->pd_prune_xid != prstate.new_prune_xid ||
+		if (PageGetPrunable(page) != prstate.new_prune_xid ||
 			PageIsFull(page))
 		{
-			((PageHeader) page)->pd_prune_xid = prstate.new_prune_xid;
+			PageSetPrunable(page, prstate.new_prune_xid);
 			PageClearFull(page);
 			SetBufferCommitInfoNeedsSave(buffer);
 		}
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/nbtree/nbtinsert.c
--- a/src/backend/access/nbtree/nbtinsert.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/nbtree/nbtinsert.c	Mon Aug 11 15:58:27 2008 +0200
@@ -793,7 +793,7 @@
 
 	rbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
 	origpage = BufferGetPage(buf);
-	leftpage = PageGetTempPage(origpage, sizeof(BTPageOpaqueData));
+	leftpage = PageGetTempPage(origpage, false);
 	rightpage = BufferGetPage(rbuf);
 
 	_bt_pageinit(leftpage, BufferGetPageSize(buf));
@@ -1115,10 +1115,8 @@
 		lastrdata->next = lastrdata + 1;
 		lastrdata++;
 
-		lastrdata->data = (char *) rightpage +
-			((PageHeader) rightpage)->pd_upper;
-		lastrdata->len = ((PageHeader) rightpage)->pd_special -
-			((PageHeader) rightpage)->pd_upper;
+		lastrdata->data = PageGetUpperPointer(rightpage);
+		lastrdata->len = PageGetDataSize(rightpage);
 		lastrdata->buffer = InvalidBuffer;
 
 		/* Log the right sibling, because we've changed its' prev-pointer. */
@@ -1772,13 +1770,8 @@
 		rdata[0].buffer = InvalidBuffer;
 		rdata[0].next = &(rdata[1]);
 
-		/*
-		 * Direct access to page is not good but faster - we should implement
-		 * some new func in page API.
-		 */
-		rdata[1].data = (char *) rootpage + ((PageHeader) rootpage)->pd_upper;
-		rdata[1].len = ((PageHeader) rootpage)->pd_special -
-			((PageHeader) rootpage)->pd_upper;
+		rdata[1].data = PageGetUpperPointer(rootpage);
+		rdata[1].len = PageGetDataSize(rootpage);
 		rdata[1].buffer = InvalidBuffer;
 		rdata[1].next = NULL;
 
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/nbtree/nbtpage.c
--- a/src/backend/access/nbtree/nbtpage.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/nbtree/nbtpage.c	Mon Aug 11 15:58:27 2008 +0200
@@ -58,8 +58,7 @@
 	 * Set pd_lower just past the end of the metadata.	This is not essential
 	 * but it makes the page look compressible to xlog.c.
 	 */
-	((PageHeader) page)->pd_lower =
-		((char *) metad + sizeof(BTMetaPageData)) - (char *) page;
+	PageSetLower(page, ((char *) metad + sizeof(BTMetaPageData)) - (char *) page);
 }
 
 /*
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/nbtree/nbtsort.c
--- a/src/backend/access/nbtree/nbtsort.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/nbtree/nbtsort.c	Mon Aug 11 15:58:27 2008 +0200
@@ -249,7 +249,7 @@
 	opaque->btpo_cycleid = 0;
 
 	/* Make the P_HIKEY line pointer appear allocated */
-	((PageHeader) page)->pd_lower += sizeof(ItemIdData);
+	PageReserveLinp(page);
 
 	return page;
 }
@@ -366,7 +366,7 @@
 			*previi = *thisii;
 			previi = thisii;
 		}
-		((PageHeader) page)->pd_lower -= sizeof(ItemIdData);
+		PageReleaseLinp(page);
 	}
 }
 
@@ -523,7 +523,7 @@
 		hii = PageGetItemId(opage, P_HIKEY);
 		*hii = *ii;
 		ItemIdSetUnused(ii);	/* redundant */
-		((PageHeader) opage)->pd_lower -= sizeof(ItemIdData);
+		PageReleaseLinp(opage);
 
 		/*
 		 * Link the old page into its parent, using its minimum key. If we
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/nbtree/nbtxlog.c
--- a/src/backend/access/nbtree/nbtxlog.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/nbtree/nbtxlog.c	Mon Aug 11 15:58:27 2008 +0200
@@ -180,9 +180,7 @@
 	 * Set pd_lower just past the end of the metadata.	This is not essential
 	 * but it makes the page look compressible to xlog.c.
 	 */
-	((PageHeader) metapg)->pd_lower =
-		((char *) md + sizeof(BTMetaPageData)) - (char *) metapg;
-
+	PageSetLower(metapg, ((char *) md + sizeof(BTMetaPageData)) - (char *) metapg);
 	PageSetLSN(metapg, lsn);
 	PageSetTLI(metapg, ThisTimeLineID);
 	MarkBufferDirty(metabuf);
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/access/transam/xlog.c
--- a/src/backend/access/transam/xlog.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/access/transam/xlog.c	Mon Aug 11 15:58:27 2008 +0200
@@ -1040,15 +1040,10 @@
 		if (rdata->buffer_std)
 		{
 			/* Assume we can omit data between pd_lower and pd_upper */
-			uint16		lower = ((PageHeader) page)->pd_lower;
-			uint16		upper = ((PageHeader) page)->pd_upper;
-
-			if (lower >= SizeOfPageHeaderData &&
-				upper > lower &&
-				upper <= BLCKSZ)
-			{
-				bkpb->hole_offset = lower;
-				bkpb->hole_length = upper - lower;
+			if (PageIsComprimable(page))
+			{
+				bkpb->hole_offset = PageGetLower(page);
+				bkpb->hole_length = PageGetExactFreeSpace(page);
 			}
 			else
 			{
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/commands/sequence.c
--- a/src/backend/commands/sequence.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/commands/sequence.c	Mon Aug 11 15:58:27 2008 +0200
@@ -387,9 +387,8 @@
 		rdata[0].buffer = InvalidBuffer;
 		rdata[0].next = &(rdata[1]);
 
-		rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
-		rdata[1].len = ((PageHeader) page)->pd_special -
-			((PageHeader) page)->pd_upper;
+		rdata[1].data = PageGetUpperPointer(page);
+		rdata[1].len = PageGetDataSize(page);
 		rdata[1].buffer = InvalidBuffer;
 		rdata[1].next = NULL;
 
@@ -618,9 +617,8 @@
 		seq->is_called = true;
 		seq->log_cnt = 0;
 
-		rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
-		rdata[1].len = ((PageHeader) page)->pd_special -
-			((PageHeader) page)->pd_upper;
+		rdata[1].data = PageGetUpperPointer(page);
+		rdata[1].len = PageGetDataSize(page);
 		rdata[1].buffer = InvalidBuffer;
 		rdata[1].next = NULL;
 
@@ -794,9 +792,8 @@
 		seq->is_called = true;
 		seq->log_cnt = 0;
 
-		rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
-		rdata[1].len = ((PageHeader) page)->pd_special -
-			((PageHeader) page)->pd_upper;
+		rdata[1].data = PageGetUpperPointer(page);
+		rdata[1].len = PageGetDataSize(page);
 		rdata[1].buffer = InvalidBuffer;
 		rdata[1].next = NULL;
 
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/storage/buffer/bufmgr.c
--- a/src/backend/storage/buffer/bufmgr.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/storage/buffer/bufmgr.c	Mon Aug 11 15:58:27 2008 +0200
@@ -356,7 +356,7 @@
 			smgrread(smgr, blockNum, (char *) bufBlock);
 
 			/* check for garbage data */
-			if (!PageHeaderIsValid((PageHeader) bufBlock))
+			if (!PageLayoutIsValid((Page) bufBlock))
 			{
 				if (zero_damaged_pages)
 				{
diff -r 879ef18ad9cb -r 3e71cf34dced src/backend/storage/page/bufpage.c
--- a/src/backend/storage/page/bufpage.c	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/backend/storage/page/bufpage.c	Mon Aug 11 15:58:27 2008 +0200
@@ -8,15 +8,19 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/page/bufpage.c,v 1.79 2008/05/13 15:44:08 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/page/bufpage.c,v 1.78 2008/02/10 20:39:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup.h"
+#include "access/transam.h"
 #include "storage/bufpage.h"
 
+
+static bool PageLayoutIsValid_04(Page page);
+bool PageIsZeroed(Page page);
 
 /* ----------------------------------------------------------------
  *						Page support functions
@@ -25,12 +29,13 @@
 
 /*
  * PageInit
- *		Initializes the contents of a page.
+ *		Initializes the contents of a page. We allow to initialize page only
+ *      in latest Page Layout Version.
  */
 void
 PageInit(Page page, Size pageSize, Size specialSize)
 {
-	PageHeader	p = (PageHeader) page;
+	PageHeader_04	p = (PageHeader_04) page;
 
 	specialSize = MAXALIGN(specialSize);
 
@@ -50,7 +55,7 @@
 
 
 /*
- * PageHeaderIsValid
+ * PageLayoutIsValid
  *		Check that the header fields of a page appear valid.
  *
  * This is called when a page has just been read in from disk.	The idea is
@@ -68,23 +73,26 @@
  * will clean up such a page and make it usable.
  */
 bool
-PageHeaderIsValid(PageHeader page)
+PageLayoutIsValid(Page page)
+{
+	/* Check normal case */
+	switch(PageGetPageLayoutVersion(page))
+	{
+		case 4 : return(PageLayoutIsValid_04(page));
+		case 0 : return(PageIsZeroed(page));
+	}
+	return false;
+}
+
+/* 
+ * Check all-zeroes case 
+ */
+bool
+PageIsZeroed(Page page)
 {
 	char	   *pagebytes;
 	int			i;
 
-	/* 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 &&
-		page->pd_special <= BLCKSZ &&
-		page->pd_special == MAXALIGN(page->pd_special))
-		return true;
-
-	/* Check all-zeroes case */
 	pagebytes = (char *) page;
 	for (i = 0; i < BLCKSZ; i++)
 	{
@@ -92,6 +100,21 @@
 			return false;
 	}
 	return true;
+}
+
+bool PageLayoutIsValid_04(Page page)
+{
+	PageHeader_04 phdr = (PageHeader_04)page;
+ 	if(
+		 PageGetPageSize(page) == BLCKSZ &&
+		(phdr->pd_flags & ~PD_VALID_FLAG_BITS) == 0 &&
+		phdr->pd_lower >= SizeOfPageHeaderData &&
+		phdr->pd_lower <= phdr->pd_upper &&
+		phdr->pd_upper <= phdr->pd_special &&
+		phdr->pd_special <= BLCKSZ &&
+		phdr->pd_special == MAXALIGN(phdr->pd_special))
+		return true;
+	return false;
 }
 
 
@@ -123,7 +146,7 @@
 			bool overwrite,
 			bool is_heap)
 {
-	PageHeader	phdr = (PageHeader) page;
+	PageHeader_04	phdr = (PageHeader_04) page;
 	Size		alignedSize;
 	int			lower;
 	int			upper;
@@ -131,6 +154,9 @@
 	OffsetNumber limit;
 	bool		needshuffle = false;
 
+	/* We allow add new items only on the new page layout - TODO indexes? */
+	if( PageGetPageLayoutVersion(page) != PG_PAGE_LAYOUT_VERSION )
+		elog(PANIC, "Add item on old page layout version is forbidden.");
 	/*
 	 * Be wary about corrupted page pointers
 	 */
@@ -156,7 +182,7 @@
 		{
 			if (offsetNumber < limit)
 			{
-				itemId = PageGetItemId(phdr, offsetNumber);
+				itemId = PageGetItemId(page, offsetNumber);
 				if (ItemIdIsUsed(itemId) || ItemIdHasStorage(itemId))
 				{
 					elog(WARNING, "will not overwrite a used ItemId");
@@ -174,7 +200,7 @@
 	{
 		/* offsetNumber was not passed in, so find a free slot */
 		/* if no free slot, we'll put it at limit (1st open slot) */
-		if (PageHasFreeLinePointers(phdr))
+		if (PageHasFreeLinePointers(page))
 		{
 			/*
 			 * Look for "recyclable" (unused) ItemId.  We check for no storage
@@ -183,14 +209,14 @@
 			 */
 			for (offsetNumber = 1; offsetNumber < limit; offsetNumber++)
 			{
-				itemId = PageGetItemId(phdr, offsetNumber);
+				itemId = PageGetItemId(page, offsetNumber);
 				if (!ItemIdIsUsed(itemId) && !ItemIdHasStorage(itemId))
 					break;
 			}
 			if (offsetNumber >= limit)
 			{
 				/* the hint is wrong, so reset it */
-				PageClearHasFreeLinePointers(phdr);
+				PageClearHasFreeLinePointers(page);
 			}
 		}
 		else
@@ -233,7 +259,7 @@
 	/*
 	 * OK to insert the item.  First, shuffle the existing pointers if needed.
 	 */
-	itemId = PageGetItemId(phdr, offsetNumber);
+	itemId = PageGetItemId(page, offsetNumber);
 
 	if (needshuffle)
 		memmove(itemId + 1, itemId,
@@ -254,31 +280,47 @@
 
 /*
  * PageGetTempPage
- *		Get a temporary page in local memory for special processing
+ *		Get a temporary page in local memory for special processing. Caller is
+ * responsible to init page. 
  */
 Page
-PageGetTempPage(Page page, Size specialSize)
+PageGetTempPage(Page page, bool copy)
+{
+	Size		pageSize;
+	Size		size;
+	Page		temp;
+
+	pageSize = PageGetPageSize(page);
+	temp = (Page) palloc(pageSize);
+
+	if( copy )
+	{
+		memcpy(temp, page, pageSize);
+	}
+
+	return temp;
+}
+
+/*
+ * PageGetTempPage
+ *		Get a temporary page in local memory for special processing
+ * XXX: only consumer now is gistplacetopage(), so maybe we don't even want it
+ */
+Page
+PageGetTempPageCopySpecial(Page page)
 {
 	Size		pageSize;
 	Page		temp;
-	PageHeader	thdr;
 
 	pageSize = PageGetPageSize(page);
 	temp = (Page) palloc(pageSize);
-	thdr = (PageHeader) temp;
 
-	/* copy old page in */
-	memcpy(temp, page, pageSize);
-
-	/* set high, low water marks */
-	thdr->pd_lower = SizeOfPageHeaderData;
-	thdr->pd_upper = pageSize - MAXALIGN(specialSize);
-
-	/* clear out the middle */
-	MemSet((char *) temp + thdr->pd_lower, 0, thdr->pd_upper - thdr->pd_lower);
+	PageInit(temp, pageSize, PageGetSpecialSize(page));
+	memcpy(PageGetSpecialPointer(temp), PageGetSpecialPointer(page), PageGetSpecialSize(page));
 
 	return temp;
 }
+
 
 /*
  * PageRestoreTempPage
@@ -329,9 +371,9 @@
 void
 PageRepairFragmentation(Page page)
 {
-	Offset		pd_lower = ((PageHeader) page)->pd_lower;
-	Offset		pd_upper = ((PageHeader) page)->pd_upper;
-	Offset		pd_special = ((PageHeader) page)->pd_special;
+	Offset		pd_lower = PageGetLower(page);
+	Offset		pd_upper = PageGetUpper(page);
+	Offset		pd_special = PageGetSpecial(page);
 	itemIdSort	itemidbase,
 				itemidptr;
 	ItemId		lp;
@@ -380,7 +422,7 @@
 	if (nstorage == 0)
 	{
 		/* Page is completely empty, so just reset it quickly */
-		((PageHeader) page)->pd_upper = pd_special;
+		PageSetUpper(page, pd_special);
 	}
 	else
 	{							/* nstorage != 0 */
@@ -430,7 +472,7 @@
 			lp->lp_off = upper;
 		}
 
-		((PageHeader) page)->pd_upper = upper;
+		PageSetUpper(page, upper);
 
 		pfree(itemidbase);
 	}
@@ -459,8 +501,7 @@
 	 * Use signed arithmetic here so that we behave sensibly if pd_lower >
 	 * pd_upper.
 	 */
-	space = (int) ((PageHeader) page)->pd_upper -
-		(int) ((PageHeader) page)->pd_lower;
+	space = PageGetExactFreeSpace(page);
 
 	if (space < (int) sizeof(ItemIdData))
 		return 0;
@@ -483,8 +524,7 @@
 	 * Use signed arithmetic here so that we behave sensibly if pd_lower >
 	 * pd_upper.
 	 */
-	space = (int) ((PageHeader) page)->pd_upper -
-		(int) ((PageHeader) page)->pd_lower;
+	space = (int)PageGetUpper(page) - (int)PageGetLower(page);
 
 	if (space < 0)
 		return 0;
@@ -524,7 +564,7 @@
 		nline = PageGetMaxOffsetNumber(page);
 		if (nline >= MaxHeapTuplesPerPage)
 		{
-			if (PageHasFreeLinePointers((PageHeader) page))
+			if (PageHasFreeLinePointers(page))
 			{
 				/*
 				 * Since this is just a hint, we must confirm that there is
@@ -571,7 +611,7 @@
 void
 PageIndexTupleDelete(Page page, OffsetNumber offnum)
 {
-	PageHeader	phdr = (PageHeader) page;
+	PageHeader_04	phdr = (PageHeader_04) page; /* TODO PGU */
 	char	   *addr;
 	ItemId		tup;
 	Size		size;
@@ -656,7 +696,7 @@
 		nline--;				/* there's one less than when we started */
 		for (i = 1; i <= nline; i++)
 		{
-			ItemId		ii = PageGetItemId(phdr, i);
+			ItemId		ii = PageGetItemId(page, i);
 
 			Assert(ItemIdHasStorage(ii));
 			if (ItemIdGetOffset(ii) <= offset)
@@ -677,7 +717,7 @@
 void
 PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
 {
-	PageHeader	phdr = (PageHeader) page;
+	PageHeader_04	phdr = (PageHeader_04) page; /* TODO PGU */
 	Offset		pd_lower = phdr->pd_lower;
 	Offset		pd_upper = phdr->pd_upper;
 	Offset		pd_special = phdr->pd_special;
@@ -797,3 +837,371 @@
 
 	pfree(itemidbase);
 }
+
+
+
+/*
+ * PageGetItemId
+ *		Returns an item identifier of a page.
+ */
+ItemId PageGetItemId(Page page, OffsetNumber offsetNumber) 
+{
+	AssertMacro(offsetNumber > 0);
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return (ItemId) (& ((PageHeader_04) page)->pd_linp[(offsetNumber) - 1]) ;
+	}
+	elog(PANIC, "Unsupported page layout in function PageGetItemId.");
+}
+
+/*
+ * PageGetContents
+ *		To be used in case the page does not contain item pointers.
+ */
+Pointer PageGetContents(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return (Pointer) (&((PageHeader_04) (page))->pd_linp[0]);
+	}
+	elog(PANIC, "Unsupported page layout in function PageGetContents.");
+}
+
+/* ----------------
+ *		page special data macros
+ * ----------------
+ */
+/*
+ * PageGetSpecialSize
+ *		Returns size of special space on a page.
+ */
+Size PageGetSpecialSize(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return (Size) PageGetPageSize(page) - ((PageHeader_04)(page))->pd_special;
+
+	}
+	elog(PANIC, "Unsupported page layout in function PageGetSpecialSize.");
+}
+
+Size PageGetDataSize(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return (Size) ((PageHeader_04)(page))->pd_special - ((PageHeader_04)(page))->pd_upper;
+	}
+	elog(PANIC, "Unsupported page layout in function PageGetDataSize.");
+}
+
+/*
+ * PageGetSpecialPointer
+ *		Returns pointer to special space on a page.
+ */
+Pointer PageGetSpecialPointer(Page page)
+{ 
+	AssertMacro(PageIsValid(page));
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return page + ((PageHeader_04)(page))->pd_special;
+	}
+	elog(PANIC, "Unsupported page layout in function PageGetSpecialPointer.");
+}
+
+/*
+ * PageGetUpperPointer
+ *		Returns pointer to first data (upper) on a page.
+ */
+Pointer PageGetUpperPointer(Page page)
+{
+	AssertMacro(PageIsValid(page));
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return page + ((PageHeader_04)(page))->pd_upper;
+	}
+	elog(PANIC, "Unsupported page layout in function PageGetUpperPointer.");
+}
+
+void PageSetLower(Page page, LocationIndex lower)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : ((PageHeader_04) page)->pd_lower = lower;
+				break;
+		default:  elog(PANIC, "Unsupported page layout in function PageSetLower.");
+	}		  
+}
+
+void PageSetUpper(Page page, LocationIndex upper)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : ((PageHeader_04) page)->pd_upper = upper;
+				break;
+		default:  elog(PANIC, "Unsupported page layout in function PageSetLower.");
+	}		  
+}
+
+
+/*
+ * PageGetItem
+ *		Retrieves an item on the given page.
+ *
+ * Note:
+ *		This does not change the status of any of the resources passed.
+ *		The semantics may change in the future.
+ */
+Item PageGetItem(Page page, ItemId itemId) 
+{
+	AssertMacro(PageIsValid(page));
+	AssertMacro(ItemIdHasStorage(itemId));
+	switch ( PageGetPageLayoutVersion(page) ) /* TODO not necessary */
+	{
+		case 4 : return (Item) (page + ItemIdGetOffset(itemId));
+	}
+	elog(PANIC, "Unsupported page layout in function PageGetItem.");
+}
+
+
+void PageReserveLinp(Page page)
+{
+	AssertMacro(PageIsValid(page));
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : ((PageHeader_04) page)->pd_lower += sizeof(ItemIdData);
+				AssertMacro(((PageHeader_04) page)->pd_lower <= ((PageHeader_04) page)->pd_upper );
+				break;
+		default: elog(PANIC, "Unsupported page layout in function PageReserveLinp.");
+	}
+}
+
+void PageReleaseLinp(Page page)
+{
+	AssertMacro(PageIsValid(page));
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : ((PageHeader_04) page)->pd_lower -= sizeof(ItemIdData);
+				AssertMacro(((PageHeader_04) page)->pd_lower >= SizeOfPageHeaderData);
+				break;
+		default: elog(PANIC, "Unsupported page layout in function PageReleaseLinp.");
+	}
+}
+
+
+/*
+ * PageGetMaxOffsetNumber
+ *		Returns the maximum offset number used by the given page.
+ *		Since offset numbers are 1-based, this is also the number
+ *		of items on the page.
+ *
+ *		NOTE: if the page is not initialized (pd_lower == 0), we must
+ *		return zero to ensure sane behavior.  Accept double evaluation
+ *		of the argument so that we can ensure this.
+ */
+int PageGetMaxOffsetNumber(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : {
+					PageHeader_04 header = (PageHeader_04) (page);
+				 	return header->pd_lower <= SizeOfPageHeaderData ? 0 :
+				 	(header->pd_lower - SizeOfPageHeaderData) / sizeof(ItemIdData);
+				 }
+	}
+	elog(PANIC, "Unsupported page layout in function PageGetMaxOffsetNumber.");
+	return 0;
+}
+
+/*
+ * Additional macros for access to page headers
+ */
+XLogRecPtr PageGetLSN(Page page) 
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return ((PageHeader_04) page)->pd_lsn;
+	}
+	elog(PANIC, "Unsupported page layout in function PageGetLSN.");
+}
+
+LocationIndex PageGetLower(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return ((PageHeader_04) page)->pd_lower;
+	}
+	elog(PANIC, "Unsupported page layout in function PageGetLower.");
+	return 0;
+}
+
+LocationIndex PageGetUpper(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return ((PageHeader_04) page)->pd_upper;
+	}
+	elog(PANIC, "Unsupported page layout in function PageGetUpper.");
+	return 0;
+}
+
+LocationIndex PageGetSpecial(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return ((PageHeader_04) page)->pd_special;
+	}
+	elog(PANIC, "Unsupported page layout in function PageGetUpper.");
+	return 0;
+}
+
+
+void PageSetLSN(Page page, XLogRecPtr lsn)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{	
+		case 4 : ((PageHeader_04) page)->pd_lsn = lsn;
+				break;
+		default: elog(PANIC, "Unsupported page layout in function PageSetLSN.");
+	}	
+}
+
+/* NOTE: only the 16 least significant bits are stored */
+TimeLineID PageGetTLI(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return ((PageHeader_04) (page))->pd_tli;
+	}
+	elog(PANIC, "Unsupported page layout in function PageGetTLI.");
+}
+
+void PageSetTLI(Page page, TimeLineID tli)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : ((PageHeader_04) (page))->pd_tli = (uint16) (tli);
+				break;
+		default: elog(PANIC, "Unsupported page layout in function PageSetTLI.");
+	}	
+}
+
+bool PageHasFreeLinePointers(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return ((PageHeader_04) (page))->pd_flags & PD_HAS_FREE_LINES;
+		default: return false;
+	}
+}
+
+void PageSetHasFreeLinePointers(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : ((PageHeader_04) (page))->pd_flags |= PD_HAS_FREE_LINES;
+				 break;
+		default: elog(PANIC, "HasFreeLinePointers is not supported on page layout version %i",
+				PageGetPageLayoutVersion(page));
+	}
+}
+
+void PageClearHasFreeLinePointers(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : ((PageHeader_04) (page))->pd_flags &= ~PD_HAS_FREE_LINES;
+				  break;
+		default: elog(PANIC, "HasFreeLinePointers is not supported on page layout version %i",
+				PageGetPageLayoutVersion(page));
+	}	
+}
+
+bool PageIsFull(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return ((PageHeader_04) (page))->pd_flags & PD_PAGE_FULL;
+	}
+	return true; /* no space on old data page */
+}
+
+void PageSetFull(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : ((PageHeader_04) (page))->pd_flags |= PD_PAGE_FULL;
+				  break;
+		default: elog(PANIC, "PageSetFull is not supported on page layout version %i",
+				PageGetPageLayoutVersion(page));
+	}
+}
+
+
+void PageClearFull(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : ((PageHeader_04) (page))->pd_flags &= ~PD_PAGE_FULL;
+				  break;
+		default: elog(PANIC, "PageClearFull is not supported on page layout version %i",
+				PageGetPageLayoutVersion(page));
+	}
+}		
+
+bool PageIsPrunable(Page page, TransactionId oldestxmin)
+{
+	AssertMacro(TransactionIdIsNormal(oldestxmin));
+	return ( 
+		TransactionIdIsValid(((PageHeader_04) page)->pd_prune_xid) && 
+		TransactionIdPrecedes(((PageHeader_04) page)->pd_prune_xid, oldestxmin) );
+}
+
+TransactionId PageGetPrunable(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : return ((PageHeader_04) page)->pd_prune_xid;
+	}
+	elog(PANIC, "PageGetPrunable is not supported on page layout version %i",
+		PageGetPageLayoutVersion(page));	
+}
+
+void PageSetPrunable(Page page, TransactionId xid)
+{
+	Assert(TransactionIdIsNormal(xid));
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : if (!TransactionIdIsValid(((PageHeader_04) (page))->pd_prune_xid) ||
+				TransactionIdPrecedes(xid, ((PageHeader_04) (page))->pd_prune_xid)) 
+				((PageHeader_04) (page))->pd_prune_xid = (xid); 
+				break;
+		default: elog(PANIC, "PageSetPrunable is not supported on page layout version %i",
+				PageGetPageLayoutVersion(page));
+	}
+}
+
+void PageClearPrunable(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : ((PageHeader_04) page)->pd_prune_xid = InvalidTransactionId;
+				break;
+		default: elog(PANIC, "PageClearPrunable is not supported on page layout version %i",
+				PageGetPageLayoutVersion(page));		
+	}
+}
+
+bool PageIsComprimable(Page page)
+{
+	switch ( PageGetPageLayoutVersion(page) )
+	{
+		case 4 : { 
+					PageHeader_04 ph = (PageHeader_04) page;
+					return(ph->pd_lower >= SizeOfPageHeaderData &&
+						ph->pd_upper > ph->pd_lower &&
+						ph->pd_upper <= BLCKSZ);
+				  }
+		default: elog(PANIC, "IsComprimable is not supported on page layout version %i",
+				PageGetPageLayoutVersion(page));		
+	}
+}
diff -r 879ef18ad9cb -r 3e71cf34dced src/include/access/gin.h
--- a/src/include/access/gin.h	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/include/access/gin.h	Mon Aug 11 15:58:27 2008 +0200
@@ -246,7 +246,6 @@
 extern Datum *extractEntriesS(GinState *ginstate, OffsetNumber attnum, Datum value,
 				int32 *nentries, bool *needUnique);
 extern Datum *extractEntriesSU(GinState *ginstate, OffsetNumber attnum, Datum value, int32 *nentries);
-extern Page GinPageGetCopyPage(Page page);
 
 extern Datum gin_index_getattr(GinState *ginstate, IndexTuple tuple);
 extern OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple);
diff -r 879ef18ad9cb -r 3e71cf34dced src/include/access/hash.h
--- a/src/include/access/hash.h	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/include/access/hash.h	Mon Aug 11 15:58:27 2008 +0200
@@ -138,7 +138,7 @@
 
 typedef struct HashMetaPageData
 {
-	PageHeaderData hashm_phdr;	/* pad for page header (do not use) */
+	PageHeaderData_04 hashm_phdr;  /* pad for page header (do not use) */
 	uint32		hashm_magic;	/* magic no. for hash tables */
 	uint32		hashm_version;	/* version ID */
 	double		hashm_ntuples;	/* number of tuples stored in the table */
@@ -191,8 +191,20 @@
 #define BMPGSZ_BIT(metap)		((metap)->hashm_bmsize << BYTE_TO_BIT)
 #define BMPG_SHIFT(metap)		((metap)->hashm_bmshift)
 #define BMPG_MASK(metap)		(BMPGSZ_BIT(metap) - 1)
-#define HashPageGetBitmap(pg) \
-	((uint32 *) (((char *) (pg)) + MAXALIGN(sizeof(PageHeaderData))))
+/*
+ * Note: Hash bitmap and metapage could be placed on MAXALIGN(SizeOfPageHeaderData),
+ * but for backward compatibility (in-place-upgrade) we waste ~4 bytes.
+ */
+#define HashPageGetBitmap(page) \
+	((uint32 *) (((char *) (page)) + MAXALIGN(SizeOfPageHeaderData + sizeof(ItemIdData) )))
+
+#define HashGetMaxBitmapSize(page) \
+	( PageGetPageSize((Page) page)- \
+	( MAXALIGN(SizeOfPageHeaderData + sizeof(ItemIdData)) + \
+      MAXALIGN(sizeof(HashPageOpaqueData))) )
+
+#define HashPageGetMeta(page) \
+ ((HashMetaPage)(page))  /* TODO check if page has layout 4 */
 
 /*
  * The number of bits in an ovflpage bitmap word.
diff -r 879ef18ad9cb -r 3e71cf34dced src/include/storage/bufpage.h
--- a/src/include/storage/bufpage.h	Tue Aug 05 21:28:29 2008 +0000
+++ b/src/include/storage/bufpage.h	Mon Aug 11 15:58:27 2008 +0200
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/bufpage.h,v 1.82 2008/07/13 21:50:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/bufpage.h,v 1.78 2008/05/12 00:00:53 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -119,7 +119,7 @@
  * On the high end, we can only support pages up to 32KB because lp_off/lp_len
  * are 15 bits.
  */
-typedef struct PageHeaderData
+typedef struct PageHeaderData_04
 {
 	/* XXX LSN is member of *any* block, not only page-organized ones */
 	XLogRecPtr	pd_lsn;			/* LSN: next byte after last byte of xlog
@@ -133,9 +133,9 @@
 	uint16		pd_pagesize_version;
 	TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */
 	ItemIdData	pd_linp[1];		/* beginning of line pointer array */
-} PageHeaderData;
+} PageHeaderData_04;
 
-typedef PageHeaderData *PageHeader;
+typedef PageHeaderData_04 *PageHeader_04;
 
 /*
  * pd_flags contains the following flag bits.  Undefined bits are initialized
@@ -179,40 +179,22 @@
 #define PageIsValid(page) PointerIsValid(page)
 
 /*
- * line pointer(s) do not count as part of header
+ * line pointer does not count as part of header
  */
-#define SizeOfPageHeaderData (offsetof(PageHeaderData, pd_linp))
+#define SizeOfPageHeaderData (offsetof(PageHeaderData_04, pd_linp[0]))
 
 /*
  * PageIsEmpty
  *		returns true iff no itemid has been allocated on the page
  */
 #define PageIsEmpty(page) \
-	(((PageHeader) (page))->pd_lower <= SizeOfPageHeaderData)
+	(((PageHeader_04) (page))->pd_lower <= SizeOfPageHeaderData)
 
 /*
  * PageIsNew
  *		returns true iff page has not been initialized (by PageInit)
  */
-#define PageIsNew(page) (((PageHeader) (page))->pd_upper == 0)
-
-/*
- * PageGetItemId
- *		Returns an item identifier of a page.
- */
-#define PageGetItemId(page, offsetNumber) \
-	((ItemId) (&((PageHeader) (page))->pd_linp[(offsetNumber) - 1]))
-
-/*
- * PageGetContents
- *		To be used in case the page does not contain item pointers.
- *
- * Note: prior to 8.3 this was not guaranteed to yield a MAXALIGN'd result.
- * Now it is.  Beware of old code that might think the offset to the contents
- * is just SizeOfPageHeaderData rather than MAXALIGN(SizeOfPageHeaderData).
- */
-#define PageGetContents(page) \
-	((char *) (page) + MAXALIGN(SizeOfPageHeaderData))
+#define PageIsNew(page) (((PageHeader_04) (page))->pd_upper == 0)
 
 /* ----------------
  *		macros to access page size info
@@ -234,14 +216,14 @@
  * however, it can be called on a page that is not stored in a buffer.
  */
 #define PageGetPageSize(page) \
-	((Size) (((PageHeader) (page))->pd_pagesize_version & (uint16) 0xFF00))
+	((Size) (((PageHeader_04) (page))->pd_pagesize_version & (uint16) 0xFF00))
 
 /*
  * PageGetPageLayoutVersion
  *		Returns the page layout version of a page.
  */
 #define PageGetPageLayoutVersion(page) \
-	(((PageHeader) (page))->pd_pagesize_version & 0x00FF)
+	(((PageHeader_04) (page))->pd_pagesize_version & 0x00FF)
 
 /*
  * PageSetPageSizeAndVersion
@@ -254,120 +236,64 @@
 ( \
 	AssertMacro(((size) & 0xFF00) == (size)), \
 	AssertMacro(((version) & 0x00FF) == (version)), \
-	((PageHeader) (page))->pd_pagesize_version = (size) | (version) \
+	((PageHeader_04) (page))->pd_pagesize_version = (size) | (version) \
 )
 
-/* ----------------
- *		page special data macros
- * ----------------
- */
-/*
- * PageGetSpecialSize
- *		Returns size of special space on a page.
- */
-#define PageGetSpecialSize(page) \
-	((uint16) (PageGetPageSize(page) - ((PageHeader)(page))->pd_special))
-
-/*
- * PageGetSpecialPointer
- *		Returns pointer to special space on a page.
- */
-#define PageGetSpecialPointer(page) \
-( \
-	AssertMacro(PageIsValid(page)), \
-	(char *) ((char *) (page) + ((PageHeader) (page))->pd_special) \
-)
-
-/*
- * PageGetItem
- *		Retrieves an item on the given page.
- *
- * Note:
- *		This does not change the status of any of the resources passed.
- *		The semantics may change in the future.
- */
-#define PageGetItem(page, itemId) \
-( \
-	AssertMacro(PageIsValid(page)), \
-	AssertMacro(ItemIdHasStorage(itemId)), \
-	(Item)(((char *)(page)) + ItemIdGetOffset(itemId)) \
-)
-
-/*
- * PageGetMaxOffsetNumber
- *		Returns the maximum offset number used by the given page.
- *		Since offset numbers are 1-based, this is also the number
- *		of items on the page.
- *
- *		NOTE: if the page is not initialized (pd_lower == 0), we must
- *		return zero to ensure sane behavior.  Accept double evaluation
- *		of the argument so that we can ensure this.
- */
-#define PageGetMaxOffsetNumber(page) \
-	(((PageHeader) (page))->pd_lower <= SizeOfPageHeaderData ? 0 : \
-	 ((((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 = (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)
-
-#define PageIsFull(page) \
-	(((PageHeader) (page))->pd_flags & PD_PAGE_FULL)
-#define PageSetFull(page) \
-	(((PageHeader) (page))->pd_flags |= PD_PAGE_FULL)
-#define PageClearFull(page) \
-	(((PageHeader) (page))->pd_flags &= ~PD_PAGE_FULL)
-
-#define PageIsPrunable(page, oldestxmin) \
-( \
-	AssertMacro(TransactionIdIsNormal(oldestxmin)), \
-	TransactionIdIsValid(((PageHeader) (page))->pd_prune_xid) && \
-	TransactionIdPrecedes(((PageHeader) (page))->pd_prune_xid, oldestxmin) \
-)
-#define PageSetPrunable(page, xid) \
-do { \
-	Assert(TransactionIdIsNormal(xid)); \
-	if (!TransactionIdIsValid(((PageHeader) (page))->pd_prune_xid) || \
-		TransactionIdPrecedes(xid, ((PageHeader) (page))->pd_prune_xid)) \
-		((PageHeader) (page))->pd_prune_xid = (xid); \
-} while (0)
-#define PageClearPrunable(page) \
-	(((PageHeader) (page))->pd_prune_xid = InvalidTransactionId)
 
 
 /* ----------------------------------------------------------------
  *		extern declarations
  * ----------------------------------------------------------------
  */
+extern Pointer PageGetContents(Page page);
+extern Pointer PageGetSpecialPointer(Page page);
+extern Pointer PageGetUpperPointer(Page page);
 
-extern void PageInit(Page page, Size pageSize, Size specialSize);
-extern bool PageHeaderIsValid(PageHeader page);
-extern OffsetNumber PageAddItem(Page page, Item item, Size size,
-			OffsetNumber offsetNumber, bool overwrite, bool is_heap);
-extern Page PageGetTempPage(Page page, Size specialSize);
+extern ItemId PageGetItemId(Page page, OffsetNumber offsetNumber);
+extern Item PageGetItem(Page page, ItemId itemId);
+extern int PageGetMaxOffsetNumber(Page page);
+
+extern XLogRecPtr PageGetLSN(Page page);
+extern void PageSetLSN(Page page, XLogRecPtr lsn);
+extern TimeLineID PageGetTLI(Page page);
+extern void PageSetTLI(Page page, TimeLineID tli);
+
+extern bool PageHasFreeLinePointers(Page page);
+extern void PageSetHasFreeLinePointers(Page page);
+extern void PageClearHasFreeLinePointers(Page page);
+extern bool PageIsFull(Page page);
+extern void PageSetFull(Page page);
+extern void PageClearFull(Page page);
+extern bool PageIsPrunable(Page page, TransactionId oldestxmin);
+extern void PageSetPrunable(Page page, TransactionId xid);
+extern TransactionId PageGetPrunable(Page page);
+extern void PageClearPrunable(Page page);
+extern bool PageIsComprimable(Page page); 
+
+extern void PageReserveLinp(Page page);
+extern void PageReleaseLinp(Page page);
+
+extern LocationIndex PageGetLower(Page page);
+extern LocationIndex PageGetUpper(Page page);
+extern LocationIndex PageGetSpecial(Page page);
+extern void PageSetLower(Page page, LocationIndex lower);
+extern void PageSetUpper(Page page, LocationIndex lower);
+
+extern Page PageGetTempPage(Page page, bool copy);
+extern Page PageGetTempPageCopySpecial(Page page);
 extern void PageRestoreTempPage(Page tempPage, Page oldPage);
-extern void PageRepairFragmentation(Page page);
+
 extern Size PageGetFreeSpace(Page page);
 extern Size PageGetExactFreeSpace(Page page);
 extern Size PageGetHeapFreeSpace(Page page);
+extern Size PageGetSpecialSize(Page page);
+extern Size PageGetDataSize(Page page);
+
+extern void PageInit(Page page, Size pageSize, Size specialSize);
+extern bool PageLayoutIsValid(Page page);
+extern OffsetNumber PageAddItem(Page page, Item item, Size size,
+			OffsetNumber offsetNumber, bool overwrite, bool is_heap);
+extern void PageRepairFragmentation(Page page);
 extern void PageIndexTupleDelete(Page page, OffsetNumber offset);
 extern void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems);
 
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to