1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-21 05:21:08 +03:00
Files
postgres/src/include/utils/freepage.h
Thomas Munro 7201cd1862 Fix relptr's encoding of the base address.
Previously, we encoded both NULL and the first byte at the base address
as 0.  That confusion led to the assertion in commit e07d4ddc, which
failed when min_dynamic_shared_memory was used.  Give them distinct
encodings, by switching to 1-based offsets for non-NULL pointers.  Also
improve macro hygiene in passing (missing/misplaced parentheses), and
remove open-coded access to the raw offset value from freepage.c/h.

Although e07d4ddc was back-patched to 10, the only code that actually
makes use of relptr at the base address arrived in 84b1c63a, so no need
to back-patch further than 14 for now.

Reported-by: Justin Pryzby <pryzby@telsasoft.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Discussion: https://postgr.es/m/20220519193839.GT19626%40telsasoft.com
2022-06-27 11:34:26 +12:00

100 lines
3.4 KiB
C

/*-------------------------------------------------------------------------
*
* freepage.h
* Management of page-organized free memory.
*
* Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/include/utils/freepage.h
*
*-------------------------------------------------------------------------
*/
#ifndef FREEPAGE_H
#define FREEPAGE_H
#include "storage/lwlock.h"
#include "utils/relptr.h"
/* Forward declarations. */
typedef struct FreePageSpanLeader FreePageSpanLeader;
typedef struct FreePageBtree FreePageBtree;
typedef struct FreePageManager FreePageManager;
/*
* PostgreSQL normally uses 8kB pages for most things, but many common
* architecture/operating system pairings use a 4kB page size for memory
* allocation, so we do that here also.
*/
#define FPM_PAGE_SIZE 4096
/*
* Each freelist except for the last contains only spans of one particular
* size. Everything larger goes on the last one. In some sense this seems
* like a waste since most allocations are in a few common sizes, but it
* means that small allocations can simply pop the head of the relevant list
* without needing to worry about whether the object we find there is of
* precisely the correct size (because we know it must be).
*/
#define FPM_NUM_FREELISTS 129
/* Define relative pointer types. */
relptr_declare(FreePageBtree, RelptrFreePageBtree);
relptr_declare(FreePageManager, RelptrFreePageManager);
relptr_declare(FreePageSpanLeader, RelptrFreePageSpanLeader);
/* Everything we need in order to manage free pages (see freepage.c) */
struct FreePageManager
{
RelptrFreePageManager self;
RelptrFreePageBtree btree_root;
RelptrFreePageSpanLeader btree_recycle;
unsigned btree_depth;
unsigned btree_recycle_count;
Size singleton_first_page;
Size singleton_npages;
Size contiguous_pages;
bool contiguous_pages_dirty;
RelptrFreePageSpanLeader freelist[FPM_NUM_FREELISTS];
#ifdef FPM_EXTRA_ASSERTS
/* For debugging only, pages put minus pages gotten. */
Size free_pages;
#endif
};
/* Macros to convert between page numbers (expressed as Size) and pointers. */
#define fpm_page_to_pointer(base, page) \
(AssertVariableIsOfTypeMacro(page, Size), \
(base) + FPM_PAGE_SIZE * (page))
#define fpm_pointer_to_page(base, ptr) \
(((Size) (((char *) (ptr)) - (base))) / FPM_PAGE_SIZE)
/* Macro to convert an allocation size to a number of pages. */
#define fpm_size_to_pages(sz) \
(((sz) + FPM_PAGE_SIZE - 1) / FPM_PAGE_SIZE)
/* Macros to check alignment of absolute and relative pointers. */
#define fpm_pointer_is_page_aligned(base, ptr) \
(((Size) (((char *) (ptr)) - (base))) % FPM_PAGE_SIZE == 0)
#define fpm_relptr_is_page_aligned(base, relptr) \
(relptr_offset(relptr) % FPM_PAGE_SIZE == 0)
/* Macro to find base address of the segment containing a FreePageManager. */
#define fpm_segment_base(fpm) \
(((char *) fpm) - relptr_offset(fpm->self))
/* Macro to access a FreePageManager's largest consecutive run of pages. */
#define fpm_largest(fpm) \
(fpm->contiguous_pages)
/* Functions to manipulate the free page map. */
extern void FreePageManagerInitialize(FreePageManager *fpm, char *base);
extern bool FreePageManagerGet(FreePageManager *fpm, Size npages,
Size *first_page);
extern void FreePageManagerPut(FreePageManager *fpm, Size first_page,
Size npages);
extern char *FreePageManagerDump(FreePageManager *fpm);
#endif /* FREEPAGE_H */