Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * slru.h
4 : * Simple LRU buffering for transaction status logfiles
5 : *
6 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : * src/include/access/slru.h
10 : *
11 : *-------------------------------------------------------------------------
12 : */
13 : #ifndef SLRU_H
14 : #define SLRU_H
15 :
16 : #include "access/xlogdefs.h"
17 : #include "storage/lwlock.h"
18 : #include "storage/sync.h"
19 :
20 : /*
21 : * To avoid overflowing internal arithmetic and the size_t data type, the
22 : * number of buffers must not exceed this number.
23 : */
24 : #define SLRU_MAX_ALLOWED_BUFFERS ((1024 * 1024 * 1024) / BLCKSZ)
25 :
26 : /*
27 : * Page status codes. Note that these do not include the "dirty" bit.
28 : * page_dirty can be true only in the VALID or WRITE_IN_PROGRESS states;
29 : * in the latter case it implies that the page has been re-dirtied since
30 : * the write started.
31 : */
32 : typedef enum
33 : {
34 : SLRU_PAGE_EMPTY, /* buffer is not in use */
35 : SLRU_PAGE_READ_IN_PROGRESS, /* page is being read in */
36 : SLRU_PAGE_VALID, /* page is valid and not being written */
37 : SLRU_PAGE_WRITE_IN_PROGRESS, /* page is being written out */
38 : } SlruPageStatus;
39 :
40 : /*
41 : * Shared-memory state
42 : *
43 : * SLRU bank locks are used to protect access to the other fields, except
44 : * latest_page_number, which uses atomics; see comment in slru.c.
45 : */
46 : typedef struct SlruSharedData
47 : {
48 : /* Number of buffers managed by this SLRU structure */
49 : int num_slots;
50 :
51 : /*
52 : * Arrays holding info for each buffer slot. Page number is undefined
53 : * when status is EMPTY, as is page_lru_count.
54 : */
55 : char **page_buffer;
56 : SlruPageStatus *page_status;
57 : bool *page_dirty;
58 : int64 *page_number;
59 : int *page_lru_count;
60 :
61 : /* The buffer_locks protects the I/O on each buffer slots */
62 : LWLockPadded *buffer_locks;
63 :
64 : /* Locks to protect the in memory buffer slot access in SLRU bank. */
65 : LWLockPadded *bank_locks;
66 :
67 : /*----------
68 : * A bank-wise LRU counter is maintained because we do a victim buffer
69 : * search within a bank. Furthermore, manipulating an individual bank
70 : * counter avoids frequent cache invalidation since we update it every time
71 : * we access the page.
72 : *
73 : * We mark a page "most recently used" by setting
74 : * page_lru_count[slotno] = ++bank_cur_lru_count[bankno];
75 : * The oldest page in the bank is therefore the one with the highest value
76 : * of
77 : * bank_cur_lru_count[bankno] - page_lru_count[slotno]
78 : * The counts will eventually wrap around, but this calculation still
79 : * works as long as no page's age exceeds INT_MAX counts.
80 : *----------
81 : */
82 : int *bank_cur_lru_count;
83 :
84 : /*
85 : * Optional array of WAL flush LSNs associated with entries in the SLRU
86 : * pages. If not zero/NULL, we must flush WAL before writing pages (true
87 : * for pg_xact, false for everything else). group_lsn[] has
88 : * lsn_groups_per_page entries per buffer slot, each containing the
89 : * highest LSN known for a contiguous group of SLRU entries on that slot's
90 : * page.
91 : */
92 : XLogRecPtr *group_lsn;
93 : int lsn_groups_per_page;
94 :
95 : /*
96 : * latest_page_number is the page number of the current end of the log;
97 : * this is not critical data, since we use it only to avoid swapping out
98 : * the latest page.
99 : */
100 : pg_atomic_uint64 latest_page_number;
101 :
102 : /* SLRU's index for statistics purposes (might not be unique) */
103 : int slru_stats_idx;
104 : } SlruSharedData;
105 :
106 : typedef SlruSharedData *SlruShared;
107 :
108 : /*
109 : * SlruCtlData is an unshared structure that points to the active information
110 : * in shared memory.
111 : */
112 : typedef struct SlruCtlData
113 : {
114 : SlruShared shared;
115 :
116 : /* Number of banks in this SLRU. */
117 : uint16 nbanks;
118 :
119 : /*
120 : * If true, use long segment file names. Otherwise, use short file names.
121 : *
122 : * For details about the file name format, see SlruFileName().
123 : */
124 : bool long_segment_names;
125 :
126 : /*
127 : * Which sync handler function to use when handing sync requests over to
128 : * the checkpointer. SYNC_HANDLER_NONE to disable fsync (eg pg_notify).
129 : */
130 : SyncRequestHandler sync_handler;
131 :
132 : /*
133 : * Decide whether a page is "older" for truncation and as a hint for
134 : * evicting pages in LRU order. Return true if every entry of the first
135 : * argument is older than every entry of the second argument. Note that
136 : * !PagePrecedes(a,b) && !PagePrecedes(b,a) need not imply a==b; it also
137 : * arises when some entries are older and some are not. For SLRUs using
138 : * SimpleLruTruncate(), this must use modular arithmetic. (For others,
139 : * the behavior of this callback has no functional implications.) Use
140 : * SlruPagePrecedesUnitTests() in SLRUs meeting its criteria.
141 : */
142 : bool (*PagePrecedes) (int64, int64);
143 :
144 : /*
145 : * Dir is set during SimpleLruInit and does not change thereafter. Since
146 : * it's always the same, it doesn't need to be in shared memory.
147 : */
148 : char Dir[64];
149 : } SlruCtlData;
150 :
151 : typedef SlruCtlData *SlruCtl;
152 :
153 : /*
154 : * Get the SLRU bank lock for given SlruCtl and the pageno.
155 : *
156 : * This lock needs to be acquired to access the slru buffer slots in the
157 : * respective bank.
158 : */
159 : static inline LWLock *
160 18211390 : SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
161 : {
162 : int bankno;
163 :
164 18211390 : bankno = pageno % ctl->nbanks;
165 18211390 : return &(ctl->shared->bank_locks[bankno].lock);
166 : }
167 :
168 : extern Size SimpleLruShmemSize(int nslots, int nlsns);
169 : extern int SimpleLruAutotuneBuffers(int divisor, int max);
170 : extern void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
171 : const char *subdir, int buffer_tranche_id,
172 : int bank_tranche_id, SyncRequestHandler sync_handler,
173 : bool long_segment_names);
174 : extern int SimpleLruZeroPage(SlruCtl ctl, int64 pageno);
175 : extern void SimpleLruZeroAndWritePage(SlruCtl ctl, int64 pageno);
176 : extern int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok,
177 : TransactionId xid);
178 : extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno,
179 : TransactionId xid);
180 : extern void SimpleLruWritePage(SlruCtl ctl, int slotno);
181 : extern void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied);
182 : #ifdef USE_ASSERT_CHECKING
183 : extern void SlruPagePrecedesUnitTests(SlruCtl ctl, int per_page);
184 : #else
185 : #define SlruPagePrecedesUnitTests(ctl, per_page) do {} while (0)
186 : #endif
187 : extern void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage);
188 : extern bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int64 pageno);
189 :
190 : typedef bool (*SlruScanCallback) (SlruCtl ctl, char *filename, int64 segpage,
191 : void *data);
192 : extern bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data);
193 : extern void SlruDeleteSegment(SlruCtl ctl, int64 segno);
194 :
195 : extern int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path);
196 :
197 : /* SlruScanDirectory public callbacks */
198 : extern bool SlruScanDirCbReportPresence(SlruCtl ctl, char *filename,
199 : int64 segpage, void *data);
200 : extern bool SlruScanDirCbDeleteAll(SlruCtl ctl, char *filename, int64 segpage,
201 : void *data);
202 : extern bool check_slru_buffers(const char *name, int *newval);
203 :
204 : #endif /* SLRU_H */
|