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