LCOV - code coverage report
Current view: top level - src/test/modules/test_slru - test_slru.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 97.0 % 101 98
Test Date: 2026-03-04 04:14:49 Functions: 100.0 % 24 24
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-2026, 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            4 : 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              : 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
      50            1 : test_slru_scan_cb(SlruCtl ctl, char *filename, int64 segpage, void *data)
      51              : {
      52            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              : {
      59           98 :     int64       pageno = PG_GETARG_INT64(0);
      60           98 :     char       *data = text_to_cstring(PG_GETARG_TEXT_PP(1));
      61              :     int         slotno;
      62           98 :     LWLock     *lock = SimpleLruGetBankLock(TestSlruCtl, pageno);
      63              : 
      64           98 :     LWLockAcquire(lock, LW_EXCLUSIVE);
      65           98 :     slotno = SimpleLruZeroPage(TestSlruCtl, pageno);
      66              : 
      67              :     /* these should match */
      68              :     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);
      79           98 :     LWLockRelease(lock);
      80              : 
      81           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              : {
      94            4 :     int64       pageno = PG_GETARG_INT64(0);
      95            4 :     bool        write_ok = PG_GETARG_BOOL(1);
      96            4 :     char       *data = NULL;
      97              :     int         slotno;
      98            4 :     LWLock     *lock = SimpleLruGetBankLock(TestSlruCtl, pageno);
      99              : 
     100              :     /* find page in buffers, reading it if necessary */
     101            4 :     LWLockAcquire(lock, LW_EXCLUSIVE);
     102            4 :     slotno = SimpleLruReadPage(TestSlruCtl, pageno,
     103              :                                write_ok, InvalidTransactionId);
     104            4 :     data = (char *) TestSlruCtl->shared->page_buffer[slotno];
     105            4 :     LWLockRelease(lock);
     106              : 
     107            4 :     PG_RETURN_TEXT_P(cstring_to_text(data));
     108              : }
     109              : 
     110              : Datum
     111            4 : test_slru_page_readonly(PG_FUNCTION_ARGS)
     112              : {
     113            4 :     int64       pageno = PG_GETARG_INT64(0);
     114            4 :     char       *data = NULL;
     115              :     int         slotno;
     116            4 :     LWLock     *lock = SimpleLruGetBankLock(TestSlruCtl, pageno);
     117              : 
     118              :     /* find page in buffers, reading it if necessary */
     119            4 :     slotno = SimpleLruReadPage_ReadOnly(TestSlruCtl,
     120              :                                         pageno,
     121              :                                         InvalidTransactionId);
     122              :     Assert(LWLockHeldByMe(lock));
     123            4 :     data = (char *) TestSlruCtl->shared->page_buffer[slotno];
     124            4 :     LWLockRelease(lock);
     125              : 
     126            4 :     PG_RETURN_TEXT_P(cstring_to_text(data));
     127              : }
     128              : 
     129              : Datum
     130           18 : test_slru_page_exists(PG_FUNCTION_ARGS)
     131              : {
     132           18 :     int64       pageno = PG_GETARG_INT64(0);
     133              :     bool        found;
     134           18 :     LWLock     *lock = SimpleLruGetBankLock(TestSlruCtl, pageno);
     135              : 
     136           18 :     LWLockAcquire(lock, LW_EXCLUSIVE);
     137           18 :     found = SimpleLruDoesPhysicalPageExist(TestSlruCtl, pageno);
     138           18 :     LWLockRelease(lock);
     139              : 
     140           18 :     PG_RETURN_BOOL(found);
     141              : }
     142              : 
     143              : Datum
     144            2 : test_slru_page_sync(PG_FUNCTION_ARGS)
     145              : {
     146            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 */
     151            2 :     ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
     152            2 :     SlruSyncFileTag(TestSlruCtl, &ftag, path);
     153              : 
     154            2 :     elog(NOTICE, "Called SlruSyncFileTag() for segment %" PRIu64 " on path %s",
     155              :          ftag.segno, path);
     156              : 
     157            2 :     PG_RETURN_VOID();
     158              : }
     159              : 
     160              : Datum
     161            2 : test_slru_page_delete(PG_FUNCTION_ARGS)
     162              : {
     163            2 :     int64       pageno = PG_GETARG_INT64(0);
     164              :     FileTag     ftag;
     165              : 
     166            2 :     ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
     167            2 :     SlruDeleteSegment(TestSlruCtl, ftag.segno);
     168              : 
     169            2 :     elog(NOTICE, "Called SlruDeleteSegment() for segment %" PRIu64,
     170              :          ftag.segno);
     171              : 
     172            2 :     PG_RETURN_VOID();
     173              : }
     174              : 
     175              : Datum
     176            2 : test_slru_page_truncate(PG_FUNCTION_ARGS)
     177              : {
     178            2 :     int64       pageno = PG_GETARG_INT64(0);
     179              : 
     180            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            4 : test_slru_shmem_request(void)
     199              : {
     200            4 :     if (prev_shmem_request_hook)
     201            0 :         prev_shmem_request_hook();
     202              : 
     203              :     /* reserve shared memory for the test SLRU */
     204            4 :     RequestAddinShmemSpace(SimpleLruShmemSize(NUM_TEST_BUFFERS, 0));
     205            4 : }
     206              : 
     207              : static bool
     208           15 : test_slru_page_precedes_logically(int64 page1, int64 page2)
     209              : {
     210           15 :     return page1 < page2;
     211              : }
     212              : 
     213              : static void
     214            4 : 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              :      */
     220            4 :     const bool  long_segment_names = true;
     221            4 :     const char  slru_dir_name[] = "pg_test_slru";
     222            4 :     int         test_tranche_id = -1;
     223            4 :     int         test_buffer_tranche_id = -1;
     224              : 
     225            4 :     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            4 :     (void) MakePGDirectory(slru_dir_name);
     233              : 
     234              :     /*
     235              :      * Initialize the SLRU facility.  In EXEC_BACKEND builds, the
     236              :      * shmem_startup_hook is called in the postmaster and in each backend, but
     237              :      * we only need to generate the LWLock tranches once.  Note that these
     238              :      * tranche ID variables are not used by SimpleLruInit() when
     239              :      * IsUnderPostmaster is true.
     240              :      */
     241            4 :     if (!IsUnderPostmaster)
     242              :     {
     243            4 :         test_tranche_id = LWLockNewTrancheId("test_slru_tranche");
     244            4 :         test_buffer_tranche_id = LWLockNewTrancheId("test_buffer_tranche");
     245              :     }
     246              : 
     247            4 :     TestSlruCtl->PagePrecedes = test_slru_page_precedes_logically;
     248            4 :     SimpleLruInit(TestSlruCtl, "TestSLRU",
     249              :                   NUM_TEST_BUFFERS, 0, slru_dir_name,
     250              :                   test_buffer_tranche_id, test_tranche_id, SYNC_HANDLER_NONE,
     251              :                   long_segment_names);
     252            4 : }
     253              : 
     254              : void
     255            4 : _PG_init(void)
     256              : {
     257            4 :     if (!process_shared_preload_libraries_in_progress)
     258            0 :         ereport(ERROR,
     259              :                 (errmsg("cannot load \"%s\" after startup", "test_slru"),
     260              :                  errdetail("\"%s\" must be loaded with \"shared_preload_libraries\".",
     261              :                            "test_slru")));
     262              : 
     263            4 :     prev_shmem_request_hook = shmem_request_hook;
     264            4 :     shmem_request_hook = test_slru_shmem_request;
     265              : 
     266            4 :     prev_shmem_startup_hook = shmem_startup_hook;
     267            4 :     shmem_startup_hook = test_slru_shmem_startup;
     268            4 : }
        

Generated by: LCOV version 2.0-1