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