LCOV - code coverage report
Current view: top level - src/test/modules/test_slru - test_slru.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 97 100 97.0 %
Date: 2024-12-03 07:14:52 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-2024, 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           6 : PG_FUNCTION_INFO_V1(test_slru_page_write);
      31           6 : PG_FUNCTION_INFO_V1(test_slru_page_writeall);
      32           6 : PG_FUNCTION_INFO_V1(test_slru_page_read);
      33           6 : PG_FUNCTION_INFO_V1(test_slru_page_readonly);
      34           6 : PG_FUNCTION_INFO_V1(test_slru_page_exists);
      35           6 : PG_FUNCTION_INFO_V1(test_slru_page_sync);
      36           6 : PG_FUNCTION_INFO_V1(test_slru_page_delete);
      37           6 : PG_FUNCTION_INFO_V1(test_slru_page_truncate);
      38           6 : 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           2 : test_slru_scan_cb(SlruCtl ctl, char *filename, int64 segpage, void *data)
      51             : {
      52           2 :     elog(NOTICE, "Calling test_slru_scan_cb()");
      53           2 :     return SlruScanDirCbDeleteAll(ctl, filename, segpage, data);
      54             : }
      55             : 
      56             : Datum
      57         196 : test_slru_page_write(PG_FUNCTION_ARGS)
      58             : {
      59         196 :     int64       pageno = PG_GETARG_INT64(0);
      60         196 :     char       *data = text_to_cstring(PG_GETARG_TEXT_PP(1));
      61             :     int         slotno;
      62         196 :     LWLock     *lock = SimpleLruGetBankLock(TestSlruCtl, pageno);
      63             : 
      64         196 :     LWLockAcquire(lock, LW_EXCLUSIVE);
      65         196 :     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         196 :     TestSlruCtl->shared->page_dirty[slotno] = true;
      72         196 :     TestSlruCtl->shared->page_status[slotno] = SLRU_PAGE_VALID;
      73             : 
      74             :     /* write given data to the page, up to the limit of the page */
      75         196 :     strncpy(TestSlruCtl->shared->page_buffer[slotno], data,
      76             :             BLCKSZ - 1);
      77             : 
      78         196 :     SimpleLruWritePage(TestSlruCtl, slotno);
      79         196 :     LWLockRelease(lock);
      80             : 
      81         196 :     PG_RETURN_VOID();
      82             : }
      83             : 
      84             : Datum
      85           4 : test_slru_page_writeall(PG_FUNCTION_ARGS)
      86             : {
      87           4 :     SimpleLruWriteAll(TestSlruCtl, true);
      88           4 :     PG_RETURN_VOID();
      89             : }
      90             : 
      91             : Datum
      92           8 : test_slru_page_read(PG_FUNCTION_ARGS)
      93             : {
      94           8 :     int64       pageno = PG_GETARG_INT64(0);
      95           8 :     bool        write_ok = PG_GETARG_BOOL(1);
      96           8 :     char       *data = NULL;
      97             :     int         slotno;
      98           8 :     LWLock     *lock = SimpleLruGetBankLock(TestSlruCtl, pageno);
      99             : 
     100             :     /* find page in buffers, reading it if necessary */
     101           8 :     LWLockAcquire(lock, LW_EXCLUSIVE);
     102           8 :     slotno = SimpleLruReadPage(TestSlruCtl, pageno,
     103             :                                write_ok, InvalidTransactionId);
     104           8 :     data = (char *) TestSlruCtl->shared->page_buffer[slotno];
     105           8 :     LWLockRelease(lock);
     106             : 
     107           8 :     PG_RETURN_TEXT_P(cstring_to_text(data));
     108             : }
     109             : 
     110             : Datum
     111           8 : test_slru_page_readonly(PG_FUNCTION_ARGS)
     112             : {
     113           8 :     int64       pageno = PG_GETARG_INT64(0);
     114           8 :     char       *data = NULL;
     115             :     int         slotno;
     116           8 :     LWLock     *lock = SimpleLruGetBankLock(TestSlruCtl, pageno);
     117             : 
     118             :     /* find page in buffers, reading it if necessary */
     119           8 :     slotno = SimpleLruReadPage_ReadOnly(TestSlruCtl,
     120             :                                         pageno,
     121             :                                         InvalidTransactionId);
     122             :     Assert(LWLockHeldByMe(lock));
     123           8 :     data = (char *) TestSlruCtl->shared->page_buffer[slotno];
     124           8 :     LWLockRelease(lock);
     125             : 
     126           8 :     PG_RETURN_TEXT_P(cstring_to_text(data));
     127             : }
     128             : 
     129             : Datum
     130          36 : test_slru_page_exists(PG_FUNCTION_ARGS)
     131             : {
     132          36 :     int64       pageno = PG_GETARG_INT64(0);
     133             :     bool        found;
     134          36 :     LWLock     *lock = SimpleLruGetBankLock(TestSlruCtl, pageno);
     135             : 
     136          36 :     LWLockAcquire(lock, LW_EXCLUSIVE);
     137          36 :     found = SimpleLruDoesPhysicalPageExist(TestSlruCtl, pageno);
     138          36 :     LWLockRelease(lock);
     139             : 
     140          36 :     PG_RETURN_BOOL(found);
     141             : }
     142             : 
     143             : Datum
     144           4 : test_slru_page_sync(PG_FUNCTION_ARGS)
     145             : {
     146           4 :     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           4 :     ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
     152           4 :     SlruSyncFileTag(TestSlruCtl, &ftag, path);
     153             : 
     154           4 :     elog(NOTICE, "Called SlruSyncFileTag() for segment %lld on path %s",
     155             :          (long long) ftag.segno, path);
     156             : 
     157           4 :     PG_RETURN_VOID();
     158             : }
     159             : 
     160             : Datum
     161           4 : test_slru_page_delete(PG_FUNCTION_ARGS)
     162             : {
     163           4 :     int64       pageno = PG_GETARG_INT64(0);
     164             :     FileTag     ftag;
     165             : 
     166           4 :     ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
     167           4 :     SlruDeleteSegment(TestSlruCtl, ftag.segno);
     168             : 
     169           4 :     elog(NOTICE, "Called SlruDeleteSegment() for segment %lld",
     170             :          (long long) ftag.segno);
     171             : 
     172           4 :     PG_RETURN_VOID();
     173             : }
     174             : 
     175             : Datum
     176           4 : test_slru_page_truncate(PG_FUNCTION_ARGS)
     177             : {
     178           4 :     int64       pageno = PG_GETARG_INT64(0);
     179             : 
     180           4 :     SimpleLruTruncate(TestSlruCtl, pageno);
     181           4 :     PG_RETURN_VOID();
     182             : }
     183             : 
     184             : Datum
     185           4 : test_slru_delete_all(PG_FUNCTION_ARGS)
     186             : {
     187             :     /* this calls SlruScanDirCbDeleteAll() internally, ensuring deletion */
     188           4 :     SlruScanDirectory(TestSlruCtl, test_slru_scan_cb, NULL);
     189             : 
     190           4 :     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          30 : test_slru_page_precedes_logically(int64 page1, int64 page2)
     209             : {
     210          30 :     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             :     int         test_tranche_id;
     223             :     int         test_buffer_tranche_id;
     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             :     /* initialize the SLRU facility */
     235           4 :     test_tranche_id = LWLockNewTrancheId();
     236           4 :     LWLockRegisterTranche(test_tranche_id, "test_slru_tranche");
     237             : 
     238           4 :     test_buffer_tranche_id = LWLockNewTrancheId();
     239           4 :     LWLockRegisterTranche(test_tranche_id, "test_buffer_tranche");
     240             : 
     241           4 :     TestSlruCtl->PagePrecedes = test_slru_page_precedes_logically;
     242           4 :     SimpleLruInit(TestSlruCtl, "TestSLRU",
     243             :                   NUM_TEST_BUFFERS, 0, slru_dir_name,
     244             :                   test_buffer_tranche_id, test_tranche_id, SYNC_HANDLER_NONE,
     245             :                   long_segment_names);
     246           4 : }
     247             : 
     248             : void
     249           4 : _PG_init(void)
     250             : {
     251           4 :     if (!process_shared_preload_libraries_in_progress)
     252           0 :         ereport(ERROR,
     253             :                 (errmsg("cannot load \"%s\" after startup", "test_slru"),
     254             :                  errdetail("\"%s\" must be loaded with \"shared_preload_libraries\".",
     255             :                            "test_slru")));
     256             : 
     257           4 :     prev_shmem_request_hook = shmem_request_hook;
     258           4 :     shmem_request_hook = test_slru_shmem_request;
     259             : 
     260           4 :     prev_shmem_startup_hook = shmem_startup_hook;
     261           4 :     shmem_startup_hook = test_slru_shmem_startup;
     262           4 : }

Generated by: LCOV version 1.14