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 "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)
534  ReleaseBuffer(res);
535  }
536 
537  /* Ditto for relcache references */
538  while (ResourceArrayGetAny(&(owner->relrefarr), &foundres))
539  {
540  Relation res = (Relation) DatumGetPointer(foundres);
541 
542  if (isCommit)
544  RelationClose(res);
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)
553  PrintDSMLeakWarning(res);
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)
649  ReleaseCatCache(res);
650  }
651 
652  /* Ditto for catcache lists */
653  while (ResourceArrayGetAny(&(owner->catlistrefarr), &foundres))
654  {
655  CatCList *res = (CatCList *) DatumGetPointer(foundres);
656 
657  if (isCommit)
659  ReleaseCatCacheList(res);
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)
689  UnregisterSnapshot(res);
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;
859  ResourceRelease_callbacks = item;
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
876  ResourceRelease_callbacks = item->next;
877  pfree(item);
878  break;
879  }
880  }
881 }
882 
883 /*
884  * Establish an AuxProcessResourceOwner for the current process.
885  */
886 void
888 {
889  Assert(AuxProcessResourceOwner == NULL);
890  Assert(CurrentResourceOwner == NULL);
891  AuxProcessResourceOwner = ResourceOwnerCreate(NULL, "AuxiliaryProcess");
892  CurrentResourceOwner = AuxProcessResourceOwner;
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 /*
903  * Convenience routine to release all resources tracked in
904  * AuxProcessResourceOwner (but that resowner is not destroyed here).
905  * Warn about leaked resources if isCommit is true.
906  */
907 void
909 {
910  /*
911  * At this writing, the only thing that could actually get released is
912  * buffer pins; but we may as well do the full release protocol.
913  */
914  ResourceOwnerRelease(AuxProcessResourceOwner,
916  isCommit, true);
917  ResourceOwnerRelease(AuxProcessResourceOwner,
919  isCommit, true);
920  ResourceOwnerRelease(AuxProcessResourceOwner,
922  isCommit, true);
923 }
924 
925 /*
926  * Shmem-exit callback for the same.
927  * Warn about leaked resources if process exit code is zero (ie normal).
928  */
929 static void
931 {
932  bool isCommit = (code == 0);
933 
934  ReleaseAuxProcessResources(isCommit);
935 }
936 
937 
938 /*
939  * Make sure there is room for at least one more entry in a ResourceOwner's
940  * buffer array.
941  *
942  * This is separate from actually inserting an entry because if we run out
943  * of memory, it's critical to do so *before* acquiring the resource.
944  */
945 void
947 {
948  /* We used to allow pinning buffers without a resowner, but no more */
949  Assert(owner != NULL);
950  ResourceArrayEnlarge(&(owner->bufferarr));
951 }
952 
953 /*
954  * Remember that a buffer pin is owned by a ResourceOwner
955  *
956  * Caller must have previously done ResourceOwnerEnlargeBuffers()
957  */
958 void
960 {
961  ResourceArrayAdd(&(owner->bufferarr), BufferGetDatum(buffer));
962 }
963 
964 /*
965  * Forget that a buffer pin is owned by a ResourceOwner
966  */
967 void
969 {
970  if (!ResourceArrayRemove(&(owner->bufferarr), BufferGetDatum(buffer)))
971  elog(ERROR, "buffer %d is not owned by resource owner %s",
972  buffer, owner->name);
973 }
974 
975 /*
976  * Remember that a Local Lock is owned by a ResourceOwner
977  *
978  * This is different from the other Remember functions in that the list of
979  * locks is only a lossy cache. It can hold up to MAX_RESOWNER_LOCKS entries,
980  * and when it overflows, we stop tracking locks. The point of only remembering
981  * only up to MAX_RESOWNER_LOCKS entries is that if a lot of locks are held,
982  * ResourceOwnerForgetLock doesn't need to scan through a large array to find
983  * the entry.
984  */
985 void
987 {
988  Assert(locallock != NULL);
989 
990  if (owner->nlocks > MAX_RESOWNER_LOCKS)
991  return; /* we have already overflowed */
992 
993  if (owner->nlocks < MAX_RESOWNER_LOCKS)
994  owner->locks[owner->nlocks] = locallock;
995  else
996  {
997  /* overflowed */
998  }
999  owner->nlocks++;
1000 }
1001 
1002 /*
1003  * Forget that a Local Lock is owned by a ResourceOwner
1004  */
1005 void
1007 {
1008  int i;
1009 
1010  if (owner->nlocks > MAX_RESOWNER_LOCKS)
1011  return; /* we have overflowed */
1012 
1013  Assert(owner->nlocks > 0);
1014  for (i = owner->nlocks - 1; i >= 0; i--)
1015  {
1016  if (locallock == owner->locks[i])
1017  {
1018  owner->locks[i] = owner->locks[owner->nlocks - 1];
1019  owner->nlocks--;
1020  return;
1021  }
1022  }
1023  elog(ERROR, "lock reference %p is not owned by resource owner %s",
1024  locallock, owner->name);
1025 }
1026 
1027 /*
1028  * Make sure there is room for at least one more entry in a ResourceOwner's
1029  * catcache reference array.
1030  *
1031  * This is separate from actually inserting an entry because if we run out
1032  * of memory, it's critical to do so *before* acquiring the resource.
1033  */
1034 void
1036 {
1037  ResourceArrayEnlarge(&(owner->catrefarr));
1038 }
1039 
1040 /*
1041  * Remember that a catcache reference is owned by a ResourceOwner
1042  *
1043  * Caller must have previously done ResourceOwnerEnlargeCatCacheRefs()
1044  */
1045 void
1047 {
1048  ResourceArrayAdd(&(owner->catrefarr), PointerGetDatum(tuple));
1049 }
1050 
1051 /*
1052  * Forget that a catcache reference is owned by a ResourceOwner
1053  */
1054 void
1056 {
1057  if (!ResourceArrayRemove(&(owner->catrefarr), PointerGetDatum(tuple)))
1058  elog(ERROR, "catcache reference %p is not owned by resource owner %s",
1059  tuple, owner->name);
1060 }
1061 
1062 /*
1063  * Make sure there is room for at least one more entry in a ResourceOwner's
1064  * catcache-list reference array.
1065  *
1066  * This is separate from actually inserting an entry because if we run out
1067  * of memory, it's critical to do so *before* acquiring the resource.
1068  */
1069 void
1071 {
1073 }
1074 
1075 /*
1076  * Remember that a catcache-list reference is owned by a ResourceOwner
1077  *
1078  * Caller must have previously done ResourceOwnerEnlargeCatCacheListRefs()
1079  */
1080 void
1082 {
1084 }
1085 
1086 /*
1087  * Forget that a catcache-list reference is owned by a ResourceOwner
1088  */
1089 void
1091 {
1092  if (!ResourceArrayRemove(&(owner->catlistrefarr), PointerGetDatum(list)))
1093  elog(ERROR, "catcache list reference %p is not owned by resource owner %s",
1094  list, owner->name);
1095 }
1096 
1097 /*
1098  * Make sure there is room for at least one more entry in a ResourceOwner's
1099  * relcache reference array.
1100  *
1101  * This is separate from actually inserting an entry because if we run out
1102  * of memory, it's critical to do so *before* acquiring the resource.
1103  */
1104 void
1106 {
1107  ResourceArrayEnlarge(&(owner->relrefarr));
1108 }
1109 
1110 /*
1111  * Remember that a relcache reference is owned by a ResourceOwner
1112  *
1113  * Caller must have previously done ResourceOwnerEnlargeRelationRefs()
1114  */
1115 void
1117 {
1118  ResourceArrayAdd(&(owner->relrefarr), PointerGetDatum(rel));
1119 }
1120 
1121 /*
1122  * Forget that a relcache reference is owned by a ResourceOwner
1123  */
1124 void
1126 {
1127  if (!ResourceArrayRemove(&(owner->relrefarr), PointerGetDatum(rel)))
1128  elog(ERROR, "relcache reference %s is not owned by resource owner %s",
1129  RelationGetRelationName(rel), owner->name);
1130 }
1131 
1132 /*
1133  * Debugging subroutine
1134  */
1135 static void
1137 {
1138  elog(WARNING, "relcache reference leak: relation \"%s\" not closed",
1140 }
1141 
1142 /*
1143  * Make sure there is room for at least one more entry in a ResourceOwner's
1144  * plancache reference array.
1145  *
1146  * This is separate from actually inserting an entry because if we run out
1147  * of memory, it's critical to do so *before* acquiring the resource.
1148  */
1149 void
1151 {
1152  ResourceArrayEnlarge(&(owner->planrefarr));
1153 }
1154 
1155 /*
1156  * Remember that a plancache reference is owned by a ResourceOwner
1157  *
1158  * Caller must have previously done ResourceOwnerEnlargePlanCacheRefs()
1159  */
1160 void
1162 {
1163  ResourceArrayAdd(&(owner->planrefarr), PointerGetDatum(plan));
1164 }
1165 
1166 /*
1167  * Forget that a plancache reference is owned by a ResourceOwner
1168  */
1169 void
1171 {
1172  if (!ResourceArrayRemove(&(owner->planrefarr), PointerGetDatum(plan)))
1173  elog(ERROR, "plancache reference %p is not owned by resource owner %s",
1174  plan, owner->name);
1175 }
1176 
1177 /*
1178  * Debugging subroutine
1179  */
1180 static void
1182 {
1183  elog(WARNING, "plancache reference leak: plan %p not closed", plan);
1184 }
1185 
1186 /*
1187  * Make sure there is room for at least one more entry in a ResourceOwner's
1188  * tupdesc reference array.
1189  *
1190  * This is separate from actually inserting an entry because if we run out
1191  * of memory, it's critical to do so *before* acquiring the resource.
1192  */
1193 void
1195 {
1196  ResourceArrayEnlarge(&(owner->tupdescarr));
1197 }
1198 
1199 /*
1200  * Remember that a tupdesc reference is owned by a ResourceOwner
1201  *
1202  * Caller must have previously done ResourceOwnerEnlargeTupleDescs()
1203  */
1204 void
1206 {
1207  ResourceArrayAdd(&(owner->tupdescarr), PointerGetDatum(tupdesc));
1208 }
1209 
1210 /*
1211  * Forget that a tupdesc reference is owned by a ResourceOwner
1212  */
1213 void
1215 {
1216  if (!ResourceArrayRemove(&(owner->tupdescarr), PointerGetDatum(tupdesc)))
1217  elog(ERROR, "tupdesc reference %p is not owned by resource owner %s",
1218  tupdesc, owner->name);
1219 }
1220 
1221 /*
1222  * Debugging subroutine
1223  */
1224 static void
1226 {
1227  elog(WARNING,
1228  "TupleDesc reference leak: TupleDesc %p (%u,%d) still referenced",
1229  tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
1230 }
1231 
1232 /*
1233  * Make sure there is room for at least one more entry in a ResourceOwner's
1234  * snapshot reference array.
1235  *
1236  * This is separate from actually inserting an entry because if we run out
1237  * of memory, it's critical to do so *before* acquiring the resource.
1238  */
1239 void
1241 {
1242  ResourceArrayEnlarge(&(owner->snapshotarr));
1243 }
1244 
1245 /*
1246  * Remember that a snapshot reference is owned by a ResourceOwner
1247  *
1248  * Caller must have previously done ResourceOwnerEnlargeSnapshots()
1249  */
1250 void
1252 {
1253  ResourceArrayAdd(&(owner->snapshotarr), PointerGetDatum(snapshot));
1254 }
1255 
1256 /*
1257  * Forget that a snapshot reference is owned by a ResourceOwner
1258  */
1259 void
1261 {
1262  if (!ResourceArrayRemove(&(owner->snapshotarr), PointerGetDatum(snapshot)))
1263  elog(ERROR, "snapshot reference %p is not owned by resource owner %s",
1264  snapshot, owner->name);
1265 }
1266 
1267 /*
1268  * Debugging subroutine
1269  */
1270 static void
1272 {
1273  elog(WARNING, "Snapshot reference leak: Snapshot %p still referenced",
1274  snapshot);
1275 }
1276 
1277 
1278 /*
1279  * Make sure there is room for at least one more entry in a ResourceOwner's
1280  * files reference array.
1281  *
1282  * This is separate from actually inserting an entry because if we run out
1283  * of memory, it's critical to do so *before* acquiring the resource.
1284  */
1285 void
1287 {
1288  ResourceArrayEnlarge(&(owner->filearr));
1289 }
1290 
1291 /*
1292  * Remember that a temporary file is owned by a ResourceOwner
1293  *
1294  * Caller must have previously done ResourceOwnerEnlargeFiles()
1295  */
1296 void
1298 {
1299  ResourceArrayAdd(&(owner->filearr), FileGetDatum(file));
1300 }
1301 
1302 /*
1303  * Forget that a temporary file is owned by a ResourceOwner
1304  */
1305 void
1307 {
1308  if (!ResourceArrayRemove(&(owner->filearr), FileGetDatum(file)))
1309  elog(ERROR, "temporary file %d is not owned by resource owner %s",
1310  file, owner->name);
1311 }
1312 
1313 /*
1314  * Debugging subroutine
1315  */
1316 static void
1318 {
1319  elog(WARNING, "temporary file leak: File %d still referenced",
1320  file);
1321 }
1322 
1323 /*
1324  * Make sure there is room for at least one more entry in a ResourceOwner's
1325  * dynamic shmem segment reference array.
1326  *
1327  * This is separate from actually inserting an entry because if we run out
1328  * of memory, it's critical to do so *before* acquiring the resource.
1329  */
1330 void
1332 {
1333  ResourceArrayEnlarge(&(owner->dsmarr));
1334 }
1335 
1336 /*
1337  * Remember that a dynamic shmem segment is owned by a ResourceOwner
1338  *
1339  * Caller must have previously done ResourceOwnerEnlargeDSMs()
1340  */
1341 void
1343 {
1344  ResourceArrayAdd(&(owner->dsmarr), PointerGetDatum(seg));
1345 }
1346 
1347 /*
1348  * Forget that a dynamic shmem segment is owned by a ResourceOwner
1349  */
1350 void
1352 {
1353  if (!ResourceArrayRemove(&(owner->dsmarr), PointerGetDatum(seg)))
1354  elog(ERROR, "dynamic shared memory segment %u is not owned by resource owner %s",
1355  dsm_segment_handle(seg), owner->name);
1356 }
1357 
1358 /*
1359  * Debugging subroutine
1360  */
1361 static void
1363 {
1364  elog(WARNING, "dynamic shared memory leak: segment %u still referenced",
1365  dsm_segment_handle(seg));
1366 }
1367 
1368 /*
1369  * Make sure there is room for at least one more entry in a ResourceOwner's
1370  * JIT context reference array.
1371  *
1372  * This is separate from actually inserting an entry because if we run out of
1373  * memory, it's critical to do so *before* acquiring the resource.
1374  */
1375 void
1377 {
1378  ResourceArrayEnlarge(&(owner->jitarr));
1379 }
1380 
1381 /*
1382  * Remember that a JIT context is owned by a ResourceOwner
1383  *
1384  * Caller must have previously done ResourceOwnerEnlargeJIT()
1385  */
1386 void
1388 {
1389  ResourceArrayAdd(&(owner->jitarr), handle);
1390 }
1391 
1392 /*
1393  * Forget that a JIT context is owned by a ResourceOwner
1394  */
1395 void
1397 {
1398  if (!ResourceArrayRemove(&(owner->jitarr), handle))
1399  elog(ERROR, "JIT context %p is not owned by resource owner %s",
1400  DatumGetPointer(handle), owner->name);
1401 }
1402 
1403 /*
1404  * Make sure there is room for at least one more entry in a ResourceOwner's
1405  * cryptohash context reference array.
1406  *
1407  * This is separate from actually inserting an entry because if we run out of
1408  * memory, it's critical to do so *before* acquiring the resource.
1409  */
1410 void
1412 {
1414 }
1415 
1416 /*
1417  * Remember that a cryptohash context is owned by a ResourceOwner
1418  *
1419  * Caller must have previously done ResourceOwnerEnlargeCryptoHash()
1420  */
1421 void
1423 {
1424  ResourceArrayAdd(&(owner->cryptohasharr), handle);
1425 }
1426 
1427 /*
1428  * Forget that a cryptohash context is owned by a ResourceOwner
1429  */
1430 void
1432 {
1433  if (!ResourceArrayRemove(&(owner->cryptohasharr), handle))
1434  elog(ERROR, "cryptohash context %p is not owned by resource owner %s",
1435  DatumGetPointer(handle), owner->name);
1436 }
1437 
1438 /*
1439  * Debugging subroutine
1440  */
1441 static void
1443 {
1444  elog(WARNING, "cryptohash context reference leak: context %p still referenced",
1445  DatumGetPointer(handle));
1446 }
1447 
1448 /*
1449  * Make sure there is room for at least one more entry in a ResourceOwner's
1450  * hmac context reference array.
1451  *
1452  * This is separate from actually inserting an entry because if we run out of
1453  * memory, it's critical to do so *before* acquiring the resource.
1454  */
1455 void
1457 {
1458  ResourceArrayEnlarge(&(owner->hmacarr));
1459 }
1460 
1461 /*
1462  * Remember that a HMAC context is owned by a ResourceOwner
1463  *
1464  * Caller must have previously done ResourceOwnerEnlargeHMAC()
1465  */
1466 void
1468 {
1469  ResourceArrayAdd(&(owner->hmacarr), handle);
1470 }
1471 
1472 /*
1473  * Forget that a HMAC context is owned by a ResourceOwner
1474  */
1475 void
1477 {
1478  if (!ResourceArrayRemove(&(owner->hmacarr), handle))
1479  elog(ERROR, "HMAC context %p is not owned by resource owner %s",
1480  DatumGetPointer(handle), owner->name);
1481 }
1482 
1483 /*
1484  * Debugging subroutine
1485  */
1486 static void
1488 {
1489  elog(WARNING, "HMAC context reference leak: context %p still referenced",
1490  DatumGetPointer(handle));
1491 }
#define DatumGetUInt32(X)
Definition: postgres.h:530
#define RESARRAY_INIT_SIZE
Definition: resowner.c:79
static void ResourceArrayEnlarge(ResourceArray *resarr)
Definition: resowner.c:214
ResourceArray relrefarr
Definition: resowner.c:126
void UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
Definition: resowner.c:863
void ResourceOwnerRememberDSM(ResourceOwner owner, dsm_segment *seg)
Definition: resowner.c:1342
void PrintCatCacheListLeakWarning(CatCList *list)
Definition: catcache.c:2089
void ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple)
Definition: resowner.c:1046
HeapTupleData * HeapTuple
Definition: htup.h:71
void PrintBufferLeakWarning(Buffer buffer)
Definition: bufmgr.c:2685
ResourceArray catrefarr
Definition: resowner.c:124
#define DatumGetFile(datum)
Definition: resowner.c:45
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:148
#define PointerGetDatum(X)
Definition: postgres.h:600
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:147
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
uint32 lastidx
Definition: resowner.c:72
void ReleaseAuxProcessResources(bool isCommit)
Definition: resowner.c:908
void ResourceOwnerEnlargeSnapshots(ResourceOwner owner)
Definition: resowner.c:1240
void ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel)
Definition: resowner.c:1116
Definition: jit.h:54
void ResourceOwnerDelete(ResourceOwner owner)
Definition: resowner.c:737
#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:1070
void ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple)
Definition: resowner.c:1055
void ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: resowner.c:1161
uint32 capacity
Definition: resowner.c:69
void ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
Definition: resowner.c:1150
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:3772
ResourceArray bufferarr
Definition: resowner.c:123
static bool ResourceArrayGetAny(ResourceArray *resarr, Datum *value)
Definition: resowner.c:376
ResourceArray snapshotarr
Definition: resowner.c:129
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:496
void ResourceOwnerReleaseAllPlanCacheRefs(ResourceOwner owner)
Definition: resowner.c:718
void ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
Definition: resowner.c:959
void ResourceOwnerEnlargeHMAC(ResourceOwner owner)
Definition: resowner.c:1456
ResourceOwner AuxProcessResourceOwner
Definition: resowner.c:149
void ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
Definition: resowner.c:1205
static ResourceReleaseCallbackItem * ResourceRelease_callbacks
Definition: resowner.c:161
void ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
Definition: resowner.c:1170
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1784
struct ResourceOwnerData * ResourceOwner
Definition: resowner.h:27
#define MAX_RESOWNER_LOCKS
Definition: resowner.c:110
void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks)
Definition: lock.c:2484
struct RelationData * Relation
Definition: relcache.h:27
#define RESARRAY_MAX_ITEMS(capacity)
Definition: resowner.c:91
const char * name
Definition: resowner.c:120
void pfree(void *pointer)
Definition: mcxt.c:1169
struct ResourceArray ResourceArray
#define ERROR
Definition: elog.h:46
Datum * itemsarr
Definition: resowner.c:67
static void ReleaseAuxProcessResourcesCallback(int code, Datum arg)
Definition: resowner.c:930
static void PrintSnapshotLeakWarning(Snapshot snapshot)
Definition: resowner.c:1271
void ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
Definition: resowner.c:1125
Datum invalidval
Definition: resowner.c:68
int32 tdtypmod
Definition: tupdesc.h:83
ResourceArray planrefarr
Definition: resowner.c:127
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
static void ResourceArrayFree(ResourceArray *resarr)
Definition: resowner.c:408
void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks)
Definition: lock.c:2579
void ResourceOwnerRememberCryptoHash(ResourceOwner owner, Datum handle)
Definition: resowner.c:1422
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:361
static void PrintPlanCacheLeakWarning(CachedPlan *plan)
Definition: resowner.c:1181
void ResourceOwnerEnlargeDSMs(ResourceOwner owner)
Definition: resowner.c:1331
void ResourceOwnerRememberFile(ResourceOwner owner, File file)
Definition: resowner.c:1297
void ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot)
Definition: resowner.c:1260
ResourceArray tupdescarr
Definition: resowner.c:128
#define RelationGetRelationName(relation)
Definition: rel.h:511
void ProcReleaseLocks(bool isCommit)
Definition: proc.c:792
unsigned int uint32
Definition: c.h:441
void ResourceOwnerEnlargeRelationRefs(ResourceOwner owner)
Definition: resowner.c:1105
ResourceReleasePhase
Definition: resowner.h:46
struct ResourceReleaseCallbackItem ResourceReleaseCallbackItem
void RelationClose(Relation relation)
Definition: relcache.c:2101
static void PrintHMACLeakWarning(Datum handle)
Definition: resowner.c:1487
static Datum hash_any(const unsigned char *k, int keylen)
Definition: hashfn.h:31
void ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
Definition: resowner.c:1214
void ResourceOwnerEnlargeTupleDescs(ResourceOwner owner)
Definition: resowner.c:1194
static void ResourceArrayInit(ResourceArray *resarr, Datum invalidval)
Definition: resowner.c:195
MemoryContext TopMemoryContext
Definition: mcxt.c:48
void ResourceOwnerEnlargeCryptoHash(ResourceOwner owner)
Definition: resowner.c:1411
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:852
void ResourceOwnerEnlargeBuffers(ResourceOwner owner)
Definition: resowner.c:946
#define WARNING
Definition: elog.h:40
static void PrintRelCacheLeakWarning(Relation rel)
Definition: resowner.c:1136
void pg_hmac_free(pg_hmac_ctx *ctx)
Definition: hmac.c:255
struct ResourceReleaseCallbackItem * next
Definition: resowner.c:156
uint32 maxitems
Definition: resowner.c:71
void ResourceOwnerRememberJIT(ResourceOwner owner, Datum handle)
Definition: resowner.c:1387
ResourceOwner ResourceOwnerGetParent(ResourceOwner owner)
Definition: resowner.c:792
uintptr_t Datum
Definition: postgres.h:411
void ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock)
Definition: resowner.c:1006
ResourceReleaseCallback callback
Definition: resowner.c:157
ResourceOwner firstchild
Definition: resowner.c:118
void PrintCatCacheLeakWarning(HeapTuple tuple)
Definition: catcache.c:2073
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:906
static void PrintTupleDescLeakWarning(TupleDesc tupdesc)
Definition: resowner.c:1225
void ReleaseCatCache(HeapTuple tuple)
Definition: catcache.c:1442
static struct @143 value
void ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list)
Definition: resowner.c:1090
void FileClose(File file)
Definition: fd.c:1917
#define BufferGetDatum(buffer)
Definition: resowner.c:46
#define FileGetDatum(file)
Definition: resowner.c:44
void ResourceOwnerForgetJIT(ResourceOwner owner, Datum handle)
Definition: resowner.c:1396
#define Assert(condition)
Definition: c.h:804
void ResourceOwnerForgetCryptoHash(ResourceOwner owner, Datum handle)
Definition: resowner.c:1431
void ResourceOwnerRelease(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:486
void DecrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:384
void CreateAuxProcessResourceOwner(void)
Definition: resowner.c:887
ResourceArray jitarr
Definition: resowner.c:132
void ResourceOwnerForgetDSM(ResourceOwner owner, dsm_segment *seg)
Definition: resowner.c:1351
static void PrintFileLeakWarning(File file)
Definition: resowner.c:1317
ResourceOwner parent
Definition: resowner.c:117
const char * name
Definition: encode.c:515
static bool ResourceArrayRemove(ResourceArray *resarr, Datum value)
Definition: resowner.c:307
#define DatumGetPointer(X)
Definition: postgres.h:593
void ResourceOwnerNewParent(ResourceOwner owner, ResourceOwner newparent)
Definition: resowner.c:801
Oid tdtypeid
Definition: tupdesc.h:82
void dsm_detach(dsm_segment *seg)
Definition: dsm.c:769
#define DatumGetBuffer(datum)
Definition: resowner.c:47
void ResourceOwnerRememberHMAC(ResourceOwner owner, Datum handle)
Definition: resowner.c:1467
struct TupleDescData * TupleDesc
Definition: tupdesc.h:89
void RegisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
Definition: resowner.c:849
void jit_release_context(JitContext *context)
Definition: jit.c:138
void ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot)
Definition: resowner.c:1251
LOCALLOCK * locks[MAX_RESOWNER_LOCKS]
Definition: resowner.c:138
void ResourceOwnerEnlargeFiles(ResourceOwner owner)
Definition: resowner.c:1286
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
#define elog(elevel,...)
Definition: elog.h:232
int i
void(* ResourceReleaseCallback)(ResourceReleasePhase phase, bool isCommit, bool isTopLevel, void *arg)
Definition: resowner.h:57
void * arg
ResourceArray catlistrefarr
Definition: resowner.c:125
struct ResourceOwnerData ResourceOwnerData
void ResourceOwnerForgetHMAC(ResourceOwner owner, Datum handle)
Definition: resowner.c:1476
ResourceArray dsmarr
Definition: resowner.c:131
void ResourceOwnerEnlargeJIT(ResourceOwner owner)
Definition: resowner.c:1376
ResourceOwner nextchild
Definition: resowner.c:119
static void PrintDSMLeakWarning(dsm_segment *seg)
Definition: resowner.c:1362
static void ResourceArrayAdd(ResourceArray *resarr, Datum value)
Definition: resowner.c:269
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:216
void ResourceOwnerForgetFile(ResourceOwner owner, File file)
Definition: resowner.c:1306
#define RESARRAY_IS_ARRAY(resarr)
Definition: resowner.c:85
int Buffer
Definition: buf.h:23
void ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock)
Definition: resowner.c:986
void ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner)
Definition: resowner.c:1035
int File
Definition: fd.h:54
uint32 nitems
Definition: resowner.c:70
ResourceArray hmacarr
Definition: resowner.c:134
static void PrintCryptoHashLeakWarning(Datum handle)
Definition: resowner.c:1442
ResourceArray filearr
Definition: resowner.c:130
ResourceArray cryptohasharr
Definition: resowner.c:133
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:428
void ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
Definition: resowner.c:968
void ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
Definition: resowner.c:1081