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