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

Generated by: LCOV version 1.11