| 1 | /*------------------------------------------------------------------------- |
| 2 | * |
| 3 | * freepage.h |
| 4 | * Management of page-organized free memory. |
| 5 | * |
| 6 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
| 7 | * Portions Copyright (c) 1994, Regents of the University of California |
| 8 | * |
| 9 | * src/include/utils/freepage.h |
| 10 | * |
| 11 | *------------------------------------------------------------------------- |
| 12 | */ |
| 13 | |
| 14 | #ifndef FREEPAGE_H |
| 15 | #define FREEPAGE_H |
| 16 | |
| 17 | #include "storage/lwlock.h" |
| 18 | #include "utils/relptr.h" |
| 19 | |
| 20 | /* Forward declarations. */ |
| 21 | typedef struct FreePageSpanLeader FreePageSpanLeader; |
| 22 | typedef struct FreePageBtree FreePageBtree; |
| 23 | typedef struct FreePageManager FreePageManager; |
| 24 | |
| 25 | /* |
| 26 | * PostgreSQL normally uses 8kB pages for most things, but many common |
| 27 | * architecture/operating system pairings use a 4kB page size for memory |
| 28 | * allocation, so we do that here also. |
| 29 | */ |
| 30 | #define FPM_PAGE_SIZE 4096 |
| 31 | |
| 32 | /* |
| 33 | * Each freelist except for the last contains only spans of one particular |
| 34 | * size. Everything larger goes on the last one. In some sense this seems |
| 35 | * like a waste since most allocations are in a few common sizes, but it |
| 36 | * means that small allocations can simply pop the head of the relevant list |
| 37 | * without needing to worry about whether the object we find there is of |
| 38 | * precisely the correct size (because we know it must be). |
| 39 | */ |
| 40 | #define FPM_NUM_FREELISTS 129 |
| 41 | |
| 42 | /* Define relative pointer types. */ |
| 43 | relptr_declare(FreePageBtree, RelptrFreePageBtree); |
| 44 | relptr_declare(FreePageManager, RelptrFreePageManager); |
| 45 | relptr_declare(FreePageSpanLeader, RelptrFreePageSpanLeader); |
| 46 | |
| 47 | /* Everything we need in order to manage free pages (see freepage.c) */ |
| 48 | struct FreePageManager |
| 49 | { |
| 50 | RelptrFreePageManager self; |
| 51 | RelptrFreePageBtree btree_root; |
| 52 | RelptrFreePageSpanLeader btree_recycle; |
| 53 | unsigned btree_depth; |
| 54 | unsigned btree_recycle_count; |
| 55 | Size singleton_first_page; |
| 56 | Size singleton_npages; |
| 57 | Size contiguous_pages; |
| 58 | bool contiguous_pages_dirty; |
| 59 | RelptrFreePageSpanLeader freelist[FPM_NUM_FREELISTS]; |
| 60 | #ifdef FPM_EXTRA_ASSERTS |
| 61 | /* For debugging only, pages put minus pages gotten. */ |
| 62 | Size free_pages; |
| 63 | #endif |
| 64 | }; |
| 65 | |
| 66 | /* Macros to convert between page numbers (expressed as Size) and pointers. */ |
| 67 | #define fpm_page_to_pointer(base, page) \ |
| 68 | (AssertVariableIsOfTypeMacro(page, Size), \ |
| 69 | (base) + FPM_PAGE_SIZE * (page)) |
| 70 | #define fpm_pointer_to_page(base, ptr) \ |
| 71 | (((Size) (((char *) (ptr)) - (base))) / FPM_PAGE_SIZE) |
| 72 | |
| 73 | /* Macro to convert an allocation size to a number of pages. */ |
| 74 | #define fpm_size_to_pages(sz) \ |
| 75 | (((sz) + FPM_PAGE_SIZE - 1) / FPM_PAGE_SIZE) |
| 76 | |
| 77 | /* Macros to check alignment of absolute and relative pointers. */ |
| 78 | #define fpm_pointer_is_page_aligned(base, ptr) \ |
| 79 | (((Size) (((char *) (ptr)) - (base))) % FPM_PAGE_SIZE == 0) |
| 80 | #define fpm_relptr_is_page_aligned(base, relptr) \ |
| 81 | ((relptr).relptr_off % FPM_PAGE_SIZE == 0) |
| 82 | |
| 83 | /* Macro to find base address of the segment containing a FreePageManager. */ |
| 84 | #define fpm_segment_base(fpm) \ |
| 85 | (((char *) fpm) - fpm->self.relptr_off) |
| 86 | |
| 87 | /* Macro to access a FreePageManager's largest consecutive run of pages. */ |
| 88 | #define fpm_largest(fpm) \ |
| 89 | (fpm->contiguous_pages) |
| 90 | |
| 91 | /* Functions to manipulate the free page map. */ |
| 92 | extern void FreePageManagerInitialize(FreePageManager *fpm, char *base); |
| 93 | extern bool FreePageManagerGet(FreePageManager *fpm, Size npages, |
| 94 | Size *first_page); |
| 95 | extern void FreePageManagerPut(FreePageManager *fpm, Size first_page, |
| 96 | Size npages); |
| 97 | extern char *FreePageManagerDump(FreePageManager *fpm); |
| 98 | |
| 99 | #endif /* FREEPAGE_H */ |
| 100 | |