1 /*--------------------------------------------------------------------------
4 * Test correctness of SLRU functions.
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * src/test/modules/test_slru/test_slru.c
12 * -------------------------------------------------------------------------
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"
28 * SQL-callable entry points
30 PG_FUNCTION_INFO_V1(test_slru_page_write
);
31 PG_FUNCTION_INFO_V1(test_slru_page_writeall
);
32 PG_FUNCTION_INFO_V1(test_slru_page_read
);
33 PG_FUNCTION_INFO_V1(test_slru_page_readonly
);
34 PG_FUNCTION_INFO_V1(test_slru_page_exists
);
35 PG_FUNCTION_INFO_V1(test_slru_page_sync
);
36 PG_FUNCTION_INFO_V1(test_slru_page_delete
);
37 PG_FUNCTION_INFO_V1(test_slru_page_truncate
);
38 PG_FUNCTION_INFO_V1(test_slru_delete_all
);
40 /* Number of SLRU page slots */
41 #define NUM_TEST_BUFFERS 16
43 static SlruCtlData TestSlruCtlData
;
44 #define TestSlruCtl (&TestSlruCtlData)
46 static shmem_request_hook_type prev_shmem_request_hook
= NULL
;
47 static shmem_startup_hook_type prev_shmem_startup_hook
= NULL
;
50 test_slru_scan_cb(SlruCtl ctl
, char *filename
, int64 segpage
, void *data
)
52 elog(NOTICE
, "Calling test_slru_scan_cb()");
53 return SlruScanDirCbDeleteAll(ctl
, filename
, segpage
, data
);
57 test_slru_page_write(PG_FUNCTION_ARGS
)
59 int64 pageno
= PG_GETARG_INT64(0);
60 char *data
= text_to_cstring(PG_GETARG_TEXT_PP(1));
62 LWLock
*lock
= SimpleLruGetBankLock(TestSlruCtl
, pageno
);
64 LWLockAcquire(lock
, LW_EXCLUSIVE
);
65 slotno
= SimpleLruZeroPage(TestSlruCtl
, pageno
);
67 /* these should match */
68 Assert(TestSlruCtl
->shared
->page_number
[slotno
] == pageno
);
70 /* mark the page as dirty so as it would get written */
71 TestSlruCtl
->shared
->page_dirty
[slotno
] = true;
72 TestSlruCtl
->shared
->page_status
[slotno
] = SLRU_PAGE_VALID
;
74 /* write given data to the page, up to the limit of the page */
75 strncpy(TestSlruCtl
->shared
->page_buffer
[slotno
], data
,
78 SimpleLruWritePage(TestSlruCtl
, slotno
);
85 test_slru_page_writeall(PG_FUNCTION_ARGS
)
87 SimpleLruWriteAll(TestSlruCtl
, true);
92 test_slru_page_read(PG_FUNCTION_ARGS
)
94 int64 pageno
= PG_GETARG_INT64(0);
95 bool write_ok
= PG_GETARG_BOOL(1);
98 LWLock
*lock
= SimpleLruGetBankLock(TestSlruCtl
, pageno
);
100 /* find page in buffers, reading it if necessary */
101 LWLockAcquire(lock
, LW_EXCLUSIVE
);
102 slotno
= SimpleLruReadPage(TestSlruCtl
, pageno
,
103 write_ok
, InvalidTransactionId
);
104 data
= (char *) TestSlruCtl
->shared
->page_buffer
[slotno
];
107 PG_RETURN_TEXT_P(cstring_to_text(data
));
111 test_slru_page_readonly(PG_FUNCTION_ARGS
)
113 int64 pageno
= PG_GETARG_INT64(0);
116 LWLock
*lock
= SimpleLruGetBankLock(TestSlruCtl
, pageno
);
118 /* find page in buffers, reading it if necessary */
119 slotno
= SimpleLruReadPage_ReadOnly(TestSlruCtl
,
121 InvalidTransactionId
);
122 Assert(LWLockHeldByMe(lock
));
123 data
= (char *) TestSlruCtl
->shared
->page_buffer
[slotno
];
126 PG_RETURN_TEXT_P(cstring_to_text(data
));
130 test_slru_page_exists(PG_FUNCTION_ARGS
)
132 int64 pageno
= PG_GETARG_INT64(0);
134 LWLock
*lock
= SimpleLruGetBankLock(TestSlruCtl
, pageno
);
136 LWLockAcquire(lock
, LW_EXCLUSIVE
);
137 found
= SimpleLruDoesPhysicalPageExist(TestSlruCtl
, pageno
);
140 PG_RETURN_BOOL(found
);
144 test_slru_page_sync(PG_FUNCTION_ARGS
)
146 int64 pageno
= PG_GETARG_INT64(0);
148 char path
[MAXPGPATH
];
150 /* note that this flushes the full file a segment is located in */
151 ftag
.segno
= pageno
/ SLRU_PAGES_PER_SEGMENT
;
152 SlruSyncFileTag(TestSlruCtl
, &ftag
, path
);
154 elog(NOTICE
, "Called SlruSyncFileTag() for segment %lld on path %s",
155 (long long) ftag
.segno
, path
);
161 test_slru_page_delete(PG_FUNCTION_ARGS
)
163 int64 pageno
= PG_GETARG_INT64(0);
166 ftag
.segno
= pageno
/ SLRU_PAGES_PER_SEGMENT
;
167 SlruDeleteSegment(TestSlruCtl
, ftag
.segno
);
169 elog(NOTICE
, "Called SlruDeleteSegment() for segment %lld",
170 (long long) ftag
.segno
);
176 test_slru_page_truncate(PG_FUNCTION_ARGS
)
178 int64 pageno
= PG_GETARG_INT64(0);
180 SimpleLruTruncate(TestSlruCtl
, pageno
);
185 test_slru_delete_all(PG_FUNCTION_ARGS
)
187 /* this calls SlruScanDirCbDeleteAll() internally, ensuring deletion */
188 SlruScanDirectory(TestSlruCtl
, test_slru_scan_cb
, NULL
);
194 * Module load callbacks and initialization.
198 test_slru_shmem_request(void)
200 if (prev_shmem_request_hook
)
201 prev_shmem_request_hook();
203 /* reserve shared memory for the test SLRU */
204 RequestAddinShmemSpace(SimpleLruShmemSize(NUM_TEST_BUFFERS
, 0));
208 test_slru_page_precedes_logically(int64 page1
, int64 page2
)
210 return page1
< page2
;
214 test_slru_shmem_startup(void)
217 * Short segments names are well tested elsewhere so in this test we are
218 * focusing on long names.
220 const bool long_segment_names
= true;
221 const char slru_dir_name
[] = "pg_test_slru";
223 int test_buffer_tranche_id
;
225 if (prev_shmem_startup_hook
)
226 prev_shmem_startup_hook();
229 * Create the SLRU directory if it does not exist yet, from the root of
230 * the data directory.
232 (void) MakePGDirectory(slru_dir_name
);
234 /* initialize the SLRU facility */
235 test_tranche_id
= LWLockNewTrancheId();
236 LWLockRegisterTranche(test_tranche_id
, "test_slru_tranche");
238 test_buffer_tranche_id
= LWLockNewTrancheId();
239 LWLockRegisterTranche(test_tranche_id
, "test_buffer_tranche");
241 TestSlruCtl
->PagePrecedes
= test_slru_page_precedes_logically
;
242 SimpleLruInit(TestSlruCtl
, "TestSLRU",
243 NUM_TEST_BUFFERS
, 0, slru_dir_name
,
244 test_buffer_tranche_id
, test_tranche_id
, SYNC_HANDLER_NONE
,
251 if (!process_shared_preload_libraries_in_progress
)
253 (errmsg("cannot load \"%s\" after startup", "test_slru"),
254 errdetail("\"%s\" must be loaded with shared_preload_libraries.",
257 prev_shmem_request_hook
= shmem_request_hook
;
258 shmem_request_hook
= test_slru_shmem_request
;
260 prev_shmem_startup_hook
= shmem_startup_hook
;
261 shmem_startup_hook
= test_slru_shmem_startup
;