LCOV - code coverage report
Current view: top level - src/test/modules/test_resowner - test_resowner_basic.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 79 84 94.0 %
Date: 2024-12-02 20:15:07 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*--------------------------------------------------------------------------
       2             :  *
       3             :  * test_resowner_basic.c
       4             :  *      Test basic ResourceOwner functionality
       5             :  *
       6             :  * Copyright (c) 2022-2024, PostgreSQL Global Development Group
       7             :  *
       8             :  * IDENTIFICATION
       9             :  *      src/test/modules/test_resowner/test_resowner_basic.c
      10             :  *
      11             :  * -------------------------------------------------------------------------
      12             :  */
      13             : #include "postgres.h"
      14             : 
      15             : #include "fmgr.h"
      16             : #include "utils/resowner.h"
      17             : 
      18           2 : PG_MODULE_MAGIC;
      19             : 
      20             : static void ReleaseString(Datum res);
      21             : static char *PrintString(Datum res);
      22             : 
      23             : /*
      24             :  * A resource that tracks strings and prints the string when it's released.
      25             :  * This makes the order that the resources are released visible.
      26             :  */
      27             : static const ResourceOwnerDesc string_desc = {
      28             :     .name = "test resource",
      29             :     .release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
      30             :     .release_priority = RELEASE_PRIO_FIRST,
      31             :     .ReleaseResource = ReleaseString,
      32             :     .DebugPrint = PrintString
      33             : };
      34             : 
      35             : static void
      36         284 : ReleaseString(Datum res)
      37             : {
      38         284 :     elog(NOTICE, "releasing string: %s", DatumGetPointer(res));
      39         284 : }
      40             : 
      41             : static char *
      42           2 : PrintString(Datum res)
      43             : {
      44           2 :     return psprintf("test string \"%s\"", DatumGetPointer(res));
      45             : }
      46             : 
      47             : /* demonstrates phases and priorities between a parent and child context */
      48           4 : PG_FUNCTION_INFO_V1(test_resowner_priorities);
      49             : Datum
      50           4 : test_resowner_priorities(PG_FUNCTION_ARGS)
      51             : {
      52           4 :     int32       nkinds = PG_GETARG_INT32(0);
      53           4 :     int32       nresources = PG_GETARG_INT32(1);
      54             :     ResourceOwner parent,
      55             :                 child;
      56             :     ResourceOwnerDesc *before_desc;
      57             :     ResourceOwnerDesc *after_desc;
      58             : 
      59           4 :     if (nkinds <= 0)
      60           0 :         elog(ERROR, "nkinds must be greater than zero");
      61           4 :     if (nresources <= 0)
      62           0 :         elog(ERROR, "nresources must be greater than zero");
      63             : 
      64           4 :     parent = ResourceOwnerCreate(CurrentResourceOwner, "test parent");
      65           4 :     child = ResourceOwnerCreate(parent, "test child");
      66             : 
      67           4 :     before_desc = palloc(nkinds * sizeof(ResourceOwnerDesc));
      68          12 :     for (int i = 0; i < nkinds; i++)
      69             :     {
      70           8 :         before_desc[i].name = psprintf("test resource before locks %d", i);
      71           8 :         before_desc[i].release_phase = RESOURCE_RELEASE_BEFORE_LOCKS;
      72           8 :         before_desc[i].release_priority = RELEASE_PRIO_FIRST + i;
      73           8 :         before_desc[i].ReleaseResource = ReleaseString;
      74           8 :         before_desc[i].DebugPrint = PrintString;
      75             :     }
      76           4 :     after_desc = palloc(nkinds * sizeof(ResourceOwnerDesc));
      77          12 :     for (int i = 0; i < nkinds; i++)
      78             :     {
      79           8 :         after_desc[i].name = psprintf("test resource after locks %d", i);
      80           8 :         after_desc[i].release_phase = RESOURCE_RELEASE_AFTER_LOCKS;
      81           8 :         after_desc[i].release_priority = RELEASE_PRIO_FIRST + i;
      82           8 :         after_desc[i].ReleaseResource = ReleaseString;
      83           8 :         after_desc[i].DebugPrint = PrintString;
      84             :     }
      85             : 
      86             :     /* Add a bunch of resources to child, with different priorities */
      87          74 :     for (int i = 0; i < nresources; i++)
      88             :     {
      89          70 :         ResourceOwnerDesc *kind = &before_desc[i % nkinds];
      90             : 
      91          70 :         ResourceOwnerEnlarge(child);
      92          70 :         ResourceOwnerRemember(child,
      93          70 :                               CStringGetDatum(psprintf("child before locks priority %d", kind->release_priority)),
      94             :                               kind);
      95             :     }
      96          74 :     for (int i = 0; i < nresources; i++)
      97             :     {
      98          70 :         ResourceOwnerDesc *kind = &after_desc[i % nkinds];
      99             : 
     100          70 :         ResourceOwnerEnlarge(child);
     101          70 :         ResourceOwnerRemember(child,
     102          70 :                               CStringGetDatum(psprintf("child after locks priority %d", kind->release_priority)),
     103             :                               kind);
     104             :     }
     105             : 
     106             :     /* And also to the parent */
     107          74 :     for (int i = 0; i < nresources; i++)
     108             :     {
     109          70 :         ResourceOwnerDesc *kind = &after_desc[i % nkinds];
     110             : 
     111          70 :         ResourceOwnerEnlarge(parent);
     112          70 :         ResourceOwnerRemember(parent,
     113          70 :                               CStringGetDatum(psprintf("parent after locks priority %d", kind->release_priority)),
     114             :                               kind);
     115             :     }
     116          74 :     for (int i = 0; i < nresources; i++)
     117             :     {
     118          70 :         ResourceOwnerDesc *kind = &before_desc[i % nkinds];
     119             : 
     120          70 :         ResourceOwnerEnlarge(parent);
     121          70 :         ResourceOwnerRemember(parent,
     122          70 :                               CStringGetDatum(psprintf("parent before locks priority %d", kind->release_priority)),
     123             :                               kind);
     124             :     }
     125             : 
     126           4 :     elog(NOTICE, "releasing resources before locks");
     127           4 :     ResourceOwnerRelease(parent, RESOURCE_RELEASE_BEFORE_LOCKS, false, false);
     128           4 :     elog(NOTICE, "releasing locks");
     129           4 :     ResourceOwnerRelease(parent, RESOURCE_RELEASE_LOCKS, false, false);
     130           4 :     elog(NOTICE, "releasing resources after locks");
     131           4 :     ResourceOwnerRelease(parent, RESOURCE_RELEASE_AFTER_LOCKS, false, false);
     132             : 
     133           4 :     ResourceOwnerDelete(parent);
     134             : 
     135           4 :     PG_RETURN_VOID();
     136             : }
     137             : 
     138           4 : PG_FUNCTION_INFO_V1(test_resowner_leak);
     139             : Datum
     140           2 : test_resowner_leak(PG_FUNCTION_ARGS)
     141             : {
     142             :     ResourceOwner resowner;
     143             : 
     144           2 :     resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
     145             : 
     146           2 :     ResourceOwnerEnlarge(resowner);
     147             : 
     148           2 :     ResourceOwnerRemember(resowner, CStringGetDatum("my string"), &string_desc);
     149             : 
     150             :     /* don't call ResourceOwnerForget, so that it is leaked */
     151             : 
     152           2 :     ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, true, false);
     153           2 :     ResourceOwnerRelease(resowner, RESOURCE_RELEASE_LOCKS, true, false);
     154           2 :     ResourceOwnerRelease(resowner, RESOURCE_RELEASE_AFTER_LOCKS, true, false);
     155             : 
     156           2 :     ResourceOwnerDelete(resowner);
     157             : 
     158           2 :     PG_RETURN_VOID();
     159             : }
     160             : 
     161           4 : PG_FUNCTION_INFO_V1(test_resowner_remember_between_phases);
     162             : Datum
     163           2 : test_resowner_remember_between_phases(PG_FUNCTION_ARGS)
     164             : {
     165             :     ResourceOwner resowner;
     166             : 
     167           2 :     resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
     168             : 
     169           2 :     ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, true, false);
     170             : 
     171             :     /*
     172             :      * Try to remember a new resource.  Fails because we already called
     173             :      * ResourceOwnerRelease.
     174             :      */
     175           2 :     ResourceOwnerEnlarge(resowner);
     176           0 :     ResourceOwnerRemember(resowner, CStringGetDatum("my string"), &string_desc);
     177             : 
     178             :     /* unreachable */
     179           0 :     elog(ERROR, "ResourceOwnerEnlarge should have errored out");
     180             : 
     181             :     PG_RETURN_VOID();
     182             : }
     183             : 
     184           4 : PG_FUNCTION_INFO_V1(test_resowner_forget_between_phases);
     185             : Datum
     186           2 : test_resowner_forget_between_phases(PG_FUNCTION_ARGS)
     187             : {
     188             :     ResourceOwner resowner;
     189             :     Datum       str_resource;
     190             : 
     191           2 :     resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
     192             : 
     193           2 :     ResourceOwnerEnlarge(resowner);
     194           2 :     str_resource = CStringGetDatum("my string");
     195           2 :     ResourceOwnerRemember(resowner, str_resource, &string_desc);
     196             : 
     197           2 :     ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, true, false);
     198             : 
     199             :     /*
     200             :      * Try to forget the resource that was remembered earlier.  Fails because
     201             :      * we already called ResourceOwnerRelease.
     202             :      */
     203           2 :     ResourceOwnerForget(resowner, str_resource, &string_desc);
     204             : 
     205             :     /* unreachable */
     206           0 :     elog(ERROR, "ResourceOwnerForget should have errored out");
     207             : 
     208             :     PG_RETURN_VOID();
     209             : }

Generated by: LCOV version 1.14