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