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-2019, PostgreSQL Global Development Group
13  * Portions Copyright (c) 1994, Regents of the University of California
14  *
15  *
16  * IDENTIFICATION
17  * src/backend/utils/resowner/resowner.c
18  *
19  *-------------------------------------------------------------------------
20  */
21 #include "postgres.h"
22 
23 #include "jit/jit.h"
24 #include "storage/bufmgr.h"
25 #include "storage/ipc.h"
26 #include "storage/predicate.h"
27 #include "storage/proc.h"
28 #include "utils/hashutils.h"
29 #include "utils/memutils.h"
30 #include "utils/rel.h"
31 #include "utils/resowner_private.h"
32 #include "utils/snapmgr.h"
33 
34 
35 /*
36  * All resource IDs managed by this code are required to fit into a Datum,
37  * which is fine since they are generally pointers or integers.
38  *
39  * Provide Datum conversion macros for a couple of things that are really
40  * just "int".
41  */
42 #define FileGetDatum(file) Int32GetDatum(file)
43 #define DatumGetFile(datum) ((File) DatumGetInt32(datum))
44 #define BufferGetDatum(buffer) Int32GetDatum(buffer)
45 #define DatumGetBuffer(datum) ((Buffer) DatumGetInt32(datum))
46 
47 /*
48  * ResourceArray is a common structure for storing all types of resource IDs.
49  *
50  * We manage small sets of resource IDs by keeping them in a simple array:
51  * itemsarr[k] holds an ID, for 0 <= k < nitems <= maxitems = capacity.
52  *
53  * If a set grows large, we switch over to using open-addressing hashing.
54  * Then, itemsarr[] is a hash table of "capacity" slots, with each
55  * slot holding either an ID or "invalidval". nitems is the number of valid
56  * items present; if it would exceed maxitems, we enlarge the array and
57  * re-hash. In this mode, maxitems should be rather less than capacity so
58  * that we don't waste too much time searching for empty slots.
59  *
60  * In either mode, lastidx remembers the location of the last item inserted
61  * or returned by GetAny; this speeds up searches in ResourceArrayRemove.
62  */
63 typedef struct ResourceArray
64 {
65  Datum *itemsarr; /* buffer for storing values */
66  Datum invalidval; /* value that is considered invalid */
67  uint32 capacity; /* allocated length of itemsarr[] */
68  uint32 nitems; /* how many items are stored in items array */
69  uint32 maxitems; /* current limit on nitems before enlarging */
70  uint32 lastidx; /* index of last item returned by GetAny */
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  * ResourceOwnerDelete
683  * Delete an owner object and its descendants.
684  *
685  * The caller must have already released all resources in the object tree.
686  */
687 void
689 {
690  /* We had better not be deleting CurrentResourceOwner ... */
691  Assert(owner != CurrentResourceOwner);
692 
693  /* And it better not own any resources, either */
694  Assert(owner->bufferarr.nitems == 0);
695  Assert(owner->catrefarr.nitems == 0);
696  Assert(owner->catlistrefarr.nitems == 0);
697  Assert(owner->relrefarr.nitems == 0);
698  Assert(owner->planrefarr.nitems == 0);
699  Assert(owner->tupdescarr.nitems == 0);
700  Assert(owner->snapshotarr.nitems == 0);
701  Assert(owner->filearr.nitems == 0);
702  Assert(owner->dsmarr.nitems == 0);
703  Assert(owner->jitarr.nitems == 0);
704  Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1);
705 
706  /*
707  * Delete children. The recursive call will delink the child from me, so
708  * just iterate as long as there is a child.
709  */
710  while (owner->firstchild != NULL)
712 
713  /*
714  * We delink the owner from its parent before deleting it, so that if
715  * there's an error we won't have deleted/busted owners still attached to
716  * the owner tree. Better a leak than a crash.
717  */
718  ResourceOwnerNewParent(owner, NULL);
719 
720  /* And free the object. */
721  ResourceArrayFree(&(owner->bufferarr));
722  ResourceArrayFree(&(owner->catrefarr));
723  ResourceArrayFree(&(owner->catlistrefarr));
724  ResourceArrayFree(&(owner->relrefarr));
725  ResourceArrayFree(&(owner->planrefarr));
726  ResourceArrayFree(&(owner->tupdescarr));
727  ResourceArrayFree(&(owner->snapshotarr));
728  ResourceArrayFree(&(owner->filearr));
729  ResourceArrayFree(&(owner->dsmarr));
730  ResourceArrayFree(&(owner->jitarr));
731 
732  pfree(owner);
733 }
734 
735 /*
736  * Fetch parent of a ResourceOwner (returns NULL if top-level owner)
737  */
740 {
741  return owner->parent;
742 }
743 
744 /*
745  * Reassign a ResourceOwner to have a new parent
746  */
747 void
749  ResourceOwner newparent)
750 {
751  ResourceOwner oldparent = owner->parent;
752 
753  if (oldparent)
754  {
755  if (owner == oldparent->firstchild)
756  oldparent->firstchild = owner->nextchild;
757  else
758  {
759  ResourceOwner child;
760 
761  for (child = oldparent->firstchild; child; child = child->nextchild)
762  {
763  if (owner == child->nextchild)
764  {
765  child->nextchild = owner->nextchild;
766  break;
767  }
768  }
769  }
770  }
771 
772  if (newparent)
773  {
774  Assert(owner != newparent);
775  owner->parent = newparent;
776  owner->nextchild = newparent->firstchild;
777  newparent->firstchild = owner;
778  }
779  else
780  {
781  owner->parent = NULL;
782  owner->nextchild = NULL;
783  }
784 }
785 
786 /*
787  * Register or deregister callback functions for resource cleanup
788  *
789  * These functions are intended for use by dynamically loaded modules.
790  * For built-in modules we generally just hardwire the appropriate calls.
791  *
792  * Note that the callback occurs post-commit or post-abort, so the callback
793  * functions can only do noncritical cleanup.
794  */
795 void
797 {
799 
800  item = (ResourceReleaseCallbackItem *)
803  item->callback = callback;
804  item->arg = arg;
806  ResourceRelease_callbacks = item;
807 }
808 
809 void
811 {
814 
815  prev = NULL;
816  for (item = ResourceRelease_callbacks; item; prev = item, item = item->next)
817  {
818  if (item->callback == callback && item->arg == arg)
819  {
820  if (prev)
821  prev->next = item->next;
822  else
823  ResourceRelease_callbacks = item->next;
824  pfree(item);
825  break;
826  }
827  }
828 }
829 
830 /*
831  * Establish an AuxProcessResourceOwner for the current process.
832  */
833 void
835 {
836  Assert(AuxProcessResourceOwner == NULL);
837  Assert(CurrentResourceOwner == NULL);
838  AuxProcessResourceOwner = ResourceOwnerCreate(NULL, "AuxiliaryProcess");
839  CurrentResourceOwner = AuxProcessResourceOwner;
840 
841  /*
842  * Register a shmem-exit callback for cleanup of aux-process resource
843  * owner. (This needs to run after, e.g., ShutdownXLOG.)
844  */
846 
847 }
848 
849 /*
850  * Convenience routine to release all resources tracked in
851  * AuxProcessResourceOwner (but that resowner is not destroyed here).
852  * Warn about leaked resources if isCommit is true.
853  */
854 void
856 {
857  /*
858  * At this writing, the only thing that could actually get released is
859  * buffer pins; but we may as well do the full release protocol.
860  */
861  ResourceOwnerRelease(AuxProcessResourceOwner,
863  isCommit, true);
864  ResourceOwnerRelease(AuxProcessResourceOwner,
866  isCommit, true);
867  ResourceOwnerRelease(AuxProcessResourceOwner,
869  isCommit, true);
870 }
871 
872 /*
873  * Shmem-exit callback for the same.
874  * Warn about leaked resources if process exit code is zero (ie normal).
875  */
876 static void
878 {
879  bool isCommit = (code == 0);
880 
881  ReleaseAuxProcessResources(isCommit);
882 }
883 
884 
885 /*
886  * Make sure there is room for at least one more entry in a ResourceOwner's
887  * buffer array.
888  *
889  * This is separate from actually inserting an entry because if we run out
890  * of memory, it's critical to do so *before* acquiring the resource.
891  */
892 void
894 {
895  /* We used to allow pinning buffers without a resowner, but no more */
896  Assert(owner != NULL);
897  ResourceArrayEnlarge(&(owner->bufferarr));
898 }
899 
900 /*
901  * Remember that a buffer pin is owned by a ResourceOwner
902  *
903  * Caller must have previously done ResourceOwnerEnlargeBuffers()
904  */
905 void
907 {
908  ResourceArrayAdd(&(owner->bufferarr), BufferGetDatum(buffer));
909 }
910 
911 /*
912  * Forget that a buffer pin is owned by a ResourceOwner
913  */
914 void
916 {
917  if (!ResourceArrayRemove(&(owner->bufferarr), BufferGetDatum(buffer)))
918  elog(ERROR, "buffer %d is not owned by resource owner %s",
919  buffer, owner->name);
920 }
921 
922 /*
923  * Remember that a Local Lock is owned by a ResourceOwner
924  *
925  * This is different from the other Remember functions in that the list of
926  * locks is only a lossy cache. It can hold up to MAX_RESOWNER_LOCKS entries,
927  * and when it overflows, we stop tracking locks. The point of only remembering
928  * only up to MAX_RESOWNER_LOCKS entries is that if a lot of locks are held,
929  * ResourceOwnerForgetLock doesn't need to scan through a large array to find
930  * the entry.
931  */
932 void
934 {
935  Assert(locallock != NULL);
936 
937  if (owner->nlocks > MAX_RESOWNER_LOCKS)
938  return; /* we have already overflowed */
939 
940  if (owner->nlocks < MAX_RESOWNER_LOCKS)
941  owner->locks[owner->nlocks] = locallock;
942  else
943  {
944  /* overflowed */
945  }
946  owner->nlocks++;
947 }
948 
949 /*
950  * Forget that a Local Lock is owned by a ResourceOwner
951  */
952 void
954 {
955  int i;
956 
957  if (owner->nlocks > MAX_RESOWNER_LOCKS)
958  return; /* we have overflowed */
959 
960  Assert(owner->nlocks > 0);
961  for (i = owner->nlocks - 1; i >= 0; i--)
962  {
963  if (locallock == owner->locks[i])
964  {
965  owner->locks[i] = owner->locks[owner->nlocks - 1];
966  owner->nlocks--;
967  return;
968  }
969  }
970  elog(ERROR, "lock reference %p is not owned by resource owner %s",
971  locallock, owner->name);
972 }
973 
974 /*
975  * Make sure there is room for at least one more entry in a ResourceOwner's
976  * catcache reference array.
977  *
978  * This is separate from actually inserting an entry because if we run out
979  * of memory, it's critical to do so *before* acquiring the resource.
980  */
981 void
983 {
984  ResourceArrayEnlarge(&(owner->catrefarr));
985 }
986 
987 /*
988  * Remember that a catcache reference is owned by a ResourceOwner
989  *
990  * Caller must have previously done ResourceOwnerEnlargeCatCacheRefs()
991  */
992 void
994 {
995  ResourceArrayAdd(&(owner->catrefarr), PointerGetDatum(tuple));
996 }
997 
998 /*
999  * Forget that a catcache reference is owned by a ResourceOwner
1000  */
1001 void
1003 {
1004  if (!ResourceArrayRemove(&(owner->catrefarr), PointerGetDatum(tuple)))
1005  elog(ERROR, "catcache reference %p is not owned by resource owner %s",
1006  tuple, owner->name);
1007 }
1008 
1009 /*
1010  * Make sure there is room for at least one more entry in a ResourceOwner's
1011  * catcache-list reference array.
1012  *
1013  * This is separate from actually inserting an entry because if we run out
1014  * of memory, it's critical to do so *before* acquiring the resource.
1015  */
1016 void
1018 {
1020 }
1021 
1022 /*
1023  * Remember that a catcache-list reference is owned by a ResourceOwner
1024  *
1025  * Caller must have previously done ResourceOwnerEnlargeCatCacheListRefs()
1026  */
1027 void
1029 {
1031 }
1032 
1033 /*
1034  * Forget that a catcache-list reference is owned by a ResourceOwner
1035  */
1036 void
1038 {
1039  if (!ResourceArrayRemove(&(owner->catlistrefarr), PointerGetDatum(list)))
1040  elog(ERROR, "catcache list reference %p is not owned by resource owner %s",
1041  list, owner->name);
1042 }
1043 
1044 /*
1045  * Make sure there is room for at least one more entry in a ResourceOwner's
1046  * relcache reference array.
1047  *
1048  * This is separate from actually inserting an entry because if we run out
1049  * of memory, it's critical to do so *before* acquiring the resource.
1050  */
1051 void
1053 {
1054  ResourceArrayEnlarge(&(owner->relrefarr));
1055 }
1056 
1057 /*
1058  * Remember that a relcache reference is owned by a ResourceOwner
1059  *
1060  * Caller must have previously done ResourceOwnerEnlargeRelationRefs()
1061  */
1062 void
1064 {
1065  ResourceArrayAdd(&(owner->relrefarr), PointerGetDatum(rel));
1066 }
1067 
1068 /*
1069  * Forget that a relcache reference is owned by a ResourceOwner
1070  */
1071 void
1073 {
1074  if (!ResourceArrayRemove(&(owner->relrefarr), PointerGetDatum(rel)))
1075  elog(ERROR, "relcache reference %s is not owned by resource owner %s",
1076  RelationGetRelationName(rel), owner->name);
1077 }
1078 
1079 /*
1080  * Debugging subroutine
1081  */
1082 static void
1084 {
1085  elog(WARNING, "relcache reference leak: relation \"%s\" not closed",
1087 }
1088 
1089 /*
1090  * Make sure there is room for at least one more entry in a ResourceOwner's
1091  * plancache reference array.
1092  *
1093  * This is separate from actually inserting an entry because if we run out
1094  * of memory, it's critical to do so *before* acquiring the resource.
1095  */
1096 void
1098 {
1099  ResourceArrayEnlarge(&(owner->planrefarr));
1100 }
1101 
1102 /*
1103  * Remember that a plancache reference is owned by a ResourceOwner
1104  *
1105  * Caller must have previously done ResourceOwnerEnlargePlanCacheRefs()
1106  */
1107 void
1109 {
1110  ResourceArrayAdd(&(owner->planrefarr), PointerGetDatum(plan));
1111 }
1112 
1113 /*
1114  * Forget that a plancache reference is owned by a ResourceOwner
1115  */
1116 void
1118 {
1119  if (!ResourceArrayRemove(&(owner->planrefarr), PointerGetDatum(plan)))
1120  elog(ERROR, "plancache reference %p is not owned by resource owner %s",
1121  plan, owner->name);
1122 }
1123 
1124 /*
1125  * Debugging subroutine
1126  */
1127 static void
1129 {
1130  elog(WARNING, "plancache reference leak: plan %p not closed", plan);
1131 }
1132 
1133 /*
1134  * Make sure there is room for at least one more entry in a ResourceOwner's
1135  * tupdesc reference array.
1136  *
1137  * This is separate from actually inserting an entry because if we run out
1138  * of memory, it's critical to do so *before* acquiring the resource.
1139  */
1140 void
1142 {
1143  ResourceArrayEnlarge(&(owner->tupdescarr));
1144 }
1145 
1146 /*
1147  * Remember that a tupdesc reference is owned by a ResourceOwner
1148  *
1149  * Caller must have previously done ResourceOwnerEnlargeTupleDescs()
1150  */
1151 void
1153 {
1154  ResourceArrayAdd(&(owner->tupdescarr), PointerGetDatum(tupdesc));
1155 }
1156 
1157 /*
1158  * Forget that a tupdesc reference is owned by a ResourceOwner
1159  */
1160 void
1162 {
1163  if (!ResourceArrayRemove(&(owner->tupdescarr), PointerGetDatum(tupdesc)))
1164  elog(ERROR, "tupdesc reference %p is not owned by resource owner %s",
1165  tupdesc, owner->name);
1166 }
1167 
1168 /*
1169  * Debugging subroutine
1170  */
1171 static void
1173 {
1174  elog(WARNING,
1175  "TupleDesc reference leak: TupleDesc %p (%u,%d) still referenced",
1176  tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
1177 }
1178 
1179 /*
1180  * Make sure there is room for at least one more entry in a ResourceOwner's
1181  * snapshot reference array.
1182  *
1183  * This is separate from actually inserting an entry because if we run out
1184  * of memory, it's critical to do so *before* acquiring the resource.
1185  */
1186 void
1188 {
1189  ResourceArrayEnlarge(&(owner->snapshotarr));
1190 }
1191 
1192 /*
1193  * Remember that a snapshot reference is owned by a ResourceOwner
1194  *
1195  * Caller must have previously done ResourceOwnerEnlargeSnapshots()
1196  */
1197 void
1199 {
1200  ResourceArrayAdd(&(owner->snapshotarr), PointerGetDatum(snapshot));
1201 }
1202 
1203 /*
1204  * Forget that a snapshot reference is owned by a ResourceOwner
1205  */
1206 void
1208 {
1209  if (!ResourceArrayRemove(&(owner->snapshotarr), PointerGetDatum(snapshot)))
1210  elog(ERROR, "snapshot reference %p is not owned by resource owner %s",
1211  snapshot, owner->name);
1212 }
1213 
1214 /*
1215  * Debugging subroutine
1216  */
1217 static void
1219 {
1220  elog(WARNING, "Snapshot reference leak: Snapshot %p still referenced",
1221  snapshot);
1222 }
1223 
1224 
1225 /*
1226  * Make sure there is room for at least one more entry in a ResourceOwner's
1227  * files reference array.
1228  *
1229  * This is separate from actually inserting an entry because if we run out
1230  * of memory, it's critical to do so *before* acquiring the resource.
1231  */
1232 void
1234 {
1235  ResourceArrayEnlarge(&(owner->filearr));
1236 }
1237 
1238 /*
1239  * Remember that a temporary file is owned by a ResourceOwner
1240  *
1241  * Caller must have previously done ResourceOwnerEnlargeFiles()
1242  */
1243 void
1245 {
1246  ResourceArrayAdd(&(owner->filearr), FileGetDatum(file));
1247 }
1248 
1249 /*
1250  * Forget that a temporary file is owned by a ResourceOwner
1251  */
1252 void
1254 {
1255  if (!ResourceArrayRemove(&(owner->filearr), FileGetDatum(file)))
1256  elog(ERROR, "temporary file %d is not owned by resource owner %s",
1257  file, owner->name);
1258 }
1259 
1260 /*
1261  * Debugging subroutine
1262  */
1263 static void
1265 {
1266  elog(WARNING, "temporary file leak: File %d still referenced",
1267  file);
1268 }
1269 
1270 /*
1271  * Make sure there is room for at least one more entry in a ResourceOwner's
1272  * dynamic shmem segment reference array.
1273  *
1274  * This is separate from actually inserting an entry because if we run out
1275  * of memory, it's critical to do so *before* acquiring the resource.
1276  */
1277 void
1279 {
1280  ResourceArrayEnlarge(&(owner->dsmarr));
1281 }
1282 
1283 /*
1284  * Remember that a dynamic shmem segment is owned by a ResourceOwner
1285  *
1286  * Caller must have previously done ResourceOwnerEnlargeDSMs()
1287  */
1288 void
1290 {
1291  ResourceArrayAdd(&(owner->dsmarr), PointerGetDatum(seg));
1292 }
1293 
1294 /*
1295  * Forget that a dynamic shmem segment is owned by a ResourceOwner
1296  */
1297 void
1299 {
1300  if (!ResourceArrayRemove(&(owner->dsmarr), PointerGetDatum(seg)))
1301  elog(ERROR, "dynamic shared memory segment %u is not owned by resource owner %s",
1302  dsm_segment_handle(seg), owner->name);
1303 }
1304 
1305 /*
1306  * Debugging subroutine
1307  */
1308 static void
1310 {
1311  elog(WARNING, "dynamic shared memory leak: segment %u still referenced",
1312  dsm_segment_handle(seg));
1313 }
1314 
1315 /*
1316  * Make sure there is room for at least one more entry in a ResourceOwner's
1317  * JIT context reference array.
1318  *
1319  * This is separate from actually inserting an entry because if we run out of
1320  * memory, it's critical to do so *before* acquiring the resource.
1321  */
1322 void
1324 {
1325  ResourceArrayEnlarge(&(owner->jitarr));
1326 }
1327 
1328 /*
1329  * Remember that a JIT context is owned by a ResourceOwner
1330  *
1331  * Caller must have previously done ResourceOwnerEnlargeJIT()
1332  */
1333 void
1335 {
1336  ResourceArrayAdd(&(owner->jitarr), handle);
1337 }
1338 
1339 /*
1340  * Forget that a JIT context is owned by a ResourceOwner
1341  */
1342 void
1344 {
1345  if (!ResourceArrayRemove(&(owner->jitarr), handle))
1346  elog(ERROR, "JIT context %p is not owned by resource owner %s",
1347  DatumGetPointer(handle), owner->name);
1348 }
#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:810
void ResourceOwnerRememberDSM(ResourceOwner owner, dsm_segment *seg)
Definition: resowner.c:1289
void PrintCatCacheListLeakWarning(CatCList *list)
Definition: catcache.c:2087
void ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple)
Definition: resowner.c:993
HeapTupleData * HeapTuple
Definition: htup.h:71
void PrintBufferLeakWarning(Buffer buffer)
Definition: bufmgr.c:2539
Datum hash_any(const unsigned char *k, int keylen)
Definition: hashfn.c:148
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:855
void ResourceOwnerEnlargeSnapshots(ResourceOwner owner)
Definition: resowner.c:1187
void ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel)
Definition: resowner.c:1063
Definition: jit.h:54
void ResourceOwnerDelete(ResourceOwner owner)
Definition: resowner.c:688
#define InvalidBuffer
Definition: buf.h:25
static struct @145 value
dsm_handle dsm_segment_handle(dsm_segment *seg)
Definition: dsm.c:966
void ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner)
Definition: resowner.c:1017
void ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple)
Definition: resowner.c:1002
void ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: resowner.c:1108
uint32 capacity
Definition: resowner.c:67
void ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
Definition: resowner.c:1097
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:263
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
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:3267
struct SnapshotData * Snapshot
Definition: snapshot.h:121
static void ResourceOwnerReleaseInternal(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:488
void ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
Definition: resowner.c:906
ResourceOwner AuxProcessResourceOwner
Definition: resowner.c:145
void ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
Definition: resowner.c:1152
static ResourceReleaseCallbackItem * ResourceRelease_callbacks
Definition: resowner.c:157
void ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: resowner.c:1117
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:2393
struct RelationData * Relation
Definition: relcache.h:26
#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:877
static void PrintSnapshotLeakWarning(Snapshot snapshot)
Definition: resowner.c:1218
void ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
Definition: resowner.c:1072
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:2488
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:361
static void PrintPlanCacheLeakWarning(CachedPlan *plan)
Definition: resowner.c:1128
void ResourceOwnerEnlargeDSMs(ResourceOwner owner)
Definition: resowner.c:1278
void ResourceOwnerRememberFile(ResourceOwner owner, File file)
Definition: resowner.c:1244
void ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot)
Definition: resowner.c:1207
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1259
ResourceArray tupdescarr
Definition: resowner.c:126
#define RelationGetRelationName(relation)
Definition: rel.h:456
void ProcReleaseLocks(bool isCommit)
Definition: proc.c:787
unsigned int uint32
Definition: c.h:359
void ResourceOwnerEnlargeRelationRefs(ResourceOwner owner)
Definition: resowner.c:1052
ResourceReleasePhase
Definition: resowner.h:46
struct ResourceReleaseCallbackItem ResourceReleaseCallbackItem
void RelationClose(Relation relation)
Definition: relcache.c:2088
void ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
Definition: resowner.c:1161
void ResourceOwnerEnlargeTupleDescs(ResourceOwner owner)
Definition: resowner.c:1141
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:893
#define WARNING
Definition: elog.h:40
static void PrintRelCacheLeakWarning(Relation rel)
Definition: resowner.c:1083
struct ResourceReleaseCallbackItem * next
Definition: resowner.c:152
uint32 maxitems
Definition: resowner.c:69
void ResourceOwnerRememberJIT(ResourceOwner owner, Datum handle)
Definition: resowner.c:1334
ResourceOwner ResourceOwnerGetParent(ResourceOwner owner)
Definition: resowner.c:739
uintptr_t Datum
Definition: postgres.h:367
void ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock)
Definition: resowner.c:953
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:1172
void ReleaseCatCache(HeapTuple tuple)
Definition: catcache.c:1440
void ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list)
Definition: resowner.c:1037
void FileClose(File file)
Definition: fd.c:1748
#define BufferGetDatum(buffer)
Definition: resowner.c:44
#define FileGetDatum(file)
Definition: resowner.c:42
void ResourceOwnerForgetJIT(ResourceOwner owner, Datum handle)
Definition: resowner.c:1343
#define Assert(condition)
Definition: c.h:739
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:834
ResourceArray jitarr
Definition: resowner.c:130
void ResourceOwnerForgetDSM(ResourceOwner owner, dsm_segment *seg)
Definition: resowner.c:1298
static void PrintFileLeakWarning(File file)
Definition: resowner.c:1264
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:748
Oid tdtypeid
Definition: tupdesc.h:82
void dsm_detach(dsm_segment *seg)
Definition: dsm.c:664
#define DatumGetBuffer(datum)
Definition: resowner.c:45
struct TupleDescData * TupleDesc
Definition: tupdesc.h:89
void RegisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
Definition: resowner.c:796
void jit_release_context(JitContext *context)
Definition: jit.c:138
void ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot)
Definition: resowner.c:1198
LOCALLOCK * locks[MAX_RESOWNER_LOCKS]
Definition: resowner.c:134
void ResourceOwnerEnlargeFiles(ResourceOwner owner)
Definition: resowner.c:1233
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
#define elog(elevel,...)
Definition: elog.h:228
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:1323
ResourceOwner nextchild
Definition: resowner.c:117
static void PrintDSMLeakWarning(dsm_segment *seg)
Definition: resowner.c:1309
static void ResourceArrayAdd(ResourceArray *resarr, Datum value)
Definition: resowner.c:263
void ResourceOwnerForgetFile(ResourceOwner owner, File file)
Definition: resowner.c:1253
#define RESARRAY_IS_ARRAY(resarr)
Definition: resowner.c:83
int Buffer
Definition: buf.h:23
void ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock)
Definition: resowner.c:933
void ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner)
Definition: resowner.c:982
int File
Definition: fd.h:45
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:915
void ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
Definition: resowner.c:1028