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