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