LCOV - code coverage report
Current view: top level - src/include/storage - bufpage.h (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 57 57 100.0 %
Date: 2025-02-22 07:14:56 Functions: 23 23 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * bufpage.h
       4             :  *    Standard POSTGRES buffer page definitions.
       5             :  *
       6             :  *
       7             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
       8             :  * Portions Copyright (c) 1994, Regents of the University of California
       9             :  *
      10             :  * src/include/storage/bufpage.h
      11             :  *
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : #ifndef BUFPAGE_H
      15             : #define BUFPAGE_H
      16             : 
      17             : #include "access/xlogdefs.h"
      18             : #include "storage/block.h"
      19             : #include "storage/item.h"
      20             : #include "storage/off.h"
      21             : 
      22             : /* GUC variable */
      23             : extern PGDLLIMPORT bool ignore_checksum_failure;
      24             : 
      25             : /*
      26             :  * A postgres disk page is an abstraction layered on top of a postgres
      27             :  * disk block (which is simply a unit of i/o, see block.h).
      28             :  *
      29             :  * specifically, while a disk block can be unformatted, a postgres
      30             :  * disk page is always a slotted page of the form:
      31             :  *
      32             :  * +----------------+---------------------------------+
      33             :  * | PageHeaderData | linp1 linp2 linp3 ...           |
      34             :  * +-----------+----+---------------------------------+
      35             :  * | ... linpN |                                      |
      36             :  * +-----------+--------------------------------------+
      37             :  * |           ^ pd_lower                             |
      38             :  * |                                                  |
      39             :  * |             v pd_upper                           |
      40             :  * +-------------+------------------------------------+
      41             :  * |             | tupleN ...                         |
      42             :  * +-------------+------------------+-----------------+
      43             :  * |       ... tuple3 tuple2 tuple1 | "special space" |
      44             :  * +--------------------------------+-----------------+
      45             :  *                                  ^ pd_special
      46             :  *
      47             :  * a page is full when nothing can be added between pd_lower and
      48             :  * pd_upper.
      49             :  *
      50             :  * all blocks written out by an access method must be disk pages.
      51             :  *
      52             :  * EXCEPTIONS:
      53             :  *
      54             :  * obviously, a page is not formatted before it is initialized by
      55             :  * a call to PageInit.
      56             :  *
      57             :  * NOTES:
      58             :  *
      59             :  * linp1..N form an ItemId (line pointer) array.  ItemPointers point
      60             :  * to a physical block number and a logical offset (line pointer
      61             :  * number) within that block/page.  Note that OffsetNumbers
      62             :  * conventionally start at 1, not 0.
      63             :  *
      64             :  * tuple1..N are added "backwards" on the page.  Since an ItemPointer
      65             :  * offset is used to access an ItemId entry rather than an actual
      66             :  * byte-offset position, tuples can be physically shuffled on a page
      67             :  * whenever the need arises.  This indirection also keeps crash recovery
      68             :  * relatively simple, because the low-level details of page space
      69             :  * management can be controlled by standard buffer page code during
      70             :  * logging, and during recovery.
      71             :  *
      72             :  * AM-generic per-page information is kept in PageHeaderData.
      73             :  *
      74             :  * AM-specific per-page data (if any) is kept in the area marked "special
      75             :  * space"; each AM has an "opaque" structure defined somewhere that is
      76             :  * stored as the page trailer.  An access method should always
      77             :  * initialize its pages with PageInit and then set its own opaque
      78             :  * fields.
      79             :  */
      80             : 
      81             : typedef char PageData;
      82             : typedef PageData *Page;
      83             : 
      84             : 
      85             : /*
      86             :  * location (byte offset) within a page.
      87             :  *
      88             :  * note that this is actually limited to 2^15 because we have limited
      89             :  * ItemIdData.lp_off and ItemIdData.lp_len to 15 bits (see itemid.h).
      90             :  */
      91             : typedef uint16 LocationIndex;
      92             : 
      93             : 
      94             : /*
      95             :  * For historical reasons, the 64-bit LSN value is stored as two 32-bit
      96             :  * values.
      97             :  */
      98             : typedef struct
      99             : {
     100             :     uint32      xlogid;         /* high bits */
     101             :     uint32      xrecoff;        /* low bits */
     102             : } PageXLogRecPtr;
     103             : 
     104             : static inline XLogRecPtr
     105    59240928 : PageXLogRecPtrGet(PageXLogRecPtr val)
     106             : {
     107    59240928 :     return (uint64) val.xlogid << 32 | val.xrecoff;
     108             : }
     109             : 
     110             : #define PageXLogRecPtrSet(ptr, lsn) \
     111             :     ((ptr).xlogid = (uint32) ((lsn) >> 32), (ptr).xrecoff = (uint32) (lsn))
     112             : 
     113             : /*
     114             :  * disk page organization
     115             :  *
     116             :  * space management information generic to any page
     117             :  *
     118             :  *      pd_lsn      - identifies xlog record for last change to this page.
     119             :  *      pd_checksum - page checksum, if set.
     120             :  *      pd_flags    - flag bits.
     121             :  *      pd_lower    - offset to start of free space.
     122             :  *      pd_upper    - offset to end of free space.
     123             :  *      pd_special  - offset to start of special space.
     124             :  *      pd_pagesize_version - size in bytes and page layout version number.
     125             :  *      pd_prune_xid - oldest XID among potentially prunable tuples on page.
     126             :  *
     127             :  * The LSN is used by the buffer manager to enforce the basic rule of WAL:
     128             :  * "thou shalt write xlog before data".  A dirty buffer cannot be dumped
     129             :  * to disk until xlog has been flushed at least as far as the page's LSN.
     130             :  *
     131             :  * pd_checksum stores the page checksum, if it has been set for this page;
     132             :  * zero is a valid value for a checksum. If a checksum is not in use then
     133             :  * we leave the field unset. This will typically mean the field is zero
     134             :  * though non-zero values may also be present if databases have been
     135             :  * pg_upgraded from releases prior to 9.3, when the same byte offset was
     136             :  * used to store the current timelineid when the page was last updated.
     137             :  * Note that there is no indication on a page as to whether the checksum
     138             :  * is valid or not, a deliberate design choice which avoids the problem
     139             :  * of relying on the page contents to decide whether to verify it. Hence
     140             :  * there are no flag bits relating to checksums.
     141             :  *
     142             :  * pd_prune_xid is a hint field that helps determine whether pruning will be
     143             :  * useful.  It is currently unused in index pages.
     144             :  *
     145             :  * The page version number and page size are packed together into a single
     146             :  * uint16 field.  This is for historical reasons: before PostgreSQL 7.3,
     147             :  * there was no concept of a page version number, and doing it this way
     148             :  * lets us pretend that pre-7.3 databases have page version number zero.
     149             :  * We constrain page sizes to be multiples of 256, leaving the low eight
     150             :  * bits available for a version number.
     151             :  *
     152             :  * Minimum possible page size is perhaps 64B to fit page header, opaque space
     153             :  * and a minimal tuple; of course, in reality you want it much bigger, so
     154             :  * the constraint on pagesize mod 256 is not an important restriction.
     155             :  * On the high end, we can only support pages up to 32KB because lp_off/lp_len
     156             :  * are 15 bits.
     157             :  */
     158             : 
     159             : typedef struct PageHeaderData
     160             : {
     161             :     /* XXX LSN is member of *any* block, not only page-organized ones */
     162             :     PageXLogRecPtr pd_lsn;      /* LSN: next byte after last byte of xlog
     163             :                                  * record for last change to this page */
     164             :     uint16      pd_checksum;    /* checksum */
     165             :     uint16      pd_flags;       /* flag bits, see below */
     166             :     LocationIndex pd_lower;     /* offset to start of free space */
     167             :     LocationIndex pd_upper;     /* offset to end of free space */
     168             :     LocationIndex pd_special;   /* offset to start of special space */
     169             :     uint16      pd_pagesize_version;
     170             :     TransactionId pd_prune_xid; /* oldest prunable XID, or zero if none */
     171             :     ItemIdData  pd_linp[FLEXIBLE_ARRAY_MEMBER]; /* line pointer array */
     172             : } PageHeaderData;
     173             : 
     174             : typedef PageHeaderData *PageHeader;
     175             : 
     176             : /*
     177             :  * pd_flags contains the following flag bits.  Undefined bits are initialized
     178             :  * to zero and may be used in the future.
     179             :  *
     180             :  * PD_HAS_FREE_LINES is set if there are any LP_UNUSED line pointers before
     181             :  * pd_lower.  This should be considered a hint rather than the truth, since
     182             :  * changes to it are not WAL-logged.
     183             :  *
     184             :  * PD_PAGE_FULL is set if an UPDATE doesn't find enough free space in the
     185             :  * page for its new tuple version; this suggests that a prune is needed.
     186             :  * Again, this is just a hint.
     187             :  */
     188             : #define PD_HAS_FREE_LINES   0x0001  /* are there any unused line pointers? */
     189             : #define PD_PAGE_FULL        0x0002  /* not enough free space for new tuple? */
     190             : #define PD_ALL_VISIBLE      0x0004  /* all tuples on page are visible to
     191             :                                      * everyone */
     192             : 
     193             : #define PD_VALID_FLAG_BITS  0x0007  /* OR of all valid pd_flags bits */
     194             : 
     195             : /*
     196             :  * Page layout version number 0 is for pre-7.3 Postgres releases.
     197             :  * Releases 7.3 and 7.4 use 1, denoting a new HeapTupleHeader layout.
     198             :  * Release 8.0 uses 2; it changed the HeapTupleHeader layout again.
     199             :  * Release 8.1 uses 3; it redefined HeapTupleHeader infomask bits.
     200             :  * Release 8.3 uses 4; it changed the HeapTupleHeader layout again, and
     201             :  *      added the pd_flags field (by stealing some bits from pd_tli),
     202             :  *      as well as adding the pd_prune_xid field (which enlarges the header).
     203             :  *
     204             :  * As of Release 9.3, the checksum version must also be considered when
     205             :  * handling pages.
     206             :  */
     207             : #define PG_PAGE_LAYOUT_VERSION      4
     208             : #define PG_DATA_CHECKSUM_VERSION    1
     209             : 
     210             : /* ----------------------------------------------------------------
     211             :  *                      page support functions
     212             :  * ----------------------------------------------------------------
     213             :  */
     214             : 
     215             : /*
     216             :  * line pointer(s) do not count as part of header
     217             :  */
     218             : #define SizeOfPageHeaderData (offsetof(PageHeaderData, pd_linp))
     219             : 
     220             : /*
     221             :  * PageIsEmpty
     222             :  *      returns true iff no itemid has been allocated on the page
     223             :  */
     224             : static inline bool
     225     3137916 : PageIsEmpty(const PageData *page)
     226             : {
     227     3137916 :     return ((const PageHeaderData *) page)->pd_lower <= SizeOfPageHeaderData;
     228             : }
     229             : 
     230             : /*
     231             :  * PageIsNew
     232             :  *      returns true iff page has not been initialized (by PageInit)
     233             :  */
     234             : static inline bool
     235    75829928 : PageIsNew(const PageData *page)
     236             : {
     237    75829928 :     return ((const PageHeaderData *) page)->pd_upper == 0;
     238             : }
     239             : 
     240             : /*
     241             :  * PageGetItemId
     242             :  *      Returns an item identifier of a page.
     243             :  */
     244             : static inline ItemId
     245  2369220922 : PageGetItemId(Page page, OffsetNumber offsetNumber)
     246             : {
     247  2369220922 :     return &((PageHeader) page)->pd_linp[offsetNumber - 1];
     248             : }
     249             : 
     250             : /*
     251             :  * PageGetContents
     252             :  *      To be used in cases where the page does not contain line pointers.
     253             :  *
     254             :  * Note: prior to 8.3 this was not guaranteed to yield a MAXALIGN'd result.
     255             :  * Now it is.  Beware of old code that might think the offset to the contents
     256             :  * is just SizeOfPageHeaderData rather than MAXALIGN(SizeOfPageHeaderData).
     257             :  */
     258             : static inline char *
     259    44937542 : PageGetContents(Page page)
     260             : {
     261    44937542 :     return (char *) page + MAXALIGN(SizeOfPageHeaderData);
     262             : }
     263             : 
     264             : /* ----------------
     265             :  *      functions to access page size info
     266             :  * ----------------
     267             :  */
     268             : 
     269             : /*
     270             :  * PageGetPageSize
     271             :  *      Returns the page size of a page.
     272             :  *
     273             :  * this can only be called on a formatted page (unlike
     274             :  * BufferGetPageSize, which can be called on an unformatted page).
     275             :  * however, it can be called on a page that is not stored in a buffer.
     276             :  */
     277             : static inline Size
     278    67987100 : PageGetPageSize(const PageData *page)
     279             : {
     280    67987100 :     return (Size) (((const PageHeaderData *) page)->pd_pagesize_version & (uint16) 0xFF00);
     281             : }
     282             : 
     283             : /*
     284             :  * PageGetPageLayoutVersion
     285             :  *      Returns the page layout version of a page.
     286             :  */
     287             : static inline uint8
     288           6 : PageGetPageLayoutVersion(const PageData *page)
     289             : {
     290           6 :     return (((const PageHeaderData *) page)->pd_pagesize_version & 0x00FF);
     291             : }
     292             : 
     293             : /*
     294             :  * PageSetPageSizeAndVersion
     295             :  *      Sets the page size and page layout version number of a page.
     296             :  *
     297             :  * We could support setting these two values separately, but there's
     298             :  * no real need for it at the moment.
     299             :  */
     300             : static inline void
     301      662244 : PageSetPageSizeAndVersion(Page page, Size size, uint8 version)
     302             : {
     303             :     Assert((size & 0xFF00) == size);
     304             :     Assert((version & 0x00FF) == version);
     305             : 
     306      662244 :     ((PageHeader) page)->pd_pagesize_version = size | version;
     307      662244 : }
     308             : 
     309             : /* ----------------
     310             :  *      page special data functions
     311             :  * ----------------
     312             :  */
     313             : /*
     314             :  * PageGetSpecialSize
     315             :  *      Returns size of special space on a page.
     316             :  */
     317             : static inline uint16
     318    44902586 : PageGetSpecialSize(const PageData *page)
     319             : {
     320    44902586 :     return (PageGetPageSize(page) - ((const PageHeaderData *) page)->pd_special);
     321             : }
     322             : 
     323             : /*
     324             :  * Using assertions, validate that the page special pointer is OK.
     325             :  *
     326             :  * This is intended to catch use of the pointer before page initialization.
     327             :  */
     328             : static inline void
     329   510626342 : PageValidateSpecialPointer(const PageData *page)
     330             : {
     331             :     Assert(page);
     332             :     Assert(((const PageHeaderData *) page)->pd_special <= BLCKSZ);
     333             :     Assert(((const PageHeaderData *) page)->pd_special >= SizeOfPageHeaderData);
     334   510626342 : }
     335             : 
     336             : /*
     337             :  * PageGetSpecialPointer
     338             :  *      Returns pointer to special space on a page.
     339             :  */
     340             : #define PageGetSpecialPointer(page) \
     341             : ( \
     342             :     PageValidateSpecialPointer(page), \
     343             :     ((page) + ((PageHeader) (page))->pd_special) \
     344             : )
     345             : 
     346             : /*
     347             :  * PageGetItem
     348             :  *      Retrieves an item on the given page.
     349             :  *
     350             :  * Note:
     351             :  *      This does not change the status of any of the resources passed.
     352             :  *      The semantics may change in the future.
     353             :  */
     354             : static inline Item
     355  1103114338 : PageGetItem(const PageData *page, const ItemIdData *itemId)
     356             : {
     357             :     Assert(page);
     358             :     Assert(ItemIdHasStorage(itemId));
     359             : 
     360  1103114338 :     return (Item) (((const char *) page) + ItemIdGetOffset(itemId));
     361             : }
     362             : 
     363             : /*
     364             :  * PageGetMaxOffsetNumber
     365             :  *      Returns the maximum offset number used by the given page.
     366             :  *      Since offset numbers are 1-based, this is also the number
     367             :  *      of items on the page.
     368             :  *
     369             :  *      NOTE: if the page is not initialized (pd_lower == 0), we must
     370             :  *      return zero to ensure sane behavior.
     371             :  */
     372             : static inline OffsetNumber
     373   715945538 : PageGetMaxOffsetNumber(const PageData *page)
     374             : {
     375   715945538 :     const PageHeaderData *pageheader = (const PageHeaderData *) page;
     376             : 
     377   715945538 :     if (pageheader->pd_lower <= SizeOfPageHeaderData)
     378      907146 :         return 0;
     379             :     else
     380   715038392 :         return (pageheader->pd_lower - SizeOfPageHeaderData) / sizeof(ItemIdData);
     381             : }
     382             : 
     383             : /*
     384             :  * Additional functions for access to page headers.
     385             :  */
     386             : static inline XLogRecPtr
     387    57079414 : PageGetLSN(const PageData *page)
     388             : {
     389    57079414 :     return PageXLogRecPtrGet(((const PageHeaderData *) page)->pd_lsn);
     390             : }
     391             : static inline void
     392    35871426 : PageSetLSN(Page page, XLogRecPtr lsn)
     393             : {
     394    35871426 :     PageXLogRecPtrSet(((PageHeader) page)->pd_lsn, lsn);
     395    35871426 : }
     396             : 
     397             : static inline bool
     398    22288306 : PageHasFreeLinePointers(const PageData *page)
     399             : {
     400    22288306 :     return ((const PageHeaderData *) page)->pd_flags & PD_HAS_FREE_LINES;
     401             : }
     402             : static inline void
     403       47306 : PageSetHasFreeLinePointers(Page page)
     404             : {
     405       47306 :     ((PageHeader) page)->pd_flags |= PD_HAS_FREE_LINES;
     406       47306 : }
     407             : static inline void
     408     9098160 : PageClearHasFreeLinePointers(Page page)
     409             : {
     410     9098160 :     ((PageHeader) page)->pd_flags &= ~PD_HAS_FREE_LINES;
     411     9098160 : }
     412             : 
     413             : static inline bool
     414     3347590 : PageIsFull(const PageData *page)
     415             : {
     416     3347590 :     return ((const PageHeaderData *) page)->pd_flags & PD_PAGE_FULL;
     417             : }
     418             : static inline void
     419      284382 : PageSetFull(Page page)
     420             : {
     421      284382 :     ((PageHeader) page)->pd_flags |= PD_PAGE_FULL;
     422      284382 : }
     423             : static inline void
     424     9095716 : PageClearFull(Page page)
     425             : {
     426     9095716 :     ((PageHeader) page)->pd_flags &= ~PD_PAGE_FULL;
     427     9095716 : }
     428             : 
     429             : static inline bool
     430    67030240 : PageIsAllVisible(const PageData *page)
     431             : {
     432    67030240 :     return ((const PageHeaderData *) page)->pd_flags & PD_ALL_VISIBLE;
     433             : }
     434             : static inline void
     435       87358 : PageSetAllVisible(Page page)
     436             : {
     437       87358 :     ((PageHeader) page)->pd_flags |= PD_ALL_VISIBLE;
     438       87358 : }
     439             : static inline void
     440     9023274 : PageClearAllVisible(Page page)
     441             : {
     442     9023274 :     ((PageHeader) page)->pd_flags &= ~PD_ALL_VISIBLE;
     443     9023274 : }
     444             : 
     445             : /*
     446             :  * These two require "access/transam.h", so left as macros.
     447             :  */
     448             : #define PageSetPrunable(page, xid) \
     449             : do { \
     450             :     Assert(TransactionIdIsNormal(xid)); \
     451             :     if (!TransactionIdIsValid(((PageHeader) (page))->pd_prune_xid) || \
     452             :         TransactionIdPrecedes(xid, ((PageHeader) (page))->pd_prune_xid)) \
     453             :         ((PageHeader) (page))->pd_prune_xid = (xid); \
     454             : } while (0)
     455             : #define PageClearPrunable(page) \
     456             :     (((PageHeader) (page))->pd_prune_xid = InvalidTransactionId)
     457             : 
     458             : 
     459             : /* ----------------------------------------------------------------
     460             :  *      extern declarations
     461             :  * ----------------------------------------------------------------
     462             :  */
     463             : 
     464             : /* flags for PageAddItemExtended() */
     465             : #define PAI_OVERWRITE           (1 << 0)
     466             : #define PAI_IS_HEAP             (1 << 1)
     467             : 
     468             : /* flags for PageIsVerifiedExtended() */
     469             : #define PIV_LOG_WARNING         (1 << 0)
     470             : #define PIV_REPORT_STAT         (1 << 1)
     471             : 
     472             : #define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap) \
     473             :     PageAddItemExtended(page, item, size, offsetNumber, \
     474             :                         ((overwrite) ? PAI_OVERWRITE : 0) | \
     475             :                         ((is_heap) ? PAI_IS_HEAP : 0))
     476             : 
     477             : #define PageIsVerified(page, blkno) \
     478             :     PageIsVerifiedExtended(page, blkno, \
     479             :                            PIV_LOG_WARNING | PIV_REPORT_STAT)
     480             : 
     481             : /*
     482             :  * Check that BLCKSZ is a multiple of sizeof(size_t).  In
     483             :  * PageIsVerifiedExtended(), it is much faster to check if a page is
     484             :  * full of zeroes using the native word size.  Note that this assertion
     485             :  * is kept within a header to make sure that StaticAssertDecl() works
     486             :  * across various combinations of platforms and compilers.
     487             :  */
     488             : StaticAssertDecl(BLCKSZ == ((BLCKSZ / sizeof(size_t)) * sizeof(size_t)),
     489             :                  "BLCKSZ has to be a multiple of sizeof(size_t)");
     490             : 
     491             : extern void PageInit(Page page, Size pageSize, Size specialSize);
     492             : extern bool PageIsVerifiedExtended(PageData *page, BlockNumber blkno, int flags);
     493             : extern OffsetNumber PageAddItemExtended(Page page, Item item, Size size,
     494             :                                         OffsetNumber offsetNumber, int flags);
     495             : extern Page PageGetTempPage(const PageData *page);
     496             : extern Page PageGetTempPageCopy(const PageData *page);
     497             : extern Page PageGetTempPageCopySpecial(const PageData *page);
     498             : extern void PageRestoreTempPage(Page tempPage, Page oldPage);
     499             : extern void PageRepairFragmentation(Page page);
     500             : extern void PageTruncateLinePointerArray(Page page);
     501             : extern Size PageGetFreeSpace(const PageData *page);
     502             : extern Size PageGetFreeSpaceForMultipleTuples(const PageData *page, int ntups);
     503             : extern Size PageGetExactFreeSpace(const PageData *page);
     504             : extern Size PageGetHeapFreeSpace(const PageData *page);
     505             : extern void PageIndexTupleDelete(Page page, OffsetNumber offnum);
     506             : extern void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems);
     507             : extern void PageIndexTupleDeleteNoCompact(Page page, OffsetNumber offnum);
     508             : extern bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum,
     509             :                                     Item newtup, Size newsize);
     510             : extern char *PageSetChecksumCopy(Page page, BlockNumber blkno);
     511             : extern void PageSetChecksumInplace(Page page, BlockNumber blkno);
     512             : 
     513             : #endif                          /* BUFPAGE_H */

Generated by: LCOV version 1.14