Age Owner Branch data TLA Line data Source code
1 : : /*--------------------------------------------------------------------------
2 : : *
3 : : * test_slru.c
4 : : * Test correctness of SLRU functions.
5 : : *
6 : : * Portions Copyright (c) 1996-2024, 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 : :
515 michael@paquier.xyz 25 :CBC 11 : PG_MODULE_MAGIC;
26 : :
27 : : /*
28 : : * SQL-callable entry points
29 : : */
30 : 2 : PG_FUNCTION_INFO_V1(test_slru_page_write);
31 : 2 : PG_FUNCTION_INFO_V1(test_slru_page_writeall);
32 : 2 : PG_FUNCTION_INFO_V1(test_slru_page_read);
33 : 2 : PG_FUNCTION_INFO_V1(test_slru_page_readonly);
34 : 2 : PG_FUNCTION_INFO_V1(test_slru_page_exists);
35 : 2 : PG_FUNCTION_INFO_V1(test_slru_page_sync);
36 : 2 : PG_FUNCTION_INFO_V1(test_slru_page_delete);
37 : 2 : PG_FUNCTION_INFO_V1(test_slru_page_truncate);
38 : 2 : PG_FUNCTION_INFO_V1(test_slru_delete_all);
39 : :
40 : : /* Number of SLRU page slots */
41 : : #define NUM_TEST_BUFFERS 16
42 : :
43 : : static SlruCtlData TestSlruCtlData;
44 : : #define TestSlruCtl (&TestSlruCtlData)
45 : :
46 : : static shmem_request_hook_type prev_shmem_request_hook = NULL;
47 : : static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
48 : :
49 : : static bool
137 akorotkov@postgresql 50 :GNC 1 : test_slru_scan_cb(SlruCtl ctl, char *filename, int64 segpage, void *data)
51 : : {
515 michael@paquier.xyz 52 [ + - ]:CBC 1 : elog(NOTICE, "Calling test_slru_scan_cb()");
53 : 1 : return SlruScanDirCbDeleteAll(ctl, filename, segpage, data);
54 : : }
55 : :
56 : : Datum
57 : 98 : test_slru_page_write(PG_FUNCTION_ARGS)
58 : : {
137 akorotkov@postgresql 59 :GNC 98 : int64 pageno = PG_GETARG_INT64(0);
515 michael@paquier.xyz 60 :CBC 98 : char *data = text_to_cstring(PG_GETARG_TEXT_PP(1));
61 : : int slotno;
46 alvherre@alvh.no-ip. 62 :GNC 98 : LWLock *lock = SimpleLruGetBankLock(TestSlruCtl, pageno);
63 : :
64 : 98 : LWLockAcquire(lock, LW_EXCLUSIVE);
515 michael@paquier.xyz 65 :CBC 98 : slotno = SimpleLruZeroPage(TestSlruCtl, pageno);
66 : :
67 : : /* these should match */
68 [ - + ]: 98 : Assert(TestSlruCtl->shared->page_number[slotno] == pageno);
69 : :
70 : : /* mark the page as dirty so as it would get written */
71 : 98 : TestSlruCtl->shared->page_dirty[slotno] = true;
72 : 98 : TestSlruCtl->shared->page_status[slotno] = SLRU_PAGE_VALID;
73 : :
74 : : /* write given data to the page, up to the limit of the page */
75 : 98 : strncpy(TestSlruCtl->shared->page_buffer[slotno], data,
76 : : BLCKSZ - 1);
77 : :
78 : 98 : SimpleLruWritePage(TestSlruCtl, slotno);
46 alvherre@alvh.no-ip. 79 :GNC 98 : LWLockRelease(lock);
80 : :
515 michael@paquier.xyz 81 :CBC 98 : PG_RETURN_VOID();
82 : : }
83 : :
84 : : Datum
85 : 2 : test_slru_page_writeall(PG_FUNCTION_ARGS)
86 : : {
87 : 2 : SimpleLruWriteAll(TestSlruCtl, true);
88 : 2 : PG_RETURN_VOID();
89 : : }
90 : :
91 : : Datum
92 : 4 : test_slru_page_read(PG_FUNCTION_ARGS)
93 : : {
137 akorotkov@postgresql 94 :GNC 4 : int64 pageno = PG_GETARG_INT64(0);
515 michael@paquier.xyz 95 :CBC 4 : bool write_ok = PG_GETARG_BOOL(1);
96 : 4 : char *data = NULL;
97 : : int slotno;
46 alvherre@alvh.no-ip. 98 :GNC 4 : LWLock *lock = SimpleLruGetBankLock(TestSlruCtl, pageno);
99 : :
100 : : /* find page in buffers, reading it if necessary */
101 : 4 : LWLockAcquire(lock, LW_EXCLUSIVE);
515 michael@paquier.xyz 102 :CBC 4 : slotno = SimpleLruReadPage(TestSlruCtl, pageno,
103 : : write_ok, InvalidTransactionId);
104 : 4 : data = (char *) TestSlruCtl->shared->page_buffer[slotno];
46 alvherre@alvh.no-ip. 105 :GNC 4 : LWLockRelease(lock);
106 : :
515 michael@paquier.xyz 107 :CBC 4 : PG_RETURN_TEXT_P(cstring_to_text(data));
108 : : }
109 : :
110 : : Datum
111 : 4 : test_slru_page_readonly(PG_FUNCTION_ARGS)
112 : : {
137 akorotkov@postgresql 113 :GNC 4 : int64 pageno = PG_GETARG_INT64(0);
515 michael@paquier.xyz 114 :CBC 4 : char *data = NULL;
115 : : int slotno;
46 alvherre@alvh.no-ip. 116 :GNC 4 : LWLock *lock = SimpleLruGetBankLock(TestSlruCtl, pageno);
117 : :
118 : : /* find page in buffers, reading it if necessary */
515 michael@paquier.xyz 119 :CBC 4 : slotno = SimpleLruReadPage_ReadOnly(TestSlruCtl,
120 : : pageno,
121 : : InvalidTransactionId);
46 alvherre@alvh.no-ip. 122 [ - + ]:GNC 4 : Assert(LWLockHeldByMe(lock));
515 michael@paquier.xyz 123 :CBC 4 : data = (char *) TestSlruCtl->shared->page_buffer[slotno];
46 alvherre@alvh.no-ip. 124 :GNC 4 : LWLockRelease(lock);
125 : :
515 michael@paquier.xyz 126 :CBC 4 : PG_RETURN_TEXT_P(cstring_to_text(data));
127 : : }
128 : :
129 : : Datum
130 : 18 : test_slru_page_exists(PG_FUNCTION_ARGS)
131 : : {
137 akorotkov@postgresql 132 :GNC 18 : int64 pageno = PG_GETARG_INT64(0);
133 : : bool found;
46 alvherre@alvh.no-ip. 134 : 18 : LWLock *lock = SimpleLruGetBankLock(TestSlruCtl, pageno);
135 : :
136 : 18 : LWLockAcquire(lock, LW_EXCLUSIVE);
515 michael@paquier.xyz 137 :CBC 18 : found = SimpleLruDoesPhysicalPageExist(TestSlruCtl, pageno);
46 alvherre@alvh.no-ip. 138 :GNC 18 : LWLockRelease(lock);
139 : :
515 michael@paquier.xyz 140 :CBC 18 : PG_RETURN_BOOL(found);
141 : : }
142 : :
143 : : Datum
144 : 2 : test_slru_page_sync(PG_FUNCTION_ARGS)
145 : : {
137 akorotkov@postgresql 146 :GNC 2 : int64 pageno = PG_GETARG_INT64(0);
147 : : FileTag ftag;
148 : : char path[MAXPGPATH];
149 : :
150 : : /* note that this flushes the full file a segment is located in */
515 michael@paquier.xyz 151 :CBC 2 : ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
152 : 2 : SlruSyncFileTag(TestSlruCtl, &ftag, path);
153 : :
137 akorotkov@postgresql 154 [ + - ]:GNC 2 : elog(NOTICE, "Called SlruSyncFileTag() for segment %lld on path %s",
155 : : (long long) ftag.segno, path);
156 : :
515 michael@paquier.xyz 157 :CBC 2 : PG_RETURN_VOID();
158 : : }
159 : :
160 : : Datum
161 : 2 : test_slru_page_delete(PG_FUNCTION_ARGS)
162 : : {
137 akorotkov@postgresql 163 :GNC 2 : int64 pageno = PG_GETARG_INT64(0);
164 : : FileTag ftag;
165 : :
515 michael@paquier.xyz 166 :CBC 2 : ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
167 : 2 : SlruDeleteSegment(TestSlruCtl, ftag.segno);
168 : :
137 akorotkov@postgresql 169 [ + - ]:GNC 2 : elog(NOTICE, "Called SlruDeleteSegment() for segment %lld",
170 : : (long long) ftag.segno);
171 : :
515 michael@paquier.xyz 172 :CBC 2 : PG_RETURN_VOID();
173 : : }
174 : :
175 : : Datum
176 : 2 : test_slru_page_truncate(PG_FUNCTION_ARGS)
177 : : {
137 akorotkov@postgresql 178 :GNC 2 : int64 pageno = PG_GETARG_INT64(0);
179 : :
515 michael@paquier.xyz 180 :CBC 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 : 11 : test_slru_shmem_request(void)
199 : : {
200 [ - + ]: 11 : if (prev_shmem_request_hook)
515 michael@paquier.xyz 201 :UBC 0 : prev_shmem_request_hook();
202 : :
203 : : /* reserve shared memory for the test SLRU */
515 michael@paquier.xyz 204 :CBC 11 : RequestAddinShmemSpace(SimpleLruShmemSize(NUM_TEST_BUFFERS, 0));
205 : 11 : }
206 : :
207 : : static bool
137 akorotkov@postgresql 208 :GNC 30 : test_slru_page_precedes_logically(int64 page1, int64 page2)
209 : : {
515 michael@paquier.xyz 210 :CBC 30 : return page1 < page2;
211 : : }
212 : :
213 : : static void
214 : 11 : test_slru_shmem_startup(void)
215 : : {
216 : : /*
217 : : * Short segments names are well tested elsewhere so in this test we are
218 : : * focusing on long names.
219 : : */
137 akorotkov@postgresql 220 :GNC 11 : const bool long_segment_names = true;
515 michael@paquier.xyz 221 :CBC 11 : const char slru_dir_name[] = "pg_test_slru";
222 : : int test_tranche_id;
223 : : int test_buffer_tranche_id;
224 : :
225 [ - + ]: 11 : if (prev_shmem_startup_hook)
515 michael@paquier.xyz 226 :UBC 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 : : */
515 michael@paquier.xyz 232 :CBC 11 : (void) MakePGDirectory(slru_dir_name);
233 : :
234 : : /* initialize the SLRU facility */
235 : 11 : test_tranche_id = LWLockNewTrancheId();
236 : 11 : LWLockRegisterTranche(test_tranche_id, "test_slru_tranche");
237 : :
46 alvherre@alvh.no-ip. 238 :GNC 11 : test_buffer_tranche_id = LWLockNewTrancheId();
239 : 11 : LWLockRegisterTranche(test_tranche_id, "test_buffer_tranche");
240 : :
515 michael@paquier.xyz 241 :CBC 11 : TestSlruCtl->PagePrecedes = test_slru_page_precedes_logically;
242 : 11 : SimpleLruInit(TestSlruCtl, "TestSLRU",
243 : : NUM_TEST_BUFFERS, 0, slru_dir_name,
244 : : test_buffer_tranche_id, test_tranche_id, SYNC_HANDLER_NONE,
245 : : long_segment_names);
246 : 11 : }
247 : :
248 : : void
249 : 11 : _PG_init(void)
250 : : {
251 [ - + ]: 11 : if (!process_shared_preload_libraries_in_progress)
515 michael@paquier.xyz 252 [ # # ]:UBC 0 : ereport(ERROR,
253 : : (errmsg("cannot load \"%s\" after startup", "test_slru"),
254 : : errdetail("\"%s\" must be loaded with shared_preload_libraries.",
255 : : "test_slru")));
256 : :
515 michael@paquier.xyz 257 :CBC 11 : prev_shmem_request_hook = shmem_request_hook;
258 : 11 : shmem_request_hook = test_slru_shmem_request;
259 : :
260 : 11 : prev_shmem_startup_hook = shmem_startup_hook;
261 : 11 : shmem_startup_hook = test_slru_shmem_startup;
262 : 11 : }
|