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, int 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 98 : test_slru_page_write(PG_FUNCTION_ARGS)
62 : {
63 98 : int pageno = PG_GETARG_INT32(0);
64 98 : char *data = text_to_cstring(PG_GETARG_TEXT_PP(1));
65 : int slotno;
66 :
67 98 : LWLockAcquire(TestSLRULock, LW_EXCLUSIVE);
68 :
69 98 : 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 98 : TestSlruCtl->shared->page_dirty[slotno] = true;
76 98 : TestSlruCtl->shared->page_status[slotno] = SLRU_PAGE_VALID;
77 :
78 : /* write given data to the page, up to the limit of the page */
79 98 : strncpy(TestSlruCtl->shared->page_buffer[slotno], data,
80 : BLCKSZ - 1);
81 :
82 98 : SimpleLruWritePage(TestSlruCtl, slotno);
83 98 : LWLockRelease(TestSLRULock);
84 :
85 98 : PG_RETURN_VOID();
86 : }
87 :
88 : Datum
89 2 : test_slru_page_writeall(PG_FUNCTION_ARGS)
90 : {
91 2 : SimpleLruWriteAll(TestSlruCtl, true);
92 2 : PG_RETURN_VOID();
93 : }
94 :
95 : Datum
96 4 : test_slru_page_read(PG_FUNCTION_ARGS)
97 : {
98 4 : int pageno = PG_GETARG_INT32(0);
99 4 : bool write_ok = PG_GETARG_BOOL(1);
100 4 : char *data = NULL;
101 : int slotno;
102 :
103 : /* find page in buffers, reading it if necessary */
104 4 : LWLockAcquire(TestSLRULock, LW_EXCLUSIVE);
105 4 : slotno = SimpleLruReadPage(TestSlruCtl, pageno,
106 : write_ok, InvalidTransactionId);
107 4 : data = (char *) TestSlruCtl->shared->page_buffer[slotno];
108 4 : LWLockRelease(TestSLRULock);
109 :
110 4 : PG_RETURN_TEXT_P(cstring_to_text(data));
111 : }
112 :
113 : Datum
114 4 : test_slru_page_readonly(PG_FUNCTION_ARGS)
115 : {
116 4 : int pageno = PG_GETARG_INT32(0);
117 4 : char *data = NULL;
118 : int slotno;
119 :
120 : /* find page in buffers, reading it if necessary */
121 4 : slotno = SimpleLruReadPage_ReadOnly(TestSlruCtl,
122 : pageno,
123 : InvalidTransactionId);
124 : Assert(LWLockHeldByMe(TestSLRULock));
125 4 : data = (char *) TestSlruCtl->shared->page_buffer[slotno];
126 4 : LWLockRelease(TestSLRULock);
127 :
128 4 : PG_RETURN_TEXT_P(cstring_to_text(data));
129 : }
130 :
131 : Datum
132 18 : test_slru_page_exists(PG_FUNCTION_ARGS)
133 : {
134 18 : int pageno = PG_GETARG_INT32(0);
135 : bool found;
136 :
137 18 : LWLockAcquire(TestSLRULock, LW_EXCLUSIVE);
138 18 : found = SimpleLruDoesPhysicalPageExist(TestSlruCtl, pageno);
139 18 : LWLockRelease(TestSLRULock);
140 :
141 18 : PG_RETURN_BOOL(found);
142 : }
143 :
144 : Datum
145 2 : test_slru_page_sync(PG_FUNCTION_ARGS)
146 : {
147 2 : int pageno = PG_GETARG_INT32(0);
148 : FileTag ftag;
149 : char path[MAXPGPATH];
150 :
151 : /* note that this flushes the full file a segment is located in */
152 2 : ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
153 2 : SlruSyncFileTag(TestSlruCtl, &ftag, path);
154 :
155 2 : elog(NOTICE, "Called SlruSyncFileTag() for segment %u on path %s",
156 : ftag.segno, path);
157 :
158 2 : PG_RETURN_VOID();
159 : }
160 :
161 : Datum
162 2 : test_slru_page_delete(PG_FUNCTION_ARGS)
163 : {
164 2 : int pageno = PG_GETARG_INT32(0);
165 : FileTag ftag;
166 :
167 2 : ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
168 2 : SlruDeleteSegment(TestSlruCtl, ftag.segno);
169 :
170 2 : elog(NOTICE, "Called SlruDeleteSegment() for segment %u", ftag.segno);
171 :
172 2 : PG_RETURN_VOID();
173 : }
174 :
175 : Datum
176 2 : test_slru_page_truncate(PG_FUNCTION_ARGS)
177 : {
178 2 : int pageno = PG_GETARG_INT32(0);
179 :
180 2 : SimpleLruTruncate(TestSlruCtl, pageno);
181 2 : PG_RETURN_VOID();
182 : }
183 :
184 : Datum
185 2 : test_slru_delete_all(PG_FUNCTION_ARGS)
186 : {
187 : /* this calls SlruScanDirCbDeleteAll() internally, ensuring deletion */
188 2 : SlruScanDirectory(TestSlruCtl, test_slru_scan_cb, NULL);
189 :
190 2 : PG_RETURN_VOID();
191 : }
192 :
193 : /*
194 : * Module load callbacks and initialization.
195 : */
196 :
197 : static void
198 2 : test_slru_shmem_request(void)
199 : {
200 2 : if (prev_shmem_request_hook)
201 0 : prev_shmem_request_hook();
202 :
203 : /* reserve shared memory for the test SLRU */
204 2 : RequestAddinShmemSpace(SimpleLruShmemSize(NUM_TEST_BUFFERS, 0));
205 2 : }
206 :
207 : static bool
208 22 : test_slru_page_precedes_logically(int page1, int page2)
209 : {
210 22 : return page1 < page2;
211 : }
212 :
213 : static void
214 2 : test_slru_shmem_startup(void)
215 : {
216 2 : const char slru_dir_name[] = "pg_test_slru";
217 : int test_tranche_id;
218 :
219 2 : if (prev_shmem_startup_hook)
220 0 : prev_shmem_startup_hook();
221 :
222 : /*
223 : * Create the SLRU directory if it does not exist yet, from the root of
224 : * the data directory.
225 : */
226 2 : (void) MakePGDirectory(slru_dir_name);
227 :
228 : /* initialize the SLRU facility */
229 2 : test_tranche_id = LWLockNewTrancheId();
230 2 : LWLockRegisterTranche(test_tranche_id, "test_slru_tranche");
231 2 : LWLockInitialize(TestSLRULock, test_tranche_id);
232 :
233 2 : TestSlruCtl->PagePrecedes = test_slru_page_precedes_logically;
234 2 : SimpleLruInit(TestSlruCtl, "TestSLRU",
235 : NUM_TEST_BUFFERS, 0, TestSLRULock, slru_dir_name,
236 : test_tranche_id, SYNC_HANDLER_NONE);
237 2 : }
238 :
239 : void
240 2 : _PG_init(void)
241 : {
242 2 : if (!process_shared_preload_libraries_in_progress)
243 0 : ereport(ERROR,
244 : (errmsg("cannot load \"%s\" after startup", "test_slru"),
245 : errdetail("\"%s\" must be loaded with shared_preload_libraries.",
246 : "test_slru")));
247 :
248 2 : prev_shmem_request_hook = shmem_request_hook;
249 2 : shmem_request_hook = test_slru_shmem_request;
250 :
251 2 : prev_shmem_startup_hook = shmem_startup_hook;
252 2 : shmem_startup_hook = test_slru_shmem_startup;
253 2 : }
|