LCOV - differential code coverage report
Current view: top level - src/test/modules/test_resowner - test_resowner_many.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: f76c13edadc2b319036e0d238703ed56bb23f934 vs 9e17d25e79d4756be08b4a5521b4b58450217137 Lines: 90.4 % 115 104 11 2 102 2
Current Date: 2026-09-20 14:13:17 +0900 Functions: 87.5 % 8 7 1 1 6
Baseline: lcov-20260920-baseline Branches: 47.5 % 80 38 42 38
Baseline Date: 2026-09-20 14:13:13 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 3 3 2 1
(360..) days: 90.2 % 112 101 11 101
Function coverage date bins:
(360..) days: 87.5 % 8 7 1 1 6
Branch coverage date bins:
(360..) days: 47.5 % 80 38 42 38

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*--------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * test_resowner_many.c
                                  4                 :                :  *      Test ResourceOwner functionality with lots of resources
                                  5                 :                :  *
                                  6                 :                :  * Copyright (c) 2022-2026, PostgreSQL Global Development Group
                                  7                 :                :  *
                                  8                 :                :  * IDENTIFICATION
                                  9                 :                :  *      src/test/modules/test_resowner/test_resowner_many.c
                                 10                 :                :  *
                                 11                 :                :  * -------------------------------------------------------------------------
                                 12                 :                :  */
                                 13                 :                : #include "postgres.h"
                                 14                 :                : 
                                 15                 :                : #include "fmgr.h"
                                 16                 :                : #include "lib/ilist.h"
                                 17                 :                : #include "utils/resowner.h"
                                 18                 :                : 
                                 19                 :                : /*
                                 20                 :                :  * Define a custom resource type to use in the test.  The resource being
                                 21                 :                :  * tracked is a palloc'd ManyTestResource struct.
                                 22                 :                :  *
                                 23                 :                :  * To cross-check that the ResourceOwner calls the callback functions
                                 24                 :                :  * correctly, we keep track of the remembered resources ourselves in a linked
                                 25                 :                :  * list, and also keep counters of how many times the callback functions have
                                 26                 :                :  * been called.
                                 27                 :                :  */
                                 28                 :                : typedef struct
                                 29                 :                : {
                                 30                 :                :     ResourceOwnerDesc desc;
                                 31                 :                :     int         nremembered;
                                 32                 :                :     int         nforgotten;
                                 33                 :                :     int         nreleased;
                                 34                 :                :     int         nleaked;
                                 35                 :                : 
                                 36                 :                :     dlist_head  current_resources;
                                 37                 :                : } ManyTestResourceKind;
                                 38                 :                : 
                                 39                 :                : typedef struct
                                 40                 :                : {
                                 41                 :                :     ManyTestResourceKind *kind;
                                 42                 :                :     dlist_node  node;
                                 43                 :                : } ManyTestResource;
                                 44                 :                : 
                                 45                 :                : /*
                                 46                 :                :  * Priority of last call to the release callback.
                                 47                 :                :  * This is used to check that the resources are released in correct order.
                                 48                 :                :  */
                                 49                 :                : static uint32 last_release_priority = 0;
                                 50                 :                : 
                                 51                 :                : /* prototypes for local functions */
                                 52                 :                : static void ReleaseManyTestResource(Datum res);
                                 53                 :                : static char *PrintManyTest(Datum res);
                                 54                 :                : static void InitManyTestResourceKind(ManyTestResourceKind *kind, char *name,
                                 55                 :                :                                      ResourceReleasePhase phase, uint32 priority);
                                 56                 :                : static void RememberManyTestResources(ResourceOwner owner,
                                 57                 :                :                                       ManyTestResourceKind *kinds, int nkinds,
                                 58                 :                :                                       int nresources);
                                 59                 :                : static void ForgetManyTestResources(ResourceOwner owner,
                                 60                 :                :                                     ManyTestResourceKind *kinds, int nkinds,
                                 61                 :                :                                     int nresources);
                                 62                 :                : static int  GetTotalResourceCount(ManyTestResourceKind *kinds, int nkinds);
                                 63                 :                : 
                                 64                 :                : /* ResourceOwner callback */
                                 65                 :                : static void
 1047 heikki.linnakangas@i       66                 :CBC      199000 : ReleaseManyTestResource(Datum res)
                                 67                 :                : {
                                 68                 :         199000 :     ManyTestResource *mres = (ManyTestResource *) DatumGetPointer(res);
                                 69                 :                : 
                                 70         [ -  + ]:         199000 :     elog(DEBUG1, "releasing resource %p from %s", mres, mres->kind->desc.name);
                                 71         [ -  + ]:         199000 :     Assert(last_release_priority <= mres->kind->desc.release_priority);
                                 72                 :                : 
                                 73                 :         199000 :     dlist_delete(&mres->node);
                                 74                 :         199000 :     mres->kind->nreleased++;
                                 75                 :         199000 :     last_release_priority = mres->kind->desc.release_priority;
                                 76                 :         199000 :     pfree(mres);
                                 77                 :         199000 : }
                                 78                 :                : 
                                 79                 :                : /* ResourceOwner callback */
                                 80                 :                : static char *
 1047 heikki.linnakangas@i       81                 :UBC           0 : PrintManyTest(Datum res)
                                 82                 :                : {
                                 83                 :              0 :     ManyTestResource *mres = (ManyTestResource *) DatumGetPointer(res);
                                 84                 :                : 
                                 85                 :                :     /*
                                 86                 :                :      * XXX: we assume that the DebugPrint function is called once for each
                                 87                 :                :      * leaked resource, and that there are no other callers.
                                 88                 :                :      */
                                 89                 :              0 :     mres->kind->nleaked++;
                                 90                 :                : 
                                 91                 :              0 :     return psprintf("many-test resource from %s", mres->kind->desc.name);
                                 92                 :                : }
                                 93                 :                : 
                                 94                 :                : static void
 1047 heikki.linnakangas@i       95                 :CBC           6 : InitManyTestResourceKind(ManyTestResourceKind *kind, char *name,
                                 96                 :                :                          ResourceReleasePhase phase, uint32 priority)
                                 97                 :                : {
                                 98                 :              6 :     kind->desc.name = name;
                                 99                 :              6 :     kind->desc.release_phase = phase;
                                100                 :              6 :     kind->desc.release_priority = priority;
                                101                 :              6 :     kind->desc.ReleaseResource = ReleaseManyTestResource;
                                102                 :              6 :     kind->desc.DebugPrint = PrintManyTest;
                                103                 :              6 :     kind->nremembered = 0;
                                104                 :              6 :     kind->nforgotten = 0;
                                105                 :              6 :     kind->nreleased = 0;
                                106                 :              6 :     kind->nleaked = 0;
                                107                 :              6 :     dlist_init(&kind->current_resources);
                                108                 :              6 : }
                                109                 :                : 
                                110                 :                : /*
                                111                 :                :  * Remember 'nresources' resources.  The resources are remembered in round
                                112                 :                :  * robin fashion with the kinds from 'kinds' array.
                                113                 :                :  */
                                114                 :                : static void
                                115                 :              2 : RememberManyTestResources(ResourceOwner owner,
                                116                 :                :                           ManyTestResourceKind *kinds, int nkinds,
                                117                 :                :                           int nresources)
                                118                 :                : {
                                119                 :              2 :     int         kind_idx = 0;
                                120                 :                : 
                                121         [ +  + ]:         200002 :     for (int i = 0; i < nresources; i++)
                                122                 :                :     {
  285 michael@paquier.xyz       123                 :         200000 :         ManyTestResource *mres = palloc_object(ManyTestResource);
                                124                 :                : 
 1047 heikki.linnakangas@i      125                 :         200000 :         mres->kind = &kinds[kind_idx];
                                126                 :         200000 :         dlist_node_init(&mres->node);
                                127                 :                : 
                                128                 :         200000 :         ResourceOwnerEnlarge(owner);
                                129                 :         200000 :         ResourceOwnerRemember(owner, PointerGetDatum(mres), &kinds[kind_idx].desc);
                                130                 :         200000 :         kinds[kind_idx].nremembered++;
                                131                 :         200000 :         dlist_push_tail(&kinds[kind_idx].current_resources, &mres->node);
                                132                 :                : 
                                133         [ -  + ]:         200000 :         elog(DEBUG1, "remembered resource %p from %s", mres, mres->kind->desc.name);
                                134                 :                : 
                                135                 :         200000 :         kind_idx = (kind_idx + 1) % nkinds;
                                136                 :                :     }
                                137                 :              2 : }
                                138                 :                : 
                                139                 :                : /*
                                140                 :                :  * Forget 'nresources' resources, in round robin fashion from 'kinds'.
                                141                 :                :  */
                                142                 :                : static void
                                143                 :              2 : ForgetManyTestResources(ResourceOwner owner,
                                144                 :                :                         ManyTestResourceKind *kinds, int nkinds,
                                145                 :                :                         int nresources)
                                146                 :                : {
                                147                 :              2 :     int         kind_idx = 0;
                                148                 :                :     int         ntotal;
                                149                 :                : 
                                150                 :              2 :     ntotal = GetTotalResourceCount(kinds, nkinds);
                                151         [ -  + ]:              2 :     if (ntotal < nresources)
 1047 heikki.linnakangas@i      152         [ #  # ]:UBC           0 :         elog(PANIC, "cannot free %d resources, only %d remembered", nresources, ntotal);
                                153                 :                : 
 1047 heikki.linnakangas@i      154         [ +  + ]:CBC        1002 :     for (int i = 0; i < nresources; i++)
                                155                 :                :     {
                                156                 :           1000 :         bool        found = false;
                                157                 :                : 
                                158         [ +  - ]:           1000 :         for (int j = 0; j < nkinds; j++)
                                159                 :                :         {
                                160                 :           1000 :             kind_idx = (kind_idx + 1) % nkinds;
                                161         [ +  - ]:           1000 :             if (!dlist_is_empty(&kinds[kind_idx].current_resources))
                                162                 :                :             {
                                163                 :           1000 :                 ManyTestResource *mres = dlist_head_element(ManyTestResource, node, &kinds[kind_idx].current_resources);
                                164                 :                : 
                                165                 :           1000 :                 ResourceOwnerForget(owner, PointerGetDatum(mres), &kinds[kind_idx].desc);
                                166                 :           1000 :                 kinds[kind_idx].nforgotten++;
                                167                 :           1000 :                 dlist_delete(&mres->node);
                                168                 :           1000 :                 pfree(mres);
                                169                 :                : 
                                170                 :           1000 :                 found = true;
                                171                 :           1000 :                 break;
                                172                 :                :             }
                                173                 :                :         }
                                174         [ -  + ]:           1000 :         if (!found)
 1047 heikki.linnakangas@i      175         [ #  # ]:UBC           0 :             elog(ERROR, "could not find a test resource to forget");
                                176                 :                :     }
 1047 heikki.linnakangas@i      177                 :CBC           2 : }
                                178                 :                : 
                                179                 :                : /*
                                180                 :                :  * Get total number of currently active resources among 'kinds'.
                                181                 :                :  */
                                182                 :                : static int
                                183                 :              5 : GetTotalResourceCount(ManyTestResourceKind *kinds, int nkinds)
                                184                 :                : {
                                185                 :              5 :     int         ntotal = 0;
                                186                 :                : 
                                187         [ +  + ]:             20 :     for (int i = 0; i < nkinds; i++)
                                188                 :             15 :         ntotal += kinds[i].nremembered - kinds[i].nforgotten - kinds[i].nreleased;
                                189                 :                : 
                                190                 :              5 :     return ntotal;
                                191                 :                : }
                                192                 :                : 
                                193                 :                : /*
                                194                 :                :  * Remember lots of resources, belonging to 'nkinds' different resource types
                                195                 :                :  * with different priorities.  Then forget some of them, and finally, release
                                196                 :                :  * the resource owner.  We use a custom resource type that performs various
                                197                 :                :  * sanity checks to verify that all the resources are released, and in the
                                198                 :                :  * correct order.
                                199                 :                :  */
                                200                 :              2 : PG_FUNCTION_INFO_V1(test_resowner_many);
                                201                 :                : Datum
                                202                 :              1 : test_resowner_many(PG_FUNCTION_ARGS)
                                203                 :                : {
                                204                 :              1 :     int32       nkinds = PG_GETARG_INT32(0);
                                205                 :              1 :     int32       nremember_bl = PG_GETARG_INT32(1);
                                206                 :              1 :     int32       nforget_bl = PG_GETARG_INT32(2);
                                207                 :              1 :     int32       nremember_al = PG_GETARG_INT32(3);
                                208                 :              1 :     int32       nforget_al = PG_GETARG_INT32(4);
                                209                 :                : 
                                210                 :                :     ResourceOwner resowner;
                                211                 :                : 
                                212                 :                :     ManyTestResourceKind *before_kinds;
                                213                 :                :     ManyTestResourceKind *after_kinds;
                                214                 :                : 
                                215                 :                :     /* Sanity check the arguments */
                                216         [ -  + ]:              1 :     if (nkinds < 0)
 1047 heikki.linnakangas@i      217         [ #  # ]:UBC           0 :         elog(ERROR, "nkinds must be >= 0");
 1047 heikki.linnakangas@i      218         [ -  + ]:CBC           1 :     if (nremember_bl < 0)
 1047 heikki.linnakangas@i      219         [ #  # ]:UBC           0 :         elog(ERROR, "nremember_bl must be >= 0");
 1047 heikki.linnakangas@i      220   [ +  -  -  + ]:CBC           1 :     if (nforget_bl < 0 || nforget_bl > nremember_bl)
 1047 heikki.linnakangas@i      221         [ #  # ]:UBC           0 :         elog(ERROR, "nforget_bl must between 0 and 'nremember_bl'");
 1047 heikki.linnakangas@i      222         [ -  + ]:CBC           1 :     if (nremember_al < 0)
 1047 heikki.linnakangas@i      223         [ #  # ]:UBC           0 :         elog(ERROR, "nremember_al must be greater than zero");
 1047 heikki.linnakangas@i      224   [ +  -  -  + ]:CBC           1 :     if (nforget_al < 0 || nforget_al > nremember_al)
 1047 heikki.linnakangas@i      225         [ #  # ]:UBC           0 :         elog(ERROR, "nforget_al must between 0 and 'nremember_al'");
                                226                 :                : 
                                227                 :                :     /* Initialize all the different resource kinds to use */
   34 michael@paquier.xyz       228                 :GNC           1 :     before_kinds = palloc_array(ManyTestResourceKind, nkinds);
 1047 heikki.linnakangas@i      229         [ +  + ]:CBC           4 :     for (int i = 0; i < nkinds; i++)
                                230                 :                :     {
                                231                 :              3 :         InitManyTestResourceKind(&before_kinds[i],
                                232                 :                :                                  psprintf("resource before locks %d", i),
                                233                 :                :                                  RESOURCE_RELEASE_BEFORE_LOCKS,
                                234                 :              3 :                                  RELEASE_PRIO_FIRST + i);
                                235                 :                :     }
   34 michael@paquier.xyz       236                 :GNC           1 :     after_kinds = palloc_array(ManyTestResourceKind, nkinds);
 1047 heikki.linnakangas@i      237         [ +  + ]:CBC           4 :     for (int i = 0; i < nkinds; i++)
                                238                 :                :     {
                                239                 :              3 :         InitManyTestResourceKind(&after_kinds[i],
                                240                 :                :                                  psprintf("resource after locks %d", i),
                                241                 :                :                                  RESOURCE_RELEASE_AFTER_LOCKS,
                                242                 :              3 :                                  RELEASE_PRIO_FIRST + i);
                                243                 :                :     }
                                244                 :                : 
                                245                 :              1 :     resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
                                246                 :                : 
                                247                 :                :     /* Remember a bunch of resources */
                                248         [ +  - ]:              1 :     if (nremember_bl > 0)
                                249                 :                :     {
                                250         [ +  - ]:              1 :         elog(NOTICE, "remembering %d before-locks resources", nremember_bl);
                                251                 :              1 :         RememberManyTestResources(resowner, before_kinds, nkinds, nremember_bl);
                                252                 :                :     }
                                253         [ +  - ]:              1 :     if (nremember_al > 0)
                                254                 :                :     {
                                255         [ +  - ]:              1 :         elog(NOTICE, "remembering %d after-locks resources", nremember_al);
                                256                 :              1 :         RememberManyTestResources(resowner, after_kinds, nkinds, nremember_al);
                                257                 :                :     }
                                258                 :                : 
                                259                 :                :     /* Forget what was remembered */
                                260         [ +  - ]:              1 :     if (nforget_bl > 0)
                                261                 :                :     {
                                262         [ +  - ]:              1 :         elog(NOTICE, "forgetting %d before-locks resources", nforget_bl);
                                263                 :              1 :         ForgetManyTestResources(resowner, before_kinds, nkinds, nforget_bl);
                                264                 :                :     }
                                265                 :                : 
                                266         [ +  - ]:              1 :     if (nforget_al > 0)
                                267                 :                :     {
                                268         [ +  - ]:              1 :         elog(NOTICE, "forgetting %d after-locks resources", nforget_al);
                                269                 :              1 :         ForgetManyTestResources(resowner, after_kinds, nkinds, nforget_al);
                                270                 :                :     }
                                271                 :                : 
                                272                 :                :     /* Start releasing */
                                273         [ +  - ]:              1 :     elog(NOTICE, "releasing resources before locks");
                                274                 :              1 :     last_release_priority = 0;
                                275                 :              1 :     ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, false, false);
                                276         [ -  + ]:              1 :     Assert(GetTotalResourceCount(before_kinds, nkinds) == 0);
                                277                 :                : 
                                278         [ +  - ]:              1 :     elog(NOTICE, "releasing locks");
                                279                 :              1 :     last_release_priority = 0;
                                280                 :              1 :     ResourceOwnerRelease(resowner, RESOURCE_RELEASE_LOCKS, false, false);
                                281                 :                : 
                                282         [ +  - ]:              1 :     elog(NOTICE, "releasing resources after locks");
                                283                 :              1 :     last_release_priority = 0;
                                284                 :              1 :     ResourceOwnerRelease(resowner, RESOURCE_RELEASE_AFTER_LOCKS, false, false);
                                285         [ -  + ]:              1 :     Assert(GetTotalResourceCount(before_kinds, nkinds) == 0);
                                286         [ -  + ]:              1 :     Assert(GetTotalResourceCount(after_kinds, nkinds) == 0);
                                287                 :                : 
                                288                 :              1 :     ResourceOwnerDelete(resowner);
                                289                 :                : 
                                290                 :              1 :     PG_RETURN_VOID();
                                291                 :                : }
        

Generated by: LCOV version 2.0-1