Age Owner Branch data TLA 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 *
29 heikki.linnakangas@i 207 :GNC 3440064 : SimpleLruGetBankLock(SlruDesc *ctl, int64 pageno)
208 : : {
209 : : int bankno;
210 : :
211 [ - + ]: 3440064 : Assert(ctl->nbanks != 0);
481 alvherre@alvh.no-ip. 212 :CBC 3440064 : bankno = pageno % ctl->nbanks;
797 213 : 3440064 : 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 */
|