Line data Source code
1 : /*--------------------------------------------------------------------------
2 : *
3 : * test_slru.c
4 : * Test correctness of SLRU functions.
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : * IDENTIFICATION
10 : * src/test/modules/test_slru/test_slru.c
11 : *
12 : * -------------------------------------------------------------------------
13 : */
14 :
15 : #include "postgres.h"
16 :
17 : #include "access/slru.h"
18 : #include "access/transam.h"
19 : #include "miscadmin.h"
20 : #include "storage/fd.h"
21 : #include "storage/ipc.h"
22 : #include "storage/shmem.h"
23 : #include "utils/builtins.h"
24 :
25 2 : PG_MODULE_MAGIC;
26 :
27 : /*
28 : * SQL-callable entry points
29 : */
30 4 : PG_FUNCTION_INFO_V1(test_slru_page_write);
31 4 : PG_FUNCTION_INFO_V1(test_slru_page_writeall);
32 4 : PG_FUNCTION_INFO_V1(test_slru_page_read);
33 4 : PG_FUNCTION_INFO_V1(test_slru_page_readonly);
34 4 : PG_FUNCTION_INFO_V1(test_slru_page_exists);
35 4 : PG_FUNCTION_INFO_V1(test_slru_page_sync);
36 4 : PG_FUNCTION_INFO_V1(test_slru_page_delete);
37 4 : PG_FUNCTION_INFO_V1(test_slru_page_truncate);
38 4 : PG_FUNCTION_INFO_V1(test_slru_delete_all);
39 :
40 : /* Number of SLRU page slots */
41 : #define NUM_TEST_BUFFERS 16
42 :
43 : /* SLRU control lock */
44 : LWLock TestSLRULock;
45 : #define TestSLRULock (&TestSLRULock)
46 :
47 : static SlruCtlData TestSlruCtlData;
48 : #define TestSlruCtl (&TestSlruCtlData)
49 :
50 : static shmem_request_hook_type prev_shmem_request_hook = NULL;
51 : static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
52 :
53 : static bool
54 2 : test_slru_scan_cb(SlruCtl ctl, char *filename, int64 segpage, void *data)
55 : {
56 2 : elog(NOTICE, "Calling test_slru_scan_cb()");
57 2 : return SlruScanDirCbDeleteAll(ctl, filename, segpage, data);
58 : }
59 :
60 : Datum
61 196 : test_slru_page_write(PG_FUNCTION_ARGS)
62 : {
63 196 : int64 pageno = PG_GETARG_INT64(0);
64 196 : char *data = text_to_cstring(PG_GETARG_TEXT_PP(1));
65 : int slotno;
66 :
67 196 : LWLockAcquire(TestSLRULock, LW_EXCLUSIVE);
68 :
69 196 : slotno = SimpleLruZeroPage(TestSlruCtl, pageno);
70 :
71 : /* these should match */
72 : Assert(TestSlruCtl->shared->page_number[slotno] == pageno);
73 :
74 : /* mark the page as dirty so as it would get written */
75 196 : TestSlruCtl->shared->page_dirty[slotno] = true;
76 196 : TestSlruCtl->shared->page_status[slotno] = SLRU_PAGE_VALID;
77 :
78 : /* write given data to the page, up to the limit of the page */
79 196 : strncpy(TestSlruCtl->shared->page_buffer[slotno], data,
80 : BLCKSZ - 1);
81 :
82 196 : SimpleLruWritePage(TestSlruCtl, slotno);
83 196 : LWLockRelease(TestSLRULock);
84 :
85 196 : PG_RETURN_VOID();
86 : }
87 :
88 : Datum
89 4 : test_slru_page_writeall(PG_FUNCTION_ARGS)
90 : {
91 4 : SimpleLruWriteAll(TestSlruCtl, true);
92 4 : PG_RETURN_VOID();
93 : }
94 :
95 : Datum
96 8 : test_slru_page_read(PG_FUNCTION_ARGS)
97 : {
98 8 : int64 pageno = PG_GETARG_INT64(0);
99 8 : bool write_ok = PG_GETARG_BOOL(1);
100 8 : char *data = NULL;
101 : int slotno;
102 :
103 : /* find page in buffers, reading it if necessary */
104 8 : LWLockAcquire(TestSLRULock, LW_EXCLUSIVE);
105 8 : slotno = SimpleLruReadPage(TestSlruCtl, pageno,
106 : write_ok, InvalidTransactionId);
107 8 : data = (char *) TestSlruCtl->shared->page_buffer[slotno];
108 8 : LWLockRelease(TestSLRULock);
109 :
110 8 : PG_RETURN_TEXT_P(cstring_to_text(data));
111 : }
112 :
113 : Datum
114 8 : test_slru_page_readonly(PG_FUNCTION_ARGS)
115 : {
116 8 : int64 pageno = PG_GETARG_INT64(0);
117 8 : char *data = NULL;
118 : int slotno;
119 :
120 : /* find page in buffers, reading it if necessary */
121 8 : slotno = SimpleLruReadPage_ReadOnly(TestSlruCtl,
122 : pageno,
123 : InvalidTransactionId);
124 : Assert(LWLockHeldByMe(TestSLRULock));
125 8 : data = (char *) TestSlruCtl->shared->page_buffer[slotno];
126 8 : LWLockRelease(TestSLRULock);
127 :
128 8 : PG_RETURN_TEXT_P(cstring_to_text(data));
129 : }
130 :
131 : Datum
132 36 : test_slru_page_exists(PG_FUNCTION_ARGS)
133 : {
134 36 : int64 pageno = PG_GETARG_INT64(0);
135 : bool found;
136 :
137 36 : LWLockAcquire(TestSLRULock, LW_EXCLUSIVE);
138 36 : found = SimpleLruDoesPhysicalPageExist(TestSlruCtl, pageno);
139 36 : LWLockRelease(TestSLRULock);
140 :
141 36 : PG_RETURN_BOOL(found);
142 : }
143 :
144 : Datum
145 4 : test_slru_page_sync(PG_FUNCTION_ARGS)
146 : {
147 4 : int64 pageno = PG_GETARG_INT64(0);
148 : FileTag ftag;
149 : char path[MAXPGPATH];
150 :
151 : /* note that this flushes the full file a segment is located in */
152 4 : ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
153 4 : SlruSyncFileTag(TestSlruCtl, &ftag, path);
154 :
155 4 : elog(NOTICE, "Called SlruSyncFileTag() for segment %lld on path %s",
156 : (long long) ftag.segno, path);
157 :
158 4 : PG_RETURN_VOID();
159 : }
160 :
161 : Datum
162 4 : test_slru_page_delete(PG_FUNCTION_ARGS)
163 : {
164 4 : int64 pageno = PG_GETARG_INT64(0);
165 : FileTag ftag;
166 :
167 4 : ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
168 4 : SlruDeleteSegment(TestSlruCtl, ftag.segno);
169 :
170 4 : elog(NOTICE, "Called SlruDeleteSegment() for segment %lld",
171 : (long long) ftag.segno);
172 :
173 4 : PG_RETURN_VOID();
174 : }
175 :
176 : Datum
177 4 : test_slru_page_truncate(PG_FUNCTION_ARGS)
178 : {
179 4 : int64 pageno = PG_GETARG_INT64(0);
180 :
181 4 : SimpleLruTruncate(TestSlruCtl, pageno);
182 4 : PG_RETURN_VOID();
183 : }
184 :
185 : Datum
186 4 : test_slru_delete_all(PG_FUNCTION_ARGS)
187 : {
188 : /* this calls SlruScanDirCbDeleteAll() internally, ensuring deletion */
189 4 : SlruScanDirectory(TestSlruCtl, test_slru_scan_cb, NULL);
190 :
191 4 : PG_RETURN_VOID();
192 : }
193 :
194 : /*
195 : * Module load callbacks and initialization.
196 : */
197 :
198 : static void
199 2 : test_slru_shmem_request(void)
200 : {
201 2 : if (prev_shmem_request_hook)
202 0 : prev_shmem_request_hook();
203 :
204 : /* reserve shared memory for the test SLRU */
205 2 : RequestAddinShmemSpace(SimpleLruShmemSize(NUM_TEST_BUFFERS, 0));
206 2 : }
207 :
208 : static bool
209 60 : test_slru_page_precedes_logically(int64 page1, int64 page2)
210 : {
211 60 : return page1 < page2;
212 : }
213 :
214 : static void
215 2 : test_slru_shmem_startup(void)
216 : {
217 : /*
218 : * Short segments names are well tested elsewhere so in this test we are
219 : * focusing on long names.
220 : */
221 2 : const bool long_segment_names = true;
222 2 : const char slru_dir_name[] = "pg_test_slru";
223 : int test_tranche_id;
224 :
225 2 : if (prev_shmem_startup_hook)
226 0 : prev_shmem_startup_hook();
227 :
228 : /*
229 : * Create the SLRU directory if it does not exist yet, from the root of
230 : * the data directory.
231 : */
232 2 : (void) MakePGDirectory(slru_dir_name);
233 :
234 : /* initialize the SLRU facility */
235 2 : test_tranche_id = LWLockNewTrancheId();
236 2 : LWLockRegisterTranche(test_tranche_id, "test_slru_tranche");
237 2 : LWLockInitialize(TestSLRULock, test_tranche_id);
238 :
239 2 : TestSlruCtl->PagePrecedes = test_slru_page_precedes_logically;
240 2 : SimpleLruInit(TestSlruCtl, "TestSLRU",
241 : NUM_TEST_BUFFERS, 0, TestSLRULock, slru_dir_name,
242 : test_tranche_id, SYNC_HANDLER_NONE, long_segment_names);
243 2 : }
244 :
245 : void
246 2 : _PG_init(void)
247 : {
248 2 : if (!process_shared_preload_libraries_in_progress)
249 0 : ereport(ERROR,
250 : (errmsg("cannot load \"%s\" after startup", "test_slru"),
251 : errdetail("\"%s\" must be loaded with shared_preload_libraries.",
252 : "test_slru")));
253 :
254 2 : prev_shmem_request_hook = shmem_request_hook;
255 2 : shmem_request_hook = test_slru_shmem_request;
256 :
257 2 : prev_shmem_startup_hook = shmem_startup_hook;
258 2 : shmem_startup_hook = test_slru_shmem_startup;
259 2 : }
|