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