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