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

Generated by: LCOV version 1.14