/*-------------------------------------------------------------------------- * * test_slru.c * Test correctness of SLRU functions. * * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * src/test/modules/test_slru/test_slru.c * * ------------------------------------------------------------------------- */ #include "postgres.h" #include "access/slru.h" #include "access/transam.h" #include "miscadmin.h" #include "storage/fd.h" #include "storage/ipc.h" #include "storage/shmem.h" #include "utils/builtins.h" PG_MODULE_MAGIC; /* * SQL-callable entry points */ PG_FUNCTION_INFO_V1(test_slru_page_write); PG_FUNCTION_INFO_V1(test_slru_page_writeall); PG_FUNCTION_INFO_V1(test_slru_page_read); PG_FUNCTION_INFO_V1(test_slru_page_readonly); PG_FUNCTION_INFO_V1(test_slru_page_exists); PG_FUNCTION_INFO_V1(test_slru_page_sync); PG_FUNCTION_INFO_V1(test_slru_page_delete); PG_FUNCTION_INFO_V1(test_slru_page_truncate); PG_FUNCTION_INFO_V1(test_slru_delete_all); /* Number of SLRU page slots */ #define NUM_TEST_BUFFERS 16 /* SLRU control lock */ LWLock TestSLRULock; #define TestSLRULock (&TestSLRULock) static SlruCtlData TestSlruCtlData; #define TestSlruCtl (&TestSlruCtlData) static shmem_request_hook_type prev_shmem_request_hook = NULL; static shmem_startup_hook_type prev_shmem_startup_hook = NULL; static bool test_slru_scan_cb(SlruCtl ctl, char *filename, int segpage, void *data) { elog(NOTICE, "Calling test_slru_scan_cb()"); return SlruScanDirCbDeleteAll(ctl, filename, segpage, data); } Datum test_slru_page_write(PG_FUNCTION_ARGS) { int pageno = PG_GETARG_INT32(0); char *data = text_to_cstring(PG_GETARG_TEXT_PP(1)); int slotno; LWLockAcquire(TestSLRULock, LW_EXCLUSIVE); slotno = SimpleLruZeroPage(TestSlruCtl, pageno); /* these should match */ Assert(TestSlruCtl->shared->page_number[slotno] == pageno); /* mark the page as dirty so as it would get written */ TestSlruCtl->shared->page_dirty[slotno] = true; TestSlruCtl->shared->page_status[slotno] = SLRU_PAGE_VALID; /* write given data to the page, up to the limit of the page */ strncpy(TestSlruCtl->shared->page_buffer[slotno], data, BLCKSZ - 1); SimpleLruWritePage(TestSlruCtl, slotno); LWLockRelease(TestSLRULock); PG_RETURN_VOID(); } Datum test_slru_page_writeall(PG_FUNCTION_ARGS) { SimpleLruWriteAll(TestSlruCtl, true); PG_RETURN_VOID(); } Datum test_slru_page_read(PG_FUNCTION_ARGS) { int pageno = PG_GETARG_INT32(0); bool write_ok = PG_GETARG_BOOL(1); char *data = NULL; int slotno; /* find page in buffers, reading it if necessary */ LWLockAcquire(TestSLRULock, LW_EXCLUSIVE); slotno = SimpleLruReadPage(TestSlruCtl, pageno, write_ok, InvalidTransactionId); data = (char *) TestSlruCtl->shared->page_buffer[slotno]; LWLockRelease(TestSLRULock); PG_RETURN_TEXT_P(cstring_to_text(data)); } Datum test_slru_page_readonly(PG_FUNCTION_ARGS) { int pageno = PG_GETARG_INT32(0); char *data = NULL; int slotno; /* find page in buffers, reading it if necessary */ slotno = SimpleLruReadPage_ReadOnly(TestSlruCtl, pageno, InvalidTransactionId); Assert(LWLockHeldByMe(TestSLRULock)); data = (char *) TestSlruCtl->shared->page_buffer[slotno]; LWLockRelease(TestSLRULock); PG_RETURN_TEXT_P(cstring_to_text(data)); } Datum test_slru_page_exists(PG_FUNCTION_ARGS) { int pageno = PG_GETARG_INT32(0); bool found; LWLockAcquire(TestSLRULock, LW_EXCLUSIVE); found = SimpleLruDoesPhysicalPageExist(TestSlruCtl, pageno); LWLockRelease(TestSLRULock); PG_RETURN_BOOL(found); } Datum test_slru_page_sync(PG_FUNCTION_ARGS) { int pageno = PG_GETARG_INT32(0); FileTag ftag; char path[MAXPGPATH]; /* note that this flushes the full file a segment is located in */ ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT; SlruSyncFileTag(TestSlruCtl, &ftag, path); elog(NOTICE, "Called SlruSyncFileTag() for segment %u on path %s", ftag.segno, path); PG_RETURN_VOID(); } Datum test_slru_page_delete(PG_FUNCTION_ARGS) { int pageno = PG_GETARG_INT32(0); FileTag ftag; ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT; SlruDeleteSegment(TestSlruCtl, ftag.segno); elog(NOTICE, "Called SlruDeleteSegment() for segment %u", ftag.segno); PG_RETURN_VOID(); } Datum test_slru_page_truncate(PG_FUNCTION_ARGS) { int pageno = PG_GETARG_INT32(0); SimpleLruTruncate(TestSlruCtl, pageno); PG_RETURN_VOID(); } Datum test_slru_delete_all(PG_FUNCTION_ARGS) { /* this calls SlruScanDirCbDeleteAll() internally, ensuring deletion */ SlruScanDirectory(TestSlruCtl, test_slru_scan_cb, NULL); PG_RETURN_VOID(); } /* * Module load callbacks and initialization. */ static void test_slru_shmem_request(void) { if (prev_shmem_request_hook) prev_shmem_request_hook(); /* reserve shared memory for the test SLRU */ RequestAddinShmemSpace(SimpleLruShmemSize(NUM_TEST_BUFFERS, 0)); } static bool test_slru_page_precedes_logically(int page1, int page2) { return page1 < page2; } static void test_slru_shmem_startup(void) { const char slru_dir_name[] = "pg_test_slru"; int test_tranche_id; if (prev_shmem_startup_hook) prev_shmem_startup_hook(); /* * Create the SLRU directory if it does not exist yet, from the root of * the data directory. */ (void) MakePGDirectory(slru_dir_name); /* initialize the SLRU facility */ test_tranche_id = LWLockNewTrancheId(); LWLockRegisterTranche(test_tranche_id, "test_slru_tranche"); LWLockInitialize(TestSLRULock, test_tranche_id); TestSlruCtl->PagePrecedes = test_slru_page_precedes_logically; SimpleLruInit(TestSlruCtl, "TestSLRU", NUM_TEST_BUFFERS, 0, TestSLRULock, slru_dir_name, test_tranche_id, SYNC_HANDLER_NONE); } void _PG_init(void) { if (!process_shared_preload_libraries_in_progress) ereport(ERROR, (errmsg("cannot load \"%s\" after startup", "test_slru"), errdetail("\"%s\" must be loaded with shared_preload_libraries.", "test_slru"))); prev_shmem_request_hook = shmem_request_hook; shmem_request_hook = test_slru_shmem_request; prev_shmem_startup_hook = shmem_startup_hook; shmem_startup_hook = test_slru_shmem_startup; }