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
234/* ----------------------------------------------------------------
235 * page support functions
236 * ----------------------------------------------------------------
237 */
238
239/*
240 * line pointer(s) do not count as part of header
241 */
242#define SizeOfPageHeaderData (offsetof(PageHeaderData, pd_linp))
243
244/*
245 * PageIsEmpty
246 * returns true iff no itemid has been allocated on the page
247 */
248static inline bool
249PageIsEmpty(const PageData *page)
250{
251 return ((const PageHeaderData *) page)->pd_lower <= SizeOfPageHeaderData;
252}
253
254/*
255 * PageIsNew
256 * returns true iff page has not been initialized (by PageInit)
257 */
258static inline bool
259PageIsNew(const PageData *page)
260{
261 return ((const PageHeaderData *) page)->pd_upper == 0;
262}
263
264/*
265 * PageGetItemId
266 * Returns an item identifier of a page.
267 */
268static inline ItemId
270{
271 return &((PageHeader) page)->pd_linp[offsetNumber - 1];
272}
273
274/*
275 * PageGetContents
276 * To be used in cases where the page does not contain line pointers.
277 *
278 * Note: prior to 8.3 this was not guaranteed to yield a MAXALIGN'd result.
279 * Now it is. Beware of old code that might think the offset to the contents
280 * is just SizeOfPageHeaderData rather than MAXALIGN(SizeOfPageHeaderData).
281 */
282static inline char *
284{
285 return (char *) page + MAXALIGN(SizeOfPageHeaderData);
286}
287
288/* ----------------
289 * functions to access page size info
290 * ----------------
291 */
292
293/*
294 * PageGetPageSize
295 * Returns the page size of a page.
296 *
297 * this can only be called on a formatted page (unlike
298 * BufferGetPageSize, which can be called on an unformatted page).
299 * however, it can be called on a page that is not stored in a buffer.
300 */
301static inline Size
302PageGetPageSize(const PageData *page)
303{
304 return (Size) (((const PageHeaderData *) page)->pd_pagesize_version & (uint16) 0xFF00);
305}
306
307/*
308 * PageGetPageLayoutVersion
309 * Returns the page layout version of a page.
310 */
311static inline uint8
313{
314 return (((const PageHeaderData *) page)->pd_pagesize_version & 0x00FF);
315}
316
317/*
318 * PageSetPageSizeAndVersion
319 * Sets the page size and page layout version number of a page.
320 *
321 * We could support setting these two values separately, but there's
322 * no real need for it at the moment.
323 */
324static inline void
325PageSetPageSizeAndVersion(Page page, Size size, uint8 version)
326{
327 Assert((size & 0xFF00) == size);
328 Assert((version & 0x00FF) == version);
329
330 ((PageHeader) page)->pd_pagesize_version = size | version;
331}
332
333/* ----------------
334 * page special data functions
335 * ----------------
336 */
337/*
338 * PageGetSpecialSize
339 * Returns size of special space on a page.
340 */
341static inline uint16
342PageGetSpecialSize(const PageData *page)
343{
344 return (PageGetPageSize(page) - ((const PageHeaderData *) page)->pd_special);
345}
346
347/*
348 * Using assertions, validate that the page special pointer is OK.
349 *
350 * This is intended to catch use of the pointer before page initialization.
351 */
352static inline void
354{
355 Assert(page);
356 Assert(((const PageHeaderData *) page)->pd_special <= BLCKSZ);
357 Assert(((const PageHeaderData *) page)->pd_special >= SizeOfPageHeaderData);
358}
359
360/*
361 * PageGetSpecialPointer
362 * Returns pointer to special space on a page.
363 */
364#define PageGetSpecialPointer(page) \
365( \
366 PageValidateSpecialPointer(page), \
367 ((page) + ((PageHeader) (page))->pd_special) \
368)
369
370/*
371 * PageGetItem
372 * Retrieves an item on the given page.
373 *
374 * Note:
375 * This does not change the status of any of the resources passed.
376 * The semantics may change in the future.
377 */
378static inline void *
380{
381 Assert(page);
383
384 return (char *) page + ItemIdGetOffset(itemId);
385}
386
387/*
388 * PageGetMaxOffsetNumber
389 * Returns the maximum offset number used by the given page.
390 * Since offset numbers are 1-based, this is also the number
391 * of items on the page.
392 *
393 * NOTE: if the page is not initialized (pd_lower == 0), we must
394 * return zero to ensure sane behavior.
395 */
396static inline OffsetNumber
398{
399 const PageHeaderData *pageheader = (const PageHeaderData *) page;
400
401 if (pageheader->pd_lower <= SizeOfPageHeaderData)
402 return 0;
403 else
404 return (pageheader->pd_lower - SizeOfPageHeaderData) / sizeof(ItemIdData);
405}
406
407/*
408 * Additional functions for access to page headers.
409 */
410static inline XLogRecPtr
411PageGetLSN(const PageData *page)
412{
413 return PageXLogRecPtrGet(&((const PageHeaderData *) page)->pd_lsn);
414}
415
416static inline void
417PageSetLSN(Page page, XLogRecPtr lsn)
418{
419 PageXLogRecPtrSet(&((PageHeader) page)->pd_lsn, lsn);
420}
421
422static inline bool
424{
425 return ((const PageHeaderData *) page)->pd_flags & PD_HAS_FREE_LINES;
426}
427static inline void
429{
430 ((PageHeader) page)->pd_flags |= PD_HAS_FREE_LINES;
431}
432static inline void
434{
435 ((PageHeader) page)->pd_flags &= ~PD_HAS_FREE_LINES;
436}
437
438static inline bool
439PageIsFull(const PageData *page)
440{
441 return ((const PageHeaderData *) page)->pd_flags & PD_PAGE_FULL;
442}
443static inline void
444PageSetFull(Page page)
445{
446 ((PageHeader) page)->pd_flags |= PD_PAGE_FULL;
447}
448static inline void
450{
451 ((PageHeader) page)->pd_flags &= ~PD_PAGE_FULL;
452}
453
454static inline bool
455PageIsAllVisible(const PageData *page)
456{
457 return ((const PageHeaderData *) page)->pd_flags & PD_ALL_VISIBLE;
458}
459static inline void
461{
462 ((PageHeader) page)->pd_flags |= PD_ALL_VISIBLE;
463}
464static inline void
466{
467 ((PageHeader) page)->pd_flags &= ~PD_ALL_VISIBLE;
468}
469
470static inline TransactionId
471PageGetPruneXid(const PageData *page)
472{
473 return ((const PageHeaderData *) page)->pd_prune_xid;
474}
475
476/*
477 * These two require "access/transam.h", so left as macros.
478 */
479#define PageSetPrunable(page, xid) \
480do { \
481 Assert(TransactionIdIsNormal(xid)); \
482 if (!TransactionIdIsValid(((PageHeader) (page))->pd_prune_xid) || \
483 TransactionIdPrecedes(xid, ((PageHeader) (page))->pd_prune_xid)) \
484 ((PageHeader) (page))->pd_prune_xid = (xid); \
485} while (0)
486#define PageClearPrunable(page) \
487 (((PageHeader) (page))->pd_prune_xid = InvalidTransactionId)
488
489
490/* ----------------------------------------------------------------
491 * extern declarations
492 * ----------------------------------------------------------------
493 */
494
495/* flags for PageAddItemExtended() */
496#define PAI_OVERWRITE (1 << 0)
497#define PAI_IS_HEAP (1 << 1)
498
499/* flags for PageIsVerified() */
500#define PIV_LOG_WARNING (1 << 0)
501#define PIV_LOG_LOG (1 << 1)
502#define PIV_IGNORE_CHECKSUM_FAILURE (1 << 2)
503#define PIV_ZERO_BUFFERS_ON_ERROR (1 << 3)
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 void PageSetChecksum(Page page, BlockNumber blkno);
541
542#endif /* BUFPAGE_H */
uint32 BlockNumber
Definition block.h:31
Size PageGetFreeSpace(const PageData *page)
Definition bufpage.c:916
#define PD_PAGE_FULL
Definition bufpage.h:214
static bool PageIsEmpty(const PageData *page)
Definition bufpage.h:248
PageHeaderData * PageHeader
Definition bufpage.h:199
PGDLLIMPORT bool ignore_checksum_failure
Definition bufpage.c:27
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition bufpage.c:433
static void PageSetHasFreeLinePointers(Page page)
Definition bufpage.h:427
Size PageGetFreeSpaceForMultipleTuples(const PageData *page, int ntups)
Definition bufpage.c:943
Size PageGetHeapFreeSpace(const PageData *page)
Definition bufpage.c:1000
static void PageXLogRecPtrSet(volatile PageXLogRecPtr *ptr, XLogRecPtr lsn)
Definition bufpage.h:131
static bool PageIsAllVisible(const PageData *page)
Definition bufpage.h:454
static uint16 PageGetSpecialSize(const PageData *page)
Definition bufpage.h:341
void PageSetChecksum(Page page, BlockNumber blkno)
Definition bufpage.c:1518
char PageData
Definition bufpage.h:80
static void PageClearAllVisible(Page page)
Definition bufpage.h:464
static TransactionId PageGetPruneXid(const PageData *page)
Definition bufpage.h:470
Page PageGetTempPage(const PageData *page)
Definition bufpage.c:374
static Size PageGetPageSize(const PageData *page)
Definition bufpage.h:301
Page PageGetTempPageCopy(const PageData *page)
Definition bufpage.c:391
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition bufpage.c:1170
static void PageClearFull(Page page)
Definition bufpage.h:448
static bool PageIsNew(const PageData *page)
Definition bufpage.h:258
#define SizeOfPageHeaderData
Definition bufpage.h:241
static char * PageGetContents(Page page)
Definition bufpage.h:282
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:1414
static void PageSetAllVisible(Page page)
Definition bufpage.h:459
static uint8 PageGetPageLayoutVersion(const PageData *page)
Definition bufpage.h:311
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:268
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:378
#define PD_ALL_VISIBLE
Definition bufpage.h:215
static void PageSetFull(Page page)
Definition bufpage.h:443
static bool PageHasFreeLinePointers(const PageData *page)
Definition bufpage.h:422
OffsetNumber PageAddItemExtended(Page page, const void *item, Size size, OffsetNumber offsetNumber, int flags)
Definition bufpage.c:203
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition bufpage.h:416
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition bufpage.c:1061
void PageRepairFragmentation(Page page)
Definition bufpage.c:708
Size PageGetExactFreeSpace(const PageData *page)
Definition bufpage.c:967
void PageTruncateLinePointerArray(Page page)
Definition bufpage.c:844
void PageInit(Page page, Size pageSize, Size specialSize)
Definition bufpage.c:42
static void PageClearHasFreeLinePointers(Page page)
Definition bufpage.h:432
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:411
uint16 LocationIndex
Definition bufpage.h:90
static void PageValidateSpecialPointer(const PageData *page)
Definition bufpage.h:352
void PageIndexTupleDeleteNoCompact(Page page, OffsetNumber offnum)
Definition bufpage.c:1304
static XLogRecPtr PageGetLSN(const PageData *page)
Definition bufpage.h:410
static void PageSetPageSizeAndVersion(Page page, Size size, uint8 version)
Definition bufpage.h:324
static bool PageIsFull(const PageData *page)
Definition bufpage.h:438
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:396
#define PGDLLIMPORT
Definition c.h:1421
#define MAXALIGN(LEN)
Definition c.h:896
uint8_t uint8
Definition c.h:622
#define Assert(condition)
Definition c.h:943
#define FLEXIBLE_ARRAY_MEMBER
Definition c.h:558
uint64_t uint64
Definition c.h:625
uint16_t uint16
Definition c.h:623
#define StaticAssertDecl(condition, errmessage)
Definition c.h:1008
uint32 TransactionId
Definition c.h:736
size_t Size
Definition c.h:689
#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