Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * slru.h
4 : * Simple LRU buffering for transaction status logfiles
5 : *
6 : * Portions Copyright (c) 1996-2026, 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/transam.h"
17 : #include "access/xlogdefs.h"
18 : #include "storage/lwlock.h"
19 : #include "storage/shmem.h"
20 : #include "storage/sync.h"
21 :
22 : /*
23 : * To avoid overflowing internal arithmetic and the size_t data type, the
24 : * number of buffers must not exceed this number.
25 : */
26 : #define SLRU_MAX_ALLOWED_BUFFERS ((1024 * 1024 * 1024) / BLCKSZ)
27 :
28 : /*
29 : * Page status codes. Note that these do not include the "dirty" bit.
30 : * page_dirty can be true only in the VALID or WRITE_IN_PROGRESS states;
31 : * in the latter case it implies that the page has been re-dirtied since
32 : * the write started.
33 : */
34 : typedef enum
35 : {
36 : SLRU_PAGE_EMPTY, /* buffer is not in use */
37 : SLRU_PAGE_READ_IN_PROGRESS, /* page is being read in */
38 : SLRU_PAGE_VALID, /* page is valid and not being written */
39 : SLRU_PAGE_WRITE_IN_PROGRESS, /* page is being written out */
40 : } SlruPageStatus;
41 :
42 : /*
43 : * Shared-memory state
44 : *
45 : * SLRU bank locks are used to protect access to the other fields, except
46 : * latest_page_number, which uses atomics; see comment in slru.c.
47 : */
48 : typedef struct SlruSharedData
49 : {
50 : /* Number of buffers managed by this SLRU structure */
51 : int num_slots;
52 :
53 : /*
54 : * Arrays holding info for each buffer slot. Page number is undefined
55 : * when status is EMPTY, as is page_lru_count.
56 : */
57 : char **page_buffer;
58 : SlruPageStatus *page_status;
59 : bool *page_dirty;
60 : int64 *page_number;
61 : int *page_lru_count;
62 :
63 : /* The buffer_locks protects the I/O on each buffer slots */
64 : LWLockPadded *buffer_locks;
65 :
66 : /* Locks to protect the in memory buffer slot access in SLRU bank. */
67 : LWLockPadded *bank_locks;
68 :
69 : /*----------
70 : * A bank-wise LRU counter is maintained because we do a victim buffer
71 : * search within a bank. Furthermore, manipulating an individual bank
72 : * counter avoids frequent cache invalidation since we update it every time
73 : * we access the page.
74 : *
75 : * We mark a page "most recently used" by setting
76 : * page_lru_count[slotno] = ++bank_cur_lru_count[bankno];
77 : * The oldest page in the bank is therefore the one with the highest value
78 : * of
79 : * bank_cur_lru_count[bankno] - page_lru_count[slotno]
80 : * The counts will eventually wrap around, but this calculation still
81 : * works as long as no page's age exceeds INT_MAX counts.
82 : *----------
83 : */
84 : int *bank_cur_lru_count;
85 :
86 : /*
87 : * Optional array of WAL flush LSNs associated with entries in the SLRU
88 : * pages. If not zero/NULL, we must flush WAL before writing pages (true
89 : * for pg_xact, false for everything else). group_lsn[] has
90 : * lsn_groups_per_page entries per buffer slot, each containing the
91 : * highest LSN known for a contiguous group of SLRU entries on that slot's
92 : * page.
93 : */
94 : XLogRecPtr *group_lsn;
95 : int lsn_groups_per_page;
96 :
97 : /*
98 : * latest_page_number is the page number of the current end of the log;
99 : * this is not critical data, since we use it only to avoid swapping out
100 : * the latest page.
101 : */
102 : pg_atomic_uint64 latest_page_number;
103 :
104 : /* SLRU's index for statistics purposes (might not be unique) */
105 : int slru_stats_idx;
106 : } SlruSharedData;
107 :
108 : typedef SlruSharedData *SlruShared;
109 :
110 : typedef struct SlruDesc SlruDesc;
111 :
112 : /*
113 : * Options for SimpleLruRequest()
114 : */
115 : typedef struct SlruOpts
116 : {
117 : /* Options for allocating the underlying shmem area; do not touch directly */
118 : ShmemStructOpts base;
119 :
120 : /*
121 : * name of SLRU. (This is user-visible, pick with care!)
122 : */
123 : const char *name;
124 :
125 : /*
126 : * Pointer to a backend-private handle for the SLRU. It is initialized
127 : * when the SLRU is initialized or attached to.
128 : */
129 : SlruDesc *desc;
130 :
131 : /* number of page slots to use. */
132 : int nslots;
133 :
134 : /* number of LSN groups per page (set to zero if not relevant). */
135 : int nlsns;
136 :
137 : /*
138 : * Which sync handler function to use when handing sync requests over to
139 : * the checkpointer. SYNC_HANDLER_NONE to disable fsync (eg pg_notify).
140 : */
141 : SyncRequestHandler sync_handler;
142 :
143 : /*
144 : * PGDATA-relative subdirectory that will contain the files.
145 : */
146 : const char *Dir;
147 :
148 : /*
149 : * If true, use long segment file names. Otherwise, use short file names.
150 : *
151 : * For details about the file name format, see SlruFileName().
152 : */
153 : bool long_segment_names;
154 :
155 :
156 : /*
157 : * Decide whether a page is "older" for truncation and as a hint for
158 : * evicting pages in LRU order. Return true if every entry of the first
159 : * argument is older than every entry of the second argument. Note that
160 : * !PagePrecedes(a,b) && !PagePrecedes(b,a) need not imply a==b; it also
161 : * arises when some entries are older and some are not. For SLRUs using
162 : * SimpleLruTruncate(), this must use modular arithmetic. (For others,
163 : * the behavior of this callback has no functional implications.) Use
164 : * SlruPagePrecedesUnitTests() in SLRUs meeting its criteria.
165 : */
166 : bool (*PagePrecedes) (int64, int64);
167 :
168 : /*
169 : * Callback to provide more details on an I/O error. This is called as
170 : * part of ereport(), and the callback function is expected to call
171 : * errdetail() to provide more context on the SLRU access.
172 : *
173 : * The opaque_data argument here is the argument that was passed to the
174 : * SimpleLruReadPage() function.
175 : */
176 : int (*errdetail_for_io_error) (const void *opaque_data);
177 :
178 : /*
179 : * Tranche IDs to use for the SLRU's per-buffer and per-bank LWLocks. If
180 : * these are left as zeros, new tranches will be assigned dynamically.
181 : */
182 : int buffer_tranche_id;
183 : int bank_tranche_id;
184 : } SlruOpts;
185 :
186 : /*
187 : * SlruDesc is an unshared structure that points to the active information
188 : * in shared memory.
189 : */
190 : typedef struct SlruDesc
191 : {
192 : SlruOpts options;
193 :
194 : SlruShared shared;
195 :
196 : /* Number of banks in this SLRU. */
197 : uint16 nbanks;
198 : } SlruDesc;
199 :
200 : /*
201 : * Get the SLRU bank lock for the given pageno.
202 : *
203 : * This lock needs to be acquired to access the slru buffer slots in the
204 : * respective bank.
205 : */
206 : static inline LWLock *
207 9929358 : SimpleLruGetBankLock(SlruDesc *ctl, int64 pageno)
208 : {
209 : int bankno;
210 :
211 : Assert(ctl->nbanks != 0);
212 9929358 : bankno = pageno % ctl->nbanks;
213 9929358 : return &(ctl->shared->bank_locks[bankno].lock);
214 : }
215 :
216 : extern void SimpleLruRequestWithOpts(const SlruOpts *options);
217 :
218 : #define SimpleLruRequest(...) \
219 : SimpleLruRequestWithOpts(&(SlruOpts){__VA_ARGS__})
220 :
221 : extern int SimpleLruAutotuneBuffers(int divisor, int max);
222 : extern int SimpleLruZeroPage(SlruDesc *ctl, int64 pageno);
223 : extern void SimpleLruZeroAndWritePage(SlruDesc *ctl, int64 pageno);
224 : extern int SimpleLruReadPage(SlruDesc *ctl, int64 pageno, bool write_ok,
225 : const void *opaque_data);
226 : extern int SimpleLruReadPage_ReadOnly(SlruDesc *ctl, int64 pageno,
227 : const void *opaque_data);
228 : extern void SimpleLruWritePage(SlruDesc *ctl, int slotno);
229 : extern void SimpleLruWriteAll(SlruDesc *ctl, bool allow_redirtied);
230 : #ifdef USE_ASSERT_CHECKING
231 : extern void SlruPagePrecedesUnitTests(SlruDesc *ctl, int per_page);
232 : #else
233 : #define SlruPagePrecedesUnitTests(ctl, per_page) do {} while (0)
234 : #endif
235 : extern void SimpleLruTruncate(SlruDesc *ctl, int64 cutoffPage);
236 : extern bool SimpleLruDoesPhysicalPageExist(SlruDesc *ctl, int64 pageno);
237 :
238 : typedef bool (*SlruScanCallback) (SlruDesc *ctl, char *filename, int64 segpage,
239 : void *data);
240 : extern bool SlruScanDirectory(SlruDesc *ctl, SlruScanCallback callback, void *data);
241 : extern void SlruDeleteSegment(SlruDesc *ctl, int64 segno);
242 :
243 : extern int SlruSyncFileTag(SlruDesc *ctl, const FileTag *ftag, char *path);
244 :
245 : /* SlruScanDirectory public callbacks */
246 : extern bool SlruScanDirCbReportPresence(SlruDesc *ctl, char *filename,
247 : int64 segpage, void *data);
248 : extern bool SlruScanDirCbDeleteAll(SlruDesc *ctl, char *filename, int64 segpage,
249 : void *data);
250 : extern bool check_slru_buffers(const char *name, int *newval);
251 :
252 : extern void shmem_slru_init(void *location, ShmemStructOpts *base_options);
253 : extern void shmem_slru_attach(void *location, ShmemStructOpts *base_options);
254 :
255 : #endif /* SLRU_H */
|