WIP: New Page API - Mailing list pgsql-hackers
From | Zdenek Kotala |
---|---|
Subject | WIP: New Page API |
Date | |
Msg-id | 48A06455.3080809@sun.com Whole thread Raw |
Responses |
Re: WIP: New Page API
(Markus Wanner <markus@bluegap.ch>)
|
List | pgsql-hackers |
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);
pgsql-hackers by date: