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

Generated by: LCOV version 1.13