LCOV - code coverage report
Current view: top level - src/backend/utils/resowner - resowner.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 365 432 84.5 %
Date: 2023-10-01 21:10:56 Functions: 58 67 86.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * resowner.c
       4             :  *    POSTGRES resource owner management code.
       5             :  *
       6             :  * Query-lifespan resources are tracked by associating them with
       7             :  * ResourceOwner objects.  This provides a simple mechanism for ensuring
       8             :  * that such resources are freed at the right time.
       9             :  * See utils/resowner/README for more info.
      10             :  *
      11             :  *
      12             :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
      13             :  * Portions Copyright (c) 1994, Regents of the University of California
      14             :  *
      15             :  *
      16             :  * IDENTIFICATION
      17             :  *    src/backend/utils/resowner/resowner.c
      18             :  *
      19             :  *-------------------------------------------------------------------------
      20             :  */
      21             : #include "postgres.h"
      22             : 
      23             : #include "common/cryptohash.h"
      24             : #include "common/hashfn.h"
      25             : #include "common/hmac.h"
      26             : #include "jit/jit.h"
      27             : #include "storage/bufmgr.h"
      28             : #include "storage/ipc.h"
      29             : #include "storage/predicate.h"
      30             : #include "storage/proc.h"
      31             : #include "utils/memutils.h"
      32             : #include "utils/rel.h"
      33             : #include "utils/resowner_private.h"
      34             : #include "utils/snapmgr.h"
      35             : 
      36             : 
      37             : /*
      38             :  * All resource IDs managed by this code are required to fit into a Datum,
      39             :  * which is fine since they are generally pointers or integers.
      40             :  *
      41             :  * Provide Datum conversion macros for a couple of things that are really
      42             :  * just "int".
      43             :  */
      44             : #define FileGetDatum(file) Int32GetDatum(file)
      45             : #define DatumGetFile(datum) ((File) DatumGetInt32(datum))
      46             : #define BufferGetDatum(buffer) Int32GetDatum(buffer)
      47             : #define DatumGetBuffer(datum) ((Buffer) DatumGetInt32(datum))
      48             : 
      49             : /*
      50             :  * ResourceArray is a common structure for storing all types of resource IDs.
      51             :  *
      52             :  * We manage small sets of resource IDs by keeping them in a simple array:
      53             :  * itemsarr[k] holds an ID, for 0 <= k < nitems <= maxitems = capacity.
      54             :  *
      55             :  * If a set grows large, we switch over to using open-addressing hashing.
      56             :  * Then, itemsarr[] is a hash table of "capacity" slots, with each
      57             :  * slot holding either an ID or "invalidval".  nitems is the number of valid
      58             :  * items present; if it would exceed maxitems, we enlarge the array and
      59             :  * re-hash.  In this mode, maxitems should be rather less than capacity so
      60             :  * that we don't waste too much time searching for empty slots.
      61             :  *
      62             :  * In either mode, lastidx remembers the location of the last item inserted
      63             :  * or returned by GetAny; this speeds up searches in ResourceArrayRemove.
      64             :  */
      65             : typedef struct ResourceArray
      66             : {
      67             :     Datum      *itemsarr;       /* buffer for storing values */
      68             :     Datum       invalidval;     /* value that is considered invalid */
      69             :     uint32      capacity;       /* allocated length of itemsarr[] */
      70             :     uint32      nitems;         /* how many items are stored in items array */
      71             :     uint32      maxitems;       /* current limit on nitems before enlarging */
      72             :     uint32      lastidx;        /* index of last item returned by GetAny */
      73             : } ResourceArray;
      74             : 
      75             : /*
      76             :  * Initially allocated size of a ResourceArray.  Must be power of two since
      77             :  * we'll use (arraysize - 1) as mask for hashing.
      78             :  */
      79             : #define RESARRAY_INIT_SIZE 16
      80             : 
      81             : /*
      82             :  * When to switch to hashing vs. simple array logic in a ResourceArray.
      83             :  */
      84             : #define RESARRAY_MAX_ARRAY 64
      85             : #define RESARRAY_IS_ARRAY(resarr) ((resarr)->capacity <= RESARRAY_MAX_ARRAY)
      86             : 
      87             : /*
      88             :  * How many items may be stored in a resource array of given capacity.
      89             :  * When this number is reached, we must resize.
      90             :  */
      91             : #define RESARRAY_MAX_ITEMS(capacity) \
      92             :     ((capacity) <= RESARRAY_MAX_ARRAY ? (capacity) : (capacity)/4 * 3)
      93             : 
      94             : /*
      95             :  * To speed up bulk releasing or reassigning locks from a resource owner to
      96             :  * its parent, each resource owner has a small cache of locks it owns. The
      97             :  * lock manager has the same information in its local lock hash table, and
      98             :  * we fall back on that if cache overflows, but traversing the hash table
      99             :  * is slower when there are a lot of locks belonging to other resource owners.
     100             :  *
     101             :  * MAX_RESOWNER_LOCKS is the size of the per-resource owner cache. It's
     102             :  * chosen based on some testing with pg_dump with a large schema. When the
     103             :  * tests were done (on 9.2), resource owners in a pg_dump run contained up
     104             :  * to 9 locks, regardless of the schema size, except for the top resource
     105             :  * owner which contained much more (overflowing the cache). 15 seems like a
     106             :  * nice round number that's somewhat higher than what pg_dump needs. Note that
     107             :  * making this number larger is not free - the bigger the cache, the slower
     108             :  * it is to release locks (in retail), when a resource owner holds many locks.
     109             :  */
     110             : #define MAX_RESOWNER_LOCKS 15
     111             : 
     112             : /*
     113             :  * ResourceOwner objects look like this
     114             :  */
     115             : typedef struct ResourceOwnerData
     116             : {
     117             :     ResourceOwner parent;       /* NULL if no parent (toplevel owner) */
     118             :     ResourceOwner firstchild;   /* head of linked list of children */
     119             :     ResourceOwner nextchild;    /* next child of same parent */
     120             :     const char *name;           /* name (just for debugging) */
     121             : 
     122             :     /* We have built-in support for remembering: */
     123             :     ResourceArray bufferarr;    /* owned buffers */
     124             :     ResourceArray bufferioarr;  /* in-progress buffer IO */
     125             :     ResourceArray catrefarr;    /* catcache references */
     126             :     ResourceArray catlistrefarr;    /* catcache-list pins */
     127             :     ResourceArray relrefarr;    /* relcache references */
     128             :     ResourceArray planrefarr;   /* plancache references */
     129             :     ResourceArray tupdescarr;   /* tupdesc references */
     130             :     ResourceArray snapshotarr;  /* snapshot references */
     131             :     ResourceArray filearr;      /* open temporary files */
     132             :     ResourceArray dsmarr;       /* dynamic shmem segments */
     133             :     ResourceArray jitarr;       /* JIT contexts */
     134             :     ResourceArray cryptohasharr;    /* cryptohash contexts */
     135             :     ResourceArray hmacarr;      /* HMAC contexts */
     136             : 
     137             :     /* We can remember up to MAX_RESOWNER_LOCKS references to local locks. */
     138             :     int         nlocks;         /* number of owned locks */
     139             :     LOCALLOCK  *locks[MAX_RESOWNER_LOCKS];  /* list of owned locks */
     140             : }           ResourceOwnerData;
     141             : 
     142             : 
     143             : /*****************************************************************************
     144             :  *    GLOBAL MEMORY                                                          *
     145             :  *****************************************************************************/
     146             : 
     147             : ResourceOwner CurrentResourceOwner = NULL;
     148             : ResourceOwner CurTransactionResourceOwner = NULL;
     149             : ResourceOwner TopTransactionResourceOwner = NULL;
     150             : ResourceOwner AuxProcessResourceOwner = NULL;
     151             : 
     152             : /*
     153             :  * List of add-on callbacks for resource releasing
     154             :  */
     155             : typedef struct ResourceReleaseCallbackItem
     156             : {
     157             :     struct ResourceReleaseCallbackItem *next;
     158             :     ResourceReleaseCallback callback;
     159             :     void       *arg;
     160             : } ResourceReleaseCallbackItem;
     161             : 
     162             : static ResourceReleaseCallbackItem *ResourceRelease_callbacks = NULL;
     163             : 
     164             : 
     165             : /* Internal routines */
     166             : static void ResourceArrayInit(ResourceArray *resarr, Datum invalidval);
     167             : static void ResourceArrayEnlarge(ResourceArray *resarr);
     168             : static void ResourceArrayAdd(ResourceArray *resarr, Datum value);
     169             : static bool ResourceArrayRemove(ResourceArray *resarr, Datum value);
     170             : static bool ResourceArrayGetAny(ResourceArray *resarr, Datum *value);
     171             : static void ResourceArrayFree(ResourceArray *resarr);
     172             : static void ResourceOwnerReleaseInternal(ResourceOwner owner,
     173             :                                          ResourceReleasePhase phase,
     174             :                                          bool isCommit,
     175             :                                          bool isTopLevel);
     176             : static void ReleaseAuxProcessResourcesCallback(int code, Datum arg);
     177             : static void PrintRelCacheLeakWarning(Relation rel);
     178             : static void PrintPlanCacheLeakWarning(CachedPlan *plan);
     179             : static void PrintTupleDescLeakWarning(TupleDesc tupdesc);
     180             : static void PrintSnapshotLeakWarning(Snapshot snapshot);
     181             : static void PrintFileLeakWarning(File file);
     182             : static void PrintDSMLeakWarning(dsm_segment *seg);
     183             : static void PrintCryptoHashLeakWarning(Datum handle);
     184             : static void PrintHMACLeakWarning(Datum handle);
     185             : 
     186             : 
     187             : /*****************************************************************************
     188             :  *    INTERNAL ROUTINES                                                      *
     189             :  *****************************************************************************/
     190             : 
     191             : 
     192             : /*
     193             :  * Initialize a ResourceArray
     194             :  */
     195             : static void
     196    14581424 : ResourceArrayInit(ResourceArray *resarr, Datum invalidval)
     197             : {
     198             :     /* Assert it's empty */
     199             :     Assert(resarr->itemsarr == NULL);
     200             :     Assert(resarr->capacity == 0);
     201             :     Assert(resarr->nitems == 0);
     202             :     Assert(resarr->maxitems == 0);
     203             :     /* Remember the appropriate "invalid" value */
     204    14581424 :     resarr->invalidval = invalidval;
     205             :     /* We don't allocate any storage until needed */
     206    14581424 : }
     207             : 
     208             : /*
     209             :  * Make sure there is room for at least one more resource in an array.
     210             :  *
     211             :  * This is separate from actually inserting a resource because if we run out
     212             :  * of memory, it's critical to do so *before* acquiring the resource.
     213             :  */
     214             : static void
     215   255338986 : ResourceArrayEnlarge(ResourceArray *resarr)
     216             : {
     217             :     uint32      i,
     218             :                 oldcap,
     219             :                 newcap;
     220             :     Datum      *olditemsarr;
     221             :     Datum      *newitemsarr;
     222             : 
     223   255338986 :     if (resarr->nitems < resarr->maxitems)
     224   251427116 :         return;                 /* no work needed */
     225             : 
     226     3911870 :     olditemsarr = resarr->itemsarr;
     227     3911870 :     oldcap = resarr->capacity;
     228             : 
     229             :     /* Double the capacity of the array (capacity must stay a power of 2!) */
     230     3911870 :     newcap = (oldcap > 0) ? oldcap * 2 : RESARRAY_INIT_SIZE;
     231     3911870 :     newitemsarr = (Datum *) MemoryContextAlloc(TopMemoryContext,
     232             :                                                newcap * sizeof(Datum));
     233    68453438 :     for (i = 0; i < newcap; i++)
     234    64541568 :         newitemsarr[i] = resarr->invalidval;
     235             : 
     236             :     /* We assume we can't fail below this point, so OK to scribble on resarr */
     237     3911870 :     resarr->itemsarr = newitemsarr;
     238     3911870 :     resarr->capacity = newcap;
     239     3911870 :     resarr->maxitems = RESARRAY_MAX_ITEMS(newcap);
     240     3911870 :     resarr->nitems = 0;
     241             : 
     242     3911870 :     if (olditemsarr != NULL)
     243             :     {
     244             :         /*
     245             :          * Transfer any pre-existing entries into the new array; they don't
     246             :          * necessarily go where they were before, so this simple logic is the
     247             :          * best way.  Note that if we were managing the set as a simple array,
     248             :          * the entries after nitems are garbage, but that shouldn't matter
     249             :          * because we won't get here unless nitems was equal to oldcap.
     250             :          */
     251     1068074 :         for (i = 0; i < oldcap; i++)
     252             :         {
     253     1057824 :             if (olditemsarr[i] != resarr->invalidval)
     254      841568 :                 ResourceArrayAdd(resarr, olditemsarr[i]);
     255             :         }
     256             : 
     257             :         /* And release old array. */
     258       10250 :         pfree(olditemsarr);
     259             :     }
     260             : 
     261             :     Assert(resarr->nitems < resarr->maxitems);
     262             : }
     263             : 
     264             : /*
     265             :  * Add a resource to ResourceArray
     266             :  *
     267             :  * Caller must have previously done ResourceArrayEnlarge()
     268             :  */
     269             : static void
     270   253493770 : ResourceArrayAdd(ResourceArray *resarr, Datum value)
     271             : {
     272             :     uint32      idx;
     273             : 
     274             :     Assert(value != resarr->invalidval);
     275             :     Assert(resarr->nitems < resarr->maxitems);
     276             : 
     277   253493770 :     if (RESARRAY_IS_ARRAY(resarr))
     278             :     {
     279             :         /* Append to linear array. */
     280   251068124 :         idx = resarr->nitems;
     281             :     }
     282             :     else
     283             :     {
     284             :         /* Insert into first free slot at or after hash location. */
     285     2425646 :         uint32      mask = resarr->capacity - 1;
     286             : 
     287     2425646 :         idx = DatumGetUInt32(hash_any((void *) &value, sizeof(value))) & mask;
     288             :         for (;;)
     289             :         {
     290   569323976 :             if (resarr->itemsarr[idx] == resarr->invalidval)
     291     2425646 :                 break;
     292   566898330 :             idx = (idx + 1) & mask;
     293             :         }
     294             :     }
     295   253493770 :     resarr->lastidx = idx;
     296   253493770 :     resarr->itemsarr[idx] = value;
     297   253493770 :     resarr->nitems++;
     298   253493770 : }
     299             : 
     300             : /*
     301             :  * Remove a resource from ResourceArray
     302             :  *
     303             :  * Returns true on success, false if resource was not found.
     304             :  *
     305             :  * Note: if same resource ID appears more than once, one instance is removed.
     306             :  */
     307             : static bool
     308   252652192 : ResourceArrayRemove(ResourceArray *resarr, Datum value)
     309             : {
     310             :     uint32      i,
     311             :                 idx,
     312   252652192 :                 lastidx = resarr->lastidx;
     313             : 
     314             :     Assert(value != resarr->invalidval);
     315             : 
     316             :     /* Search through all items, but try lastidx first. */
     317   252652192 :     if (RESARRAY_IS_ARRAY(resarr))
     318             :     {
     319   250875314 :         if (lastidx < resarr->nitems &&
     320   250875314 :             resarr->itemsarr[lastidx] == value)
     321             :         {
     322   244036548 :             resarr->itemsarr[lastidx] = resarr->itemsarr[resarr->nitems - 1];
     323   244036548 :             resarr->nitems--;
     324             :             /* Update lastidx to make reverse-order removals fast. */
     325   244036548 :             resarr->lastidx = resarr->nitems - 1;
     326   244036548 :             return true;
     327             :         }
     328    14005730 :         for (i = 0; i < resarr->nitems; i++)
     329             :         {
     330    14005730 :             if (resarr->itemsarr[i] == value)
     331             :             {
     332     6838766 :                 resarr->itemsarr[i] = resarr->itemsarr[resarr->nitems - 1];
     333     6838766 :                 resarr->nitems--;
     334             :                 /* Update lastidx to make reverse-order removals fast. */
     335     6838766 :                 resarr->lastidx = resarr->nitems - 1;
     336     6838766 :                 return true;
     337             :             }
     338             :         }
     339             :     }
     340             :     else
     341             :     {
     342     1776878 :         uint32      mask = resarr->capacity - 1;
     343             : 
     344     1776878 :         if (lastidx < resarr->capacity &&
     345     1776878 :             resarr->itemsarr[lastidx] == value)
     346             :         {
     347     1242422 :             resarr->itemsarr[lastidx] = resarr->invalidval;
     348     1242422 :             resarr->nitems--;
     349     1242422 :             return true;
     350             :         }
     351      534456 :         idx = DatumGetUInt32(hash_any((void *) &value, sizeof(value))) & mask;
     352   185268444 :         for (i = 0; i < resarr->capacity; i++)
     353             :         {
     354   185268444 :             if (resarr->itemsarr[idx] == value)
     355             :             {
     356      534456 :                 resarr->itemsarr[idx] = resarr->invalidval;
     357      534456 :                 resarr->nitems--;
     358      534456 :                 return true;
     359             :             }
     360   184733988 :             idx = (idx + 1) & mask;
     361             :         }
     362             :     }
     363             : 
     364           0 :     return false;
     365             : }
     366             : 
     367             : /*
     368             :  * Get any convenient entry in a ResourceArray.
     369             :  *
     370             :  * "Convenient" is defined as "easy for ResourceArrayRemove to remove";
     371             :  * we help that along by setting lastidx to match.  This avoids O(N^2) cost
     372             :  * when removing all ResourceArray items during ResourceOwner destruction.
     373             :  *
     374             :  * Returns true if we found an element, or false if the array is empty.
     375             :  */
     376             : static bool
     377    14771572 : ResourceArrayGetAny(ResourceArray *resarr, Datum *value)
     378             : {
     379    14771572 :     if (resarr->nitems == 0)
     380    14585864 :         return false;
     381             : 
     382      185708 :     if (RESARRAY_IS_ARRAY(resarr))
     383             :     {
     384             :         /* Linear array: just return the first element. */
     385      167742 :         resarr->lastidx = 0;
     386             :     }
     387             :     else
     388             :     {
     389             :         /* Hash: search forward from wherever we were last. */
     390       17966 :         uint32      mask = resarr->capacity - 1;
     391             : 
     392             :         for (;;)
     393             :         {
     394       44294 :             resarr->lastidx &= mask;
     395       44294 :             if (resarr->itemsarr[resarr->lastidx] != resarr->invalidval)
     396       17966 :                 break;
     397       26328 :             resarr->lastidx++;
     398             :         }
     399             :     }
     400             : 
     401      185708 :     *value = resarr->itemsarr[resarr->lastidx];
     402      185708 :     return true;
     403             : }
     404             : 
     405             : /*
     406             :  * Trash a ResourceArray (we don't care about its state after this)
     407             :  */
     408             : static void
     409    14533272 : ResourceArrayFree(ResourceArray *resarr)
     410             : {
     411    14533272 :     if (resarr->itemsarr)
     412     3897174 :         pfree(resarr->itemsarr);
     413    14533272 : }
     414             : 
     415             : 
     416             : /*****************************************************************************
     417             :  *    EXPORTED ROUTINES                                                      *
     418             :  *****************************************************************************/
     419             : 
     420             : 
     421             : /*
     422             :  * ResourceOwnerCreate
     423             :  *      Create an empty ResourceOwner.
     424             :  *
     425             :  * All ResourceOwner objects are kept in TopMemoryContext, since they should
     426             :  * only be freed explicitly.
     427             :  */
     428             : ResourceOwner
     429     1121648 : ResourceOwnerCreate(ResourceOwner parent, const char *name)
     430             : {
     431             :     ResourceOwner owner;
     432             : 
     433     1121648 :     owner = (ResourceOwner) MemoryContextAllocZero(TopMemoryContext,
     434             :                                                    sizeof(ResourceOwnerData));
     435     1121648 :     owner->name = name;
     436             : 
     437     1121648 :     if (parent)
     438             :     {
     439      616820 :         owner->parent = parent;
     440      616820 :         owner->nextchild = parent->firstchild;
     441      616820 :         parent->firstchild = owner;
     442             :     }
     443             : 
     444     1121648 :     ResourceArrayInit(&(owner->bufferarr), BufferGetDatum(InvalidBuffer));
     445     1121648 :     ResourceArrayInit(&(owner->bufferioarr), BufferGetDatum(InvalidBuffer));
     446     1121648 :     ResourceArrayInit(&(owner->catrefarr), PointerGetDatum(NULL));
     447     1121648 :     ResourceArrayInit(&(owner->catlistrefarr), PointerGetDatum(NULL));
     448     1121648 :     ResourceArrayInit(&(owner->relrefarr), PointerGetDatum(NULL));
     449     1121648 :     ResourceArrayInit(&(owner->planrefarr), PointerGetDatum(NULL));
     450     1121648 :     ResourceArrayInit(&(owner->tupdescarr), PointerGetDatum(NULL));
     451     1121648 :     ResourceArrayInit(&(owner->snapshotarr), PointerGetDatum(NULL));
     452     1121648 :     ResourceArrayInit(&(owner->filearr), FileGetDatum(-1));
     453     1121648 :     ResourceArrayInit(&(owner->dsmarr), PointerGetDatum(NULL));
     454     1121648 :     ResourceArrayInit(&(owner->jitarr), PointerGetDatum(NULL));
     455     1121648 :     ResourceArrayInit(&(owner->cryptohasharr), PointerGetDatum(NULL));
     456     1121648 :     ResourceArrayInit(&(owner->hmacarr), PointerGetDatum(NULL));
     457             : 
     458     1121648 :     return owner;
     459             : }
     460             : 
     461             : /*
     462             :  * ResourceOwnerRelease
     463             :  *      Release all resources owned by a ResourceOwner and its descendants,
     464             :  *      but don't delete the owner objects themselves.
     465             :  *
     466             :  * Note that this executes just one phase of release, and so typically
     467             :  * must be called three times.  We do it this way because (a) we want to
     468             :  * do all the recursion separately for each phase, thereby preserving
     469             :  * the needed order of operations; and (b) xact.c may have other operations
     470             :  * to do between the phases.
     471             :  *
     472             :  * phase: release phase to execute
     473             :  * isCommit: true for successful completion of a query or transaction,
     474             :  *          false for unsuccessful
     475             :  * isTopLevel: true if completing a main transaction, else false
     476             :  *
     477             :  * isCommit is passed because some modules may expect that their resources
     478             :  * were all released already if the transaction or portal finished normally.
     479             :  * If so it is reasonable to give a warning (NOT an error) should any
     480             :  * unreleased resources be present.  When isCommit is false, such warnings
     481             :  * are generally inappropriate.
     482             :  *
     483             :  * isTopLevel is passed when we are releasing TopTransactionResourceOwner
     484             :  * at completion of a main transaction.  This generally means that *all*
     485             :  * resources will be released, and so we can optimize things a bit.
     486             :  */
     487             : void
     488     3200412 : ResourceOwnerRelease(ResourceOwner owner,
     489             :                      ResourceReleasePhase phase,
     490             :                      bool isCommit,
     491             :                      bool isTopLevel)
     492             : {
     493             :     /* There's not currently any setup needed before recursing */
     494     3200412 :     ResourceOwnerReleaseInternal(owner, phase, isCommit, isTopLevel);
     495     3200412 : }
     496             : 
     497             : static void
     498     3362604 : ResourceOwnerReleaseInternal(ResourceOwner owner,
     499             :                              ResourceReleasePhase phase,
     500             :                              bool isCommit,
     501             :                              bool isTopLevel)
     502             : {
     503             :     ResourceOwner child;
     504             :     ResourceOwner save;
     505             :     ResourceReleaseCallbackItem *item;
     506             :     ResourceReleaseCallbackItem *next;
     507             :     Datum       foundres;
     508             : 
     509             :     /* Recurse to handle descendants */
     510     3524796 :     for (child = owner->firstchild; child != NULL; child = child->nextchild)
     511      162192 :         ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel);
     512             : 
     513             :     /*
     514             :      * Make CurrentResourceOwner point to me, so that ReleaseBuffer etc don't
     515             :      * get confused.
     516             :      */
     517     3362604 :     save = CurrentResourceOwner;
     518     3362604 :     CurrentResourceOwner = owner;
     519             : 
     520     3362604 :     if (phase == RESOURCE_RELEASE_BEFORE_LOCKS)
     521             :     {
     522             :         /*
     523             :          * Abort failed buffer IO. AbortBufferIO()->TerminateBufferIO() calls
     524             :          * ResourceOwnerForgetBufferIO(), so we just have to iterate till
     525             :          * there are none.
     526             :          *
     527             :          * Needs to be before we release buffer pins.
     528             :          *
     529             :          * During a commit, there shouldn't be any in-progress IO.
     530             :          */
     531     1120894 :         while (ResourceArrayGetAny(&(owner->bufferioarr), &foundres))
     532             :         {
     533          26 :             Buffer      res = DatumGetBuffer(foundres);
     534             : 
     535          26 :             if (isCommit)
     536           0 :                 elog(PANIC, "lost track of buffer IO on buffer %d", res);
     537          26 :             AbortBufferIO(res);
     538             :         }
     539             : 
     540             :         /*
     541             :          * Release buffer pins.  Note that ReleaseBuffer will remove the
     542             :          * buffer entry from our array, so we just have to iterate till there
     543             :          * are none.
     544             :          *
     545             :          * During a commit, there shouldn't be any remaining pins --- that
     546             :          * would indicate failure to clean up the executor correctly --- so
     547             :          * issue warnings.  In the abort case, just clean up quietly.
     548             :          */
     549     1128202 :         while (ResourceArrayGetAny(&(owner->bufferarr), &foundres))
     550             :         {
     551        7334 :             Buffer      res = DatumGetBuffer(foundres);
     552             : 
     553        7334 :             if (isCommit)
     554           0 :                 PrintBufferLeakWarning(res);
     555        7334 :             ReleaseBuffer(res);
     556             :         }
     557             : 
     558             :         /* Ditto for relcache references */
     559     1152782 :         while (ResourceArrayGetAny(&(owner->relrefarr), &foundres))
     560             :         {
     561       31914 :             Relation    res = (Relation) DatumGetPointer(foundres);
     562             : 
     563       31914 :             if (isCommit)
     564           0 :                 PrintRelCacheLeakWarning(res);
     565       31914 :             RelationClose(res);
     566             :         }
     567             : 
     568             :         /* Ditto for dynamic shared memory segments */
     569     1120868 :         while (ResourceArrayGetAny(&(owner->dsmarr), &foundres))
     570             :         {
     571           0 :             dsm_segment *res = (dsm_segment *) DatumGetPointer(foundres);
     572             : 
     573           0 :             if (isCommit)
     574           0 :                 PrintDSMLeakWarning(res);
     575           0 :             dsm_detach(res);
     576             :         }
     577             : 
     578             :         /* Ditto for JIT contexts */
     579     1120884 :         while (ResourceArrayGetAny(&(owner->jitarr), &foundres))
     580             :         {
     581          16 :             JitContext *context = (JitContext *) DatumGetPointer(foundres);
     582             : 
     583          16 :             jit_release_context(context);
     584             :         }
     585             : 
     586             :         /* Ditto for cryptohash contexts */
     587     1120876 :         while (ResourceArrayGetAny(&(owner->cryptohasharr), &foundres))
     588             :         {
     589             :             pg_cryptohash_ctx *context =
     590           8 :                 (pg_cryptohash_ctx *) DatumGetPointer(foundres);
     591             : 
     592           8 :             if (isCommit)
     593           0 :                 PrintCryptoHashLeakWarning(foundres);
     594           8 :             pg_cryptohash_free(context);
     595             :         }
     596             : 
     597             :         /* Ditto for HMAC contexts */
     598     1120868 :         while (ResourceArrayGetAny(&(owner->hmacarr), &foundres))
     599             :         {
     600           0 :             pg_hmac_ctx *context = (pg_hmac_ctx *) DatumGetPointer(foundres);
     601             : 
     602           0 :             if (isCommit)
     603           0 :                 PrintHMACLeakWarning(foundres);
     604           0 :             pg_hmac_free(context);
     605             :         }
     606             :     }
     607     2241736 :     else if (phase == RESOURCE_RELEASE_LOCKS)
     608             :     {
     609     1120868 :         if (isTopLevel)
     610             :         {
     611             :             /*
     612             :              * For a top-level xact we are going to release all locks (or at
     613             :              * least all non-session locks), so just do a single lmgr call at
     614             :              * the top of the recursion.
     615             :              */
     616      557864 :             if (owner == TopTransactionResourceOwner)
     617             :             {
     618      499990 :                 ProcReleaseLocks(isCommit);
     619      499990 :                 ReleasePredicateLocks(isCommit, false);
     620             :             }
     621             :         }
     622             :         else
     623             :         {
     624             :             /*
     625             :              * Release locks retail.  Note that if we are committing a
     626             :              * subtransaction, we do NOT release its locks yet, but transfer
     627             :              * them to the parent.
     628             :              */
     629             :             LOCALLOCK **locks;
     630             :             int         nlocks;
     631             : 
     632             :             Assert(owner->parent != NULL);
     633             : 
     634             :             /*
     635             :              * Pass the list of locks owned by this resource owner to the lock
     636             :              * manager, unless it has overflowed.
     637             :              */
     638      563004 :             if (owner->nlocks > MAX_RESOWNER_LOCKS)
     639             :             {
     640        5436 :                 locks = NULL;
     641        5436 :                 nlocks = 0;
     642             :             }
     643             :             else
     644             :             {
     645      557568 :                 locks = owner->locks;
     646      557568 :                 nlocks = owner->nlocks;
     647             :             }
     648             : 
     649      563004 :             if (isCommit)
     650      553754 :                 LockReassignCurrentOwner(locks, nlocks);
     651             :             else
     652        9250 :                 LockReleaseCurrentOwner(locks, nlocks);
     653             :         }
     654             :     }
     655     1120868 :     else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
     656             :     {
     657             :         /*
     658             :          * Release catcache references.  Note that ReleaseCatCache will remove
     659             :          * the catref entry from our array, so we just have to iterate till
     660             :          * there are none.
     661             :          *
     662             :          * As with buffer pins, warn if any are left at commit time.
     663             :          */
     664     1130116 :         while (ResourceArrayGetAny(&(owner->catrefarr), &foundres))
     665             :         {
     666        9248 :             HeapTuple   res = (HeapTuple) DatumGetPointer(foundres);
     667             : 
     668        9248 :             if (isCommit)
     669           0 :                 PrintCatCacheLeakWarning(res);
     670        9248 :             ReleaseCatCache(res);
     671             :         }
     672             : 
     673             :         /* Ditto for catcache lists */
     674     1120904 :         while (ResourceArrayGetAny(&(owner->catlistrefarr), &foundres))
     675             :         {
     676          36 :             CatCList   *res = (CatCList *) DatumGetPointer(foundres);
     677             : 
     678          36 :             if (isCommit)
     679           0 :                 PrintCatCacheListLeakWarning(res);
     680          36 :             ReleaseCatCacheList(res);
     681             :         }
     682             : 
     683             :         /* Ditto for plancache references */
     684     1130988 :         while (ResourceArrayGetAny(&(owner->planrefarr), &foundres))
     685             :         {
     686       10120 :             CachedPlan *res = (CachedPlan *) DatumGetPointer(foundres);
     687             : 
     688       10120 :             if (isCommit)
     689           0 :                 PrintPlanCacheLeakWarning(res);
     690       10120 :             ReleaseCachedPlan(res, owner);
     691             :         }
     692             : 
     693             :         /* Ditto for tupdesc references */
     694     1131936 :         while (ResourceArrayGetAny(&(owner->tupdescarr), &foundres))
     695             :         {
     696       11068 :             TupleDesc   res = (TupleDesc) DatumGetPointer(foundres);
     697             : 
     698       11068 :             if (isCommit)
     699           0 :                 PrintTupleDescLeakWarning(res);
     700       11068 :             DecrTupleDescRefCount(res);
     701             :         }
     702             : 
     703             :         /* Ditto for snapshot references */
     704     1171176 :         while (ResourceArrayGetAny(&(owner->snapshotarr), &foundres))
     705             :         {
     706       50308 :             Snapshot    res = (Snapshot) DatumGetPointer(foundres);
     707             : 
     708       50308 :             if (isCommit)
     709           0 :                 PrintSnapshotLeakWarning(res);
     710       50308 :             UnregisterSnapshot(res);
     711             :         }
     712             : 
     713             :         /* Ditto for temporary files */
     714     1120876 :         while (ResourceArrayGetAny(&(owner->filearr), &foundres))
     715             :         {
     716           8 :             File        res = DatumGetFile(foundres);
     717             : 
     718           8 :             if (isCommit)
     719           0 :                 PrintFileLeakWarning(res);
     720           8 :             FileClose(res);
     721             :         }
     722             :     }
     723             : 
     724             :     /* Let add-on modules get a chance too */
     725     3366120 :     for (item = ResourceRelease_callbacks; item; item = next)
     726             :     {
     727             :         /* allow callbacks to unregister themselves when called */
     728        3516 :         next = item->next;
     729        3516 :         item->callback(phase, isCommit, isTopLevel, item->arg);
     730             :     }
     731             : 
     732     3362604 :     CurrentResourceOwner = save;
     733     3362604 : }
     734             : 
     735             : /*
     736             :  * ResourceOwnerReleaseAllPlanCacheRefs
     737             :  *      Release the plancache references (only) held by this owner.
     738             :  *
     739             :  * We might eventually add similar functions for other resource types,
     740             :  * but for now, only this is needed.
     741             :  */
     742             : void
     743       14580 : ResourceOwnerReleaseAllPlanCacheRefs(ResourceOwner owner)
     744             : {
     745             :     Datum       foundres;
     746             : 
     747       80202 :     while (ResourceArrayGetAny(&(owner->planrefarr), &foundres))
     748             :     {
     749       65622 :         CachedPlan *res = (CachedPlan *) DatumGetPointer(foundres);
     750             : 
     751       65622 :         ReleaseCachedPlan(res, owner);
     752             :     }
     753       14580 : }
     754             : 
     755             : /*
     756             :  * ResourceOwnerDelete
     757             :  *      Delete an owner object and its descendants.
     758             :  *
     759             :  * The caller must have already released all resources in the object tree.
     760             :  */
     761             : void
     762     1117944 : ResourceOwnerDelete(ResourceOwner owner)
     763             : {
     764             :     /* We had better not be deleting CurrentResourceOwner ... */
     765             :     Assert(owner != CurrentResourceOwner);
     766             : 
     767             :     /* And it better not own any resources, either */
     768             :     Assert(owner->bufferarr.nitems == 0);
     769             :     Assert(owner->bufferioarr.nitems == 0);
     770             :     Assert(owner->catrefarr.nitems == 0);
     771             :     Assert(owner->catlistrefarr.nitems == 0);
     772             :     Assert(owner->relrefarr.nitems == 0);
     773             :     Assert(owner->planrefarr.nitems == 0);
     774             :     Assert(owner->tupdescarr.nitems == 0);
     775             :     Assert(owner->snapshotarr.nitems == 0);
     776             :     Assert(owner->filearr.nitems == 0);
     777             :     Assert(owner->dsmarr.nitems == 0);
     778             :     Assert(owner->jitarr.nitems == 0);
     779             :     Assert(owner->cryptohasharr.nitems == 0);
     780             :     Assert(owner->hmacarr.nitems == 0);
     781             :     Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1);
     782             : 
     783             :     /*
     784             :      * Delete children.  The recursive call will delink the child from me, so
     785             :      * just iterate as long as there is a child.
     786             :      */
     787     1172014 :     while (owner->firstchild != NULL)
     788       54070 :         ResourceOwnerDelete(owner->firstchild);
     789             : 
     790             :     /*
     791             :      * We delink the owner from its parent before deleting it, so that if
     792             :      * there's an error we won't have deleted/busted owners still attached to
     793             :      * the owner tree.  Better a leak than a crash.
     794             :      */
     795     1117944 :     ResourceOwnerNewParent(owner, NULL);
     796             : 
     797             :     /* And free the object. */
     798     1117944 :     ResourceArrayFree(&(owner->bufferarr));
     799     1117944 :     ResourceArrayFree(&(owner->bufferioarr));
     800     1117944 :     ResourceArrayFree(&(owner->catrefarr));
     801     1117944 :     ResourceArrayFree(&(owner->catlistrefarr));
     802     1117944 :     ResourceArrayFree(&(owner->relrefarr));
     803     1117944 :     ResourceArrayFree(&(owner->planrefarr));
     804     1117944 :     ResourceArrayFree(&(owner->tupdescarr));
     805     1117944 :     ResourceArrayFree(&(owner->snapshotarr));
     806     1117944 :     ResourceArrayFree(&(owner->filearr));
     807     1117944 :     ResourceArrayFree(&(owner->dsmarr));
     808     1117944 :     ResourceArrayFree(&(owner->jitarr));
     809     1117944 :     ResourceArrayFree(&(owner->cryptohasharr));
     810     1117944 :     ResourceArrayFree(&(owner->hmacarr));
     811             : 
     812     1117944 :     pfree(owner);
     813     1117944 : }
     814             : 
     815             : /*
     816             :  * Fetch parent of a ResourceOwner (returns NULL if top-level owner)
     817             :  */
     818             : ResourceOwner
     819      553754 : ResourceOwnerGetParent(ResourceOwner owner)
     820             : {
     821      553754 :     return owner->parent;
     822             : }
     823             : 
     824             : /*
     825             :  * Reassign a ResourceOwner to have a new parent
     826             :  */
     827             : void
     828     1118018 : ResourceOwnerNewParent(ResourceOwner owner,
     829             :                        ResourceOwner newparent)
     830             : {
     831     1118018 :     ResourceOwner oldparent = owner->parent;
     832             : 
     833     1118018 :     if (oldparent)
     834             :     {
     835      616894 :         if (owner == oldparent->firstchild)
     836      602272 :             oldparent->firstchild = owner->nextchild;
     837             :         else
     838             :         {
     839             :             ResourceOwner child;
     840             : 
     841       16460 :             for (child = oldparent->firstchild; child; child = child->nextchild)
     842             :             {
     843       16460 :                 if (owner == child->nextchild)
     844             :                 {
     845       14622 :                     child->nextchild = owner->nextchild;
     846       14622 :                     break;
     847             :                 }
     848             :             }
     849             :         }
     850             :     }
     851             : 
     852     1118018 :     if (newparent)
     853             :     {
     854             :         Assert(owner != newparent);
     855          74 :         owner->parent = newparent;
     856          74 :         owner->nextchild = newparent->firstchild;
     857          74 :         newparent->firstchild = owner;
     858             :     }
     859             :     else
     860             :     {
     861     1117944 :         owner->parent = NULL;
     862     1117944 :         owner->nextchild = NULL;
     863             :     }
     864     1118018 : }
     865             : 
     866             : /*
     867             :  * Register or deregister callback functions for resource cleanup
     868             :  *
     869             :  * These functions are intended for use by dynamically loaded modules.
     870             :  * For built-in modules we generally just hardwire the appropriate calls.
     871             :  *
     872             :  * Note that the callback occurs post-commit or post-abort, so the callback
     873             :  * functions can only do noncritical cleanup.
     874             :  */
     875             : void
     876          46 : RegisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
     877             : {
     878             :     ResourceReleaseCallbackItem *item;
     879             : 
     880             :     item = (ResourceReleaseCallbackItem *)
     881          46 :         MemoryContextAlloc(TopMemoryContext,
     882             :                            sizeof(ResourceReleaseCallbackItem));
     883          46 :     item->callback = callback;
     884          46 :     item->arg = arg;
     885          46 :     item->next = ResourceRelease_callbacks;
     886          46 :     ResourceRelease_callbacks = item;
     887          46 : }
     888             : 
     889             : void
     890           0 : UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
     891             : {
     892             :     ResourceReleaseCallbackItem *item;
     893             :     ResourceReleaseCallbackItem *prev;
     894             : 
     895           0 :     prev = NULL;
     896           0 :     for (item = ResourceRelease_callbacks; item; prev = item, item = item->next)
     897             :     {
     898           0 :         if (item->callback == callback && item->arg == arg)
     899             :         {
     900           0 :             if (prev)
     901           0 :                 prev->next = item->next;
     902             :             else
     903           0 :                 ResourceRelease_callbacks = item->next;
     904           0 :             pfree(item);
     905           0 :             break;
     906             :         }
     907             :     }
     908           0 : }
     909             : 
     910             : /*
     911             :  * Establish an AuxProcessResourceOwner for the current process.
     912             :  */
     913             : void
     914        3694 : CreateAuxProcessResourceOwner(void)
     915             : {
     916             :     Assert(AuxProcessResourceOwner == NULL);
     917             :     Assert(CurrentResourceOwner == NULL);
     918        3694 :     AuxProcessResourceOwner = ResourceOwnerCreate(NULL, "AuxiliaryProcess");
     919        3694 :     CurrentResourceOwner = AuxProcessResourceOwner;
     920             : 
     921             :     /*
     922             :      * Register a shmem-exit callback for cleanup of aux-process resource
     923             :      * owner.  (This needs to run after, e.g., ShutdownXLOG.)
     924             :      */
     925        3694 :     on_shmem_exit(ReleaseAuxProcessResourcesCallback, 0);
     926        3694 : }
     927             : 
     928             : /*
     929             :  * Convenience routine to release all resources tracked in
     930             :  * AuxProcessResourceOwner (but that resowner is not destroyed here).
     931             :  * Warn about leaked resources if isCommit is true.
     932             :  */
     933             : void
     934        3836 : ReleaseAuxProcessResources(bool isCommit)
     935             : {
     936             :     /*
     937             :      * At this writing, the only thing that could actually get released is
     938             :      * buffer pins; but we may as well do the full release protocol.
     939             :      */
     940        3836 :     ResourceOwnerRelease(AuxProcessResourceOwner,
     941             :                          RESOURCE_RELEASE_BEFORE_LOCKS,
     942             :                          isCommit, true);
     943        3836 :     ResourceOwnerRelease(AuxProcessResourceOwner,
     944             :                          RESOURCE_RELEASE_LOCKS,
     945             :                          isCommit, true);
     946        3836 :     ResourceOwnerRelease(AuxProcessResourceOwner,
     947             :                          RESOURCE_RELEASE_AFTER_LOCKS,
     948             :                          isCommit, true);
     949        3836 : }
     950             : 
     951             : /*
     952             :  * Shmem-exit callback for the same.
     953             :  * Warn about leaked resources if process exit code is zero (ie normal).
     954             :  */
     955             : static void
     956        3694 : ReleaseAuxProcessResourcesCallback(int code, Datum arg)
     957             : {
     958        3694 :     bool        isCommit = (code == 0);
     959             : 
     960        3694 :     ReleaseAuxProcessResources(isCommit);
     961        3694 : }
     962             : 
     963             : 
     964             : /*
     965             :  * Make sure there is room for at least one more entry in a ResourceOwner's
     966             :  * buffer array.
     967             :  *
     968             :  * This is separate from actually inserting an entry because if we run out
     969             :  * of memory, it's critical to do so *before* acquiring the resource.
     970             :  */
     971             : void
     972   110079532 : ResourceOwnerEnlargeBuffers(ResourceOwner owner)
     973             : {
     974             :     /* We used to allow pinning buffers without a resowner, but no more */
     975             :     Assert(owner != NULL);
     976   110079532 :     ResourceArrayEnlarge(&(owner->bufferarr));
     977   110079532 : }
     978             : 
     979             : /*
     980             :  * Remember that a buffer pin is owned by a ResourceOwner
     981             :  *
     982             :  * Caller must have previously done ResourceOwnerEnlargeBuffers()
     983             :  */
     984             : void
     985   107750450 : ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
     986             : {
     987   107750450 :     ResourceArrayAdd(&(owner->bufferarr), BufferGetDatum(buffer));
     988   107750450 : }
     989             : 
     990             : /*
     991             :  * Forget that a buffer pin is owned by a ResourceOwner
     992             :  */
     993             : void
     994   107750450 : ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
     995             : {
     996   107750450 :     if (!ResourceArrayRemove(&(owner->bufferarr), BufferGetDatum(buffer)))
     997           0 :         elog(ERROR, "buffer %d is not owned by resource owner %s",
     998             :              buffer, owner->name);
     999   107750450 : }
    1000             : 
    1001             : 
    1002             : /*
    1003             :  * Make sure there is room for at least one more entry in a ResourceOwner's
    1004             :  * buffer array.
    1005             :  *
    1006             :  * This is separate from actually inserting an entry because if we run out
    1007             :  * of memory, it's critical to do so *before* acquiring the resource.
    1008             :  */
    1009             : void
    1010     3590748 : ResourceOwnerEnlargeBufferIOs(ResourceOwner owner)
    1011             : {
    1012             :     /* We used to allow pinning buffers without a resowner, but no more */
    1013             :     Assert(owner != NULL);
    1014     3590748 :     ResourceArrayEnlarge(&(owner->bufferioarr));
    1015     3590748 : }
    1016             : 
    1017             : /*
    1018             :  * Remember that a buffer IO is owned by a ResourceOwner
    1019             :  *
    1020             :  * Caller must have previously done ResourceOwnerEnlargeBufferIOs()
    1021             :  */
    1022             : void
    1023     3590546 : ResourceOwnerRememberBufferIO(ResourceOwner owner, Buffer buffer)
    1024             : {
    1025     3590546 :     ResourceArrayAdd(&(owner->bufferioarr), BufferGetDatum(buffer));
    1026     3590546 : }
    1027             : 
    1028             : /*
    1029             :  * Forget that a buffer IO is owned by a ResourceOwner
    1030             :  */
    1031             : void
    1032     3590546 : ResourceOwnerForgetBufferIO(ResourceOwner owner, Buffer buffer)
    1033             : {
    1034     3590546 :     if (!ResourceArrayRemove(&(owner->bufferioarr), BufferGetDatum(buffer)))
    1035           0 :         elog(PANIC, "buffer IO %d is not owned by resource owner %s",
    1036             :              buffer, owner->name);
    1037     3590546 : }
    1038             : 
    1039             : /*
    1040             :  * Remember that a Local Lock is owned by a ResourceOwner
    1041             :  *
    1042             :  * This is different from the other Remember functions in that the list of
    1043             :  * locks is only a lossy cache. It can hold up to MAX_RESOWNER_LOCKS entries,
    1044             :  * and when it overflows, we stop tracking locks. The point of only remembering
    1045             :  * only up to MAX_RESOWNER_LOCKS entries is that if a lot of locks are held,
    1046             :  * ResourceOwnerForgetLock doesn't need to scan through a large array to find
    1047             :  * the entry.
    1048             :  */
    1049             : void
    1050    24853030 : ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock)
    1051             : {
    1052             :     Assert(locallock != NULL);
    1053             : 
    1054    24853030 :     if (owner->nlocks > MAX_RESOWNER_LOCKS)
    1055     2655870 :         return;                 /* we have already overflowed */
    1056             : 
    1057    22197160 :     if (owner->nlocks < MAX_RESOWNER_LOCKS)
    1058    22181798 :         owner->locks[owner->nlocks] = locallock;
    1059             :     else
    1060             :     {
    1061             :         /* overflowed */
    1062             :     }
    1063    22197160 :     owner->nlocks++;
    1064             : }
    1065             : 
    1066             : /*
    1067             :  * Forget that a Local Lock is owned by a ResourceOwner
    1068             :  */
    1069             : void
    1070    24853030 : ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock)
    1071             : {
    1072             :     int         i;
    1073             : 
    1074    24853030 :     if (owner->nlocks > MAX_RESOWNER_LOCKS)
    1075     2901662 :         return;                 /* we have overflowed */
    1076             : 
    1077             :     Assert(owner->nlocks > 0);
    1078    24957340 :     for (i = owner->nlocks - 1; i >= 0; i--)
    1079             :     {
    1080    24957340 :         if (locallock == owner->locks[i])
    1081             :         {
    1082    21951368 :             owner->locks[i] = owner->locks[owner->nlocks - 1];
    1083    21951368 :             owner->nlocks--;
    1084    21951368 :             return;
    1085             :         }
    1086             :     }
    1087           0 :     elog(ERROR, "lock reference %p is not owned by resource owner %s",
    1088             :          locallock, owner->name);
    1089             : }
    1090             : 
    1091             : /*
    1092             :  * Make sure there is room for at least one more entry in a ResourceOwner's
    1093             :  * catcache reference array.
    1094             :  *
    1095             :  * This is separate from actually inserting an entry because if we run out
    1096             :  * of memory, it's critical to do so *before* acquiring the resource.
    1097             :  */
    1098             : void
    1099    61066002 : ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner)
    1100             : {
    1101    61066002 :     ResourceArrayEnlarge(&(owner->catrefarr));
    1102    61066002 : }
    1103             : 
    1104             : /*
    1105             :  * Remember that a catcache reference is owned by a ResourceOwner
    1106             :  *
    1107             :  * Caller must have previously done ResourceOwnerEnlargeCatCacheRefs()
    1108             :  */
    1109             : void
    1110    61066002 : ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple)
    1111             : {
    1112    61066002 :     ResourceArrayAdd(&(owner->catrefarr), PointerGetDatum(tuple));
    1113    61066002 : }
    1114             : 
    1115             : /*
    1116             :  * Forget that a catcache reference is owned by a ResourceOwner
    1117             :  */
    1118             : void
    1119    61066002 : ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple)
    1120             : {
    1121    61066002 :     if (!ResourceArrayRemove(&(owner->catrefarr), PointerGetDatum(tuple)))
    1122           0 :         elog(ERROR, "catcache reference %p is not owned by resource owner %s",
    1123             :              tuple, owner->name);
    1124    61066002 : }
    1125             : 
    1126             : /*
    1127             :  * Make sure there is room for at least one more entry in a ResourceOwner's
    1128             :  * catcache-list reference array.
    1129             :  *
    1130             :  * This is separate from actually inserting an entry because if we run out
    1131             :  * of memory, it's critical to do so *before* acquiring the resource.
    1132             :  */
    1133             : void
    1134     2618836 : ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner)
    1135             : {
    1136     2618836 :     ResourceArrayEnlarge(&(owner->catlistrefarr));
    1137     2618836 : }
    1138             : 
    1139             : /*
    1140             :  * Remember that a catcache-list reference is owned by a ResourceOwner
    1141             :  *
    1142             :  * Caller must have previously done ResourceOwnerEnlargeCatCacheListRefs()
    1143             :  */
    1144             : void
    1145     2618836 : ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
    1146             : {
    1147     2618836 :     ResourceArrayAdd(&(owner->catlistrefarr), PointerGetDatum(list));
    1148     2618836 : }
    1149             : 
    1150             : /*
    1151             :  * Forget that a catcache-list reference is owned by a ResourceOwner
    1152             :  */
    1153             : void
    1154     2618836 : ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list)
    1155             : {
    1156     2618836 :     if (!ResourceArrayRemove(&(owner->catlistrefarr), PointerGetDatum(list)))
    1157           0 :         elog(ERROR, "catcache list reference %p is not owned by resource owner %s",
    1158             :              list, owner->name);
    1159     2618836 : }
    1160             : 
    1161             : /*
    1162             :  * Make sure there is room for at least one more entry in a ResourceOwner's
    1163             :  * relcache reference array.
    1164             :  *
    1165             :  * This is separate from actually inserting an entry because if we run out
    1166             :  * of memory, it's critical to do so *before* acquiring the resource.
    1167             :  */
    1168             : void
    1169    41730240 : ResourceOwnerEnlargeRelationRefs(ResourceOwner owner)
    1170             : {
    1171    41730240 :     ResourceArrayEnlarge(&(owner->relrefarr));
    1172    41730240 : }
    1173             : 
    1174             : /*
    1175             :  * Remember that a relcache reference is owned by a ResourceOwner
    1176             :  *
    1177             :  * Caller must have previously done ResourceOwnerEnlargeRelationRefs()
    1178             :  */
    1179             : void
    1180    41376902 : ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel)
    1181             : {
    1182    41376902 :     ResourceArrayAdd(&(owner->relrefarr), PointerGetDatum(rel));
    1183    41376902 : }
    1184             : 
    1185             : /*
    1186             :  * Forget that a relcache reference is owned by a ResourceOwner
    1187             :  */
    1188             : void
    1189    41376902 : ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
    1190             : {
    1191    41376902 :     if (!ResourceArrayRemove(&(owner->relrefarr), PointerGetDatum(rel)))
    1192           0 :         elog(ERROR, "relcache reference %s is not owned by resource owner %s",
    1193             :              RelationGetRelationName(rel), owner->name);
    1194    41376902 : }
    1195             : 
    1196             : /*
    1197             :  * Debugging subroutine
    1198             :  */
    1199             : static void
    1200           0 : PrintRelCacheLeakWarning(Relation rel)
    1201             : {
    1202           0 :     elog(WARNING, "relcache reference leak: relation \"%s\" not closed",
    1203             :          RelationGetRelationName(rel));
    1204           0 : }
    1205             : 
    1206             : /*
    1207             :  * Make sure there is room for at least one more entry in a ResourceOwner's
    1208             :  * plancache reference array.
    1209             :  *
    1210             :  * This is separate from actually inserting an entry because if we run out
    1211             :  * of memory, it's critical to do so *before* acquiring the resource.
    1212             :  */
    1213             : void
    1214      172462 : ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
    1215             : {
    1216      172462 :     ResourceArrayEnlarge(&(owner->planrefarr));
    1217      172462 : }
    1218             : 
    1219             : /*
    1220             :  * Remember that a plancache reference is owned by a ResourceOwner
    1221             :  *
    1222             :  * Caller must have previously done ResourceOwnerEnlargePlanCacheRefs()
    1223             :  */
    1224             : void
    1225      172462 : ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
    1226             : {
    1227      172462 :     ResourceArrayAdd(&(owner->planrefarr), PointerGetDatum(plan));
    1228      172462 : }
    1229             : 
    1230             : /*
    1231             :  * Forget that a plancache reference is owned by a ResourceOwner
    1232             :  */
    1233             : void
    1234      172462 : ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
    1235             : {
    1236      172462 :     if (!ResourceArrayRemove(&(owner->planrefarr), PointerGetDatum(plan)))
    1237           0 :         elog(ERROR, "plancache reference %p is not owned by resource owner %s",
    1238             :              plan, owner->name);
    1239      172462 : }
    1240             : 
    1241             : /*
    1242             :  * Debugging subroutine
    1243             :  */
    1244             : static void
    1245           0 : PrintPlanCacheLeakWarning(CachedPlan *plan)
    1246             : {
    1247           0 :     elog(WARNING, "plancache reference leak: plan %p not closed", plan);
    1248           0 : }
    1249             : 
    1250             : /*
    1251             :  * Make sure there is room for at least one more entry in a ResourceOwner's
    1252             :  * tupdesc reference array.
    1253             :  *
    1254             :  * This is separate from actually inserting an entry because if we run out
    1255             :  * of memory, it's critical to do so *before* acquiring the resource.
    1256             :  */
    1257             : void
    1258    25453662 : ResourceOwnerEnlargeTupleDescs(ResourceOwner owner)
    1259             : {
    1260    25453662 :     ResourceArrayEnlarge(&(owner->tupdescarr));
    1261    25453662 : }
    1262             : 
    1263             : /*
    1264             :  * Remember that a tupdesc reference is owned by a ResourceOwner
    1265             :  *
    1266             :  * Caller must have previously done ResourceOwnerEnlargeTupleDescs()
    1267             :  */
    1268             : void
    1269    25453662 : ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
    1270             : {
    1271    25453662 :     ResourceArrayAdd(&(owner->tupdescarr), PointerGetDatum(tupdesc));
    1272    25453662 : }
    1273             : 
    1274             : /*
    1275             :  * Forget that a tupdesc reference is owned by a ResourceOwner
    1276             :  */
    1277             : void
    1278    25453662 : ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
    1279             : {
    1280    25453662 :     if (!ResourceArrayRemove(&(owner->tupdescarr), PointerGetDatum(tupdesc)))
    1281           0 :         elog(ERROR, "tupdesc reference %p is not owned by resource owner %s",
    1282             :              tupdesc, owner->name);
    1283    25453662 : }
    1284             : 
    1285             : /*
    1286             :  * Debugging subroutine
    1287             :  */
    1288             : static void
    1289           0 : PrintTupleDescLeakWarning(TupleDesc tupdesc)
    1290             : {
    1291           0 :     elog(WARNING,
    1292             :          "TupleDesc reference leak: TupleDesc %p (%u,%d) still referenced",
    1293             :          tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
    1294           0 : }
    1295             : 
    1296             : /*
    1297             :  * Make sure there is room for at least one more entry in a ResourceOwner's
    1298             :  * snapshot reference array.
    1299             :  *
    1300             :  * This is separate from actually inserting an entry because if we run out
    1301             :  * of memory, it's critical to do so *before* acquiring the resource.
    1302             :  */
    1303             : void
    1304     9730576 : ResourceOwnerEnlargeSnapshots(ResourceOwner owner)
    1305             : {
    1306     9730576 :     ResourceArrayEnlarge(&(owner->snapshotarr));
    1307     9730576 : }
    1308             : 
    1309             : /*
    1310             :  * Remember that a snapshot reference is owned by a ResourceOwner
    1311             :  *
    1312             :  * Caller must have previously done ResourceOwnerEnlargeSnapshots()
    1313             :  */
    1314             : void
    1315     9730576 : ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot)
    1316             : {
    1317     9730576 :     ResourceArrayAdd(&(owner->snapshotarr), PointerGetDatum(snapshot));
    1318     9730576 : }
    1319             : 
    1320             : /*
    1321             :  * Forget that a snapshot reference is owned by a ResourceOwner
    1322             :  */
    1323             : void
    1324     9730576 : ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot)
    1325             : {
    1326     9730576 :     if (!ResourceArrayRemove(&(owner->snapshotarr), PointerGetDatum(snapshot)))
    1327           0 :         elog(ERROR, "snapshot reference %p is not owned by resource owner %s",
    1328             :              snapshot, owner->name);
    1329     9730576 : }
    1330             : 
    1331             : /*
    1332             :  * Debugging subroutine
    1333             :  */
    1334             : static void
    1335           0 : PrintSnapshotLeakWarning(Snapshot snapshot)
    1336             : {
    1337           0 :     elog(WARNING, "Snapshot reference leak: Snapshot %p still referenced",
    1338             :          snapshot);
    1339           0 : }
    1340             : 
    1341             : 
    1342             : /*
    1343             :  * Make sure there is room for at least one more entry in a ResourceOwner's
    1344             :  * files reference array.
    1345             :  *
    1346             :  * This is separate from actually inserting an entry because if we run out
    1347             :  * of memory, it's critical to do so *before* acquiring the resource.
    1348             :  */
    1349             : void
    1350       12816 : ResourceOwnerEnlargeFiles(ResourceOwner owner)
    1351             : {
    1352       12816 :     ResourceArrayEnlarge(&(owner->filearr));
    1353       12816 : }
    1354             : 
    1355             : /*
    1356             :  * Remember that a temporary file is owned by a ResourceOwner
    1357             :  *
    1358             :  * Caller must have previously done ResourceOwnerEnlargeFiles()
    1359             :  */
    1360             : void
    1361        8654 : ResourceOwnerRememberFile(ResourceOwner owner, File file)
    1362             : {
    1363        8654 :     ResourceArrayAdd(&(owner->filearr), FileGetDatum(file));
    1364        8654 : }
    1365             : 
    1366             : /*
    1367             :  * Forget that a temporary file is owned by a ResourceOwner
    1368             :  */
    1369             : void
    1370        8654 : ResourceOwnerForgetFile(ResourceOwner owner, File file)
    1371             : {
    1372        8654 :     if (!ResourceArrayRemove(&(owner->filearr), FileGetDatum(file)))
    1373           0 :         elog(ERROR, "temporary file %d is not owned by resource owner %s",
    1374             :              file, owner->name);
    1375        8654 : }
    1376             : 
    1377             : /*
    1378             :  * Debugging subroutine
    1379             :  */
    1380             : static void
    1381           0 : PrintFileLeakWarning(File file)
    1382             : {
    1383           0 :     elog(WARNING, "temporary file leak: File %d still referenced",
    1384             :          file);
    1385           0 : }
    1386             : 
    1387             : /*
    1388             :  * Make sure there is room for at least one more entry in a ResourceOwner's
    1389             :  * dynamic shmem segment reference array.
    1390             :  *
    1391             :  * This is separate from actually inserting an entry because if we run out
    1392             :  * of memory, it's critical to do so *before* acquiring the resource.
    1393             :  */
    1394             : void
    1395       29584 : ResourceOwnerEnlargeDSMs(ResourceOwner owner)
    1396             : {
    1397       29584 :     ResourceArrayEnlarge(&(owner->dsmarr));
    1398       29584 : }
    1399             : 
    1400             : /*
    1401             :  * Remember that a dynamic shmem segment is owned by a ResourceOwner
    1402             :  *
    1403             :  * Caller must have previously done ResourceOwnerEnlargeDSMs()
    1404             :  */
    1405             : void
    1406       29584 : ResourceOwnerRememberDSM(ResourceOwner owner, dsm_segment *seg)
    1407             : {
    1408       29584 :     ResourceArrayAdd(&(owner->dsmarr), PointerGetDatum(seg));
    1409       29584 : }
    1410             : 
    1411             : /*
    1412             :  * Forget that a dynamic shmem segment is owned by a ResourceOwner
    1413             :  */
    1414             : void
    1415       29584 : ResourceOwnerForgetDSM(ResourceOwner owner, dsm_segment *seg)
    1416             : {
    1417       29584 :     if (!ResourceArrayRemove(&(owner->dsmarr), PointerGetDatum(seg)))
    1418           0 :         elog(ERROR, "dynamic shared memory segment %u is not owned by resource owner %s",
    1419             :              dsm_segment_handle(seg), owner->name);
    1420       29584 : }
    1421             : 
    1422             : /*
    1423             :  * Debugging subroutine
    1424             :  */
    1425             : static void
    1426           0 : PrintDSMLeakWarning(dsm_segment *seg)
    1427             : {
    1428           0 :     elog(WARNING, "dynamic shared memory leak: segment %u still referenced",
    1429             :          dsm_segment_handle(seg));
    1430           0 : }
    1431             : 
    1432             : /*
    1433             :  * Make sure there is room for at least one more entry in a ResourceOwner's
    1434             :  * JIT context reference array.
    1435             :  *
    1436             :  * This is separate from actually inserting an entry because if we run out of
    1437             :  * memory, it's critical to do so *before* acquiring the resource.
    1438             :  */
    1439             : void
    1440        1664 : ResourceOwnerEnlargeJIT(ResourceOwner owner)
    1441             : {
    1442        1664 :     ResourceArrayEnlarge(&(owner->jitarr));
    1443        1664 : }
    1444             : 
    1445             : /*
    1446             :  * Remember that a JIT context is owned by a ResourceOwner
    1447             :  *
    1448             :  * Caller must have previously done ResourceOwnerEnlargeJIT()
    1449             :  */
    1450             : void
    1451        1664 : ResourceOwnerRememberJIT(ResourceOwner owner, Datum handle)
    1452             : {
    1453        1664 :     ResourceArrayAdd(&(owner->jitarr), handle);
    1454        1664 : }
    1455             : 
    1456             : /*
    1457             :  * Forget that a JIT context is owned by a ResourceOwner
    1458             :  */
    1459             : void
    1460        1664 : ResourceOwnerForgetJIT(ResourceOwner owner, Datum handle)
    1461             : {
    1462        1664 :     if (!ResourceArrayRemove(&(owner->jitarr), handle))
    1463           0 :         elog(ERROR, "JIT context %p is not owned by resource owner %s",
    1464             :              DatumGetPointer(handle), owner->name);
    1465        1664 : }
    1466             : 
    1467             : /*
    1468             :  * Make sure there is room for at least one more entry in a ResourceOwner's
    1469             :  * cryptohash context reference array.
    1470             :  *
    1471             :  * This is separate from actually inserting an entry because if we run out of
    1472             :  * memory, it's critical to do so *before* acquiring the resource.
    1473             :  */
    1474             : void
    1475      852410 : ResourceOwnerEnlargeCryptoHash(ResourceOwner owner)
    1476             : {
    1477      852410 :     ResourceArrayEnlarge(&(owner->cryptohasharr));
    1478      852410 : }
    1479             : 
    1480             : /*
    1481             :  * Remember that a cryptohash context is owned by a ResourceOwner
    1482             :  *
    1483             :  * Caller must have previously done ResourceOwnerEnlargeCryptoHash()
    1484             :  */
    1485             : void
    1486      852410 : ResourceOwnerRememberCryptoHash(ResourceOwner owner, Datum handle)
    1487             : {
    1488      852410 :     ResourceArrayAdd(&(owner->cryptohasharr), handle);
    1489      852410 : }
    1490             : 
    1491             : /*
    1492             :  * Forget that a cryptohash context is owned by a ResourceOwner
    1493             :  */
    1494             : void
    1495      852400 : ResourceOwnerForgetCryptoHash(ResourceOwner owner, Datum handle)
    1496             : {
    1497      852400 :     if (!ResourceArrayRemove(&(owner->cryptohasharr), handle))
    1498           0 :         elog(ERROR, "cryptohash context %p is not owned by resource owner %s",
    1499             :              DatumGetPointer(handle), owner->name);
    1500      852400 : }
    1501             : 
    1502             : /*
    1503             :  * Debugging subroutine
    1504             :  */
    1505             : static void
    1506           0 : PrintCryptoHashLeakWarning(Datum handle)
    1507             : {
    1508           0 :     elog(WARNING, "cryptohash context reference leak: context %p still referenced",
    1509             :          DatumGetPointer(handle));
    1510           0 : }
    1511             : 
    1512             : /*
    1513             :  * Make sure there is room for at least one more entry in a ResourceOwner's
    1514             :  * hmac context reference array.
    1515             :  *
    1516             :  * This is separate from actually inserting an entry because if we run out of
    1517             :  * memory, it's critical to do so *before* acquiring the resource.
    1518             :  */
    1519             : void
    1520         454 : ResourceOwnerEnlargeHMAC(ResourceOwner owner)
    1521             : {
    1522         454 :     ResourceArrayEnlarge(&(owner->hmacarr));
    1523         454 : }
    1524             : 
    1525             : /*
    1526             :  * Remember that a HMAC context is owned by a ResourceOwner
    1527             :  *
    1528             :  * Caller must have previously done ResourceOwnerEnlargeHMAC()
    1529             :  */
    1530             : void
    1531         454 : ResourceOwnerRememberHMAC(ResourceOwner owner, Datum handle)
    1532             : {
    1533         454 :     ResourceArrayAdd(&(owner->hmacarr), handle);
    1534         454 : }
    1535             : 
    1536             : /*
    1537             :  * Forget that a HMAC context is owned by a ResourceOwner
    1538             :  */
    1539             : void
    1540         454 : ResourceOwnerForgetHMAC(ResourceOwner owner, Datum handle)
    1541             : {
    1542         454 :     if (!ResourceArrayRemove(&(owner->hmacarr), handle))
    1543           0 :         elog(ERROR, "HMAC context %p is not owned by resource owner %s",
    1544             :              DatumGetPointer(handle), owner->name);
    1545         454 : }
    1546             : 
    1547             : /*
    1548             :  * Debugging subroutine
    1549             :  */
    1550             : static void
    1551           0 : PrintHMACLeakWarning(Datum handle)
    1552             : {
    1553           0 :     elog(WARNING, "HMAC context reference leak: context %p still referenced",
    1554             :          DatumGetPointer(handle));
    1555           0 : }

Generated by: LCOV version 1.14