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

Generated by: LCOV version 2.1-beta2-3-g6141622