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