LCOV - code coverage report
Current view: top level - src/test/modules/test_slru - test_slru.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 92 95 96.8 %
Date: 2023-12-11 15:11:28 Functions: 24 24 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14