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 on how to use it.
10  *
11  * The implementation consists of a small fixed-size array and a hash table.
12  * New entries are inserted to the fixed-size array, and when the array
13  * fills up, all the entries are moved to the hash table. This way, the
14  * array always contains a few most recently remembered references. To find
15  * a particular reference, you need to search both the array and the hash
16  * table.
17  *
18  * The most frequent usage is that a resource is remembered, and forgotten
19  * shortly thereafter. For example, pin a buffer, read one tuple from it,
20  * release the pin. Linearly scanning the small array handles that case
21  * efficiently. However, some resources are held for a longer time, and
22  * sometimes a lot of resources need to be held simultaneously. The hash
23  * table handles those cases.
24  *
25  * When it's time to release the resources, we sort them according to the
26  * release-priority of each resource, and release them in that order.
27  *
28  * Local lock references are special, they are not stored in the array or
29  * the hash table. Instead, each resource owner has a separate small cache
30  * of locks it owns. The lock manager has the same information in its local
31  * lock hash table, and we fall back on that if the cache overflows, but
32  * traversing the hash table is slower when there are a lot of locks
33  * belonging to other resource owners. This is to speed up bulk releasing
34  * or reassigning locks from a resource owner to its parent.
35  *
36  *
37  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
38  * Portions Copyright (c) 1994, Regents of the University of California
39  *
40  *
41  * IDENTIFICATION
42  * src/backend/utils/resowner/resowner.c
43  *
44  *-------------------------------------------------------------------------
45  */
46 #include "postgres.h"
47 
48 #include "common/hashfn.h"
49 #include "common/int.h"
50 #include "storage/ipc.h"
51 #include "storage/predicate.h"
52 #include "storage/proc.h"
53 #include "utils/memutils.h"
54 #include "utils/resowner.h"
55 
56 /*
57  * ResourceElem represents a reference associated with a resource owner.
58  *
59  * All objects managed by this code are required to fit into a Datum,
60  * which is fine since they are generally pointers or integers.
61  */
62 typedef struct ResourceElem
63 {
65  const ResourceOwnerDesc *kind; /* NULL indicates a free hash table slot */
67 
68 /*
69  * Size of the fixed-size array to hold most-recently remembered resources.
70  */
71 #define RESOWNER_ARRAY_SIZE 32
72 
73 /*
74  * Initially allocated size of a ResourceOwner's hash table. Must be power of
75  * two because we use (capacity - 1) as mask for hashing.
76  */
77 #define RESOWNER_HASH_INIT_SIZE 64
78 
79 /*
80  * How many items may be stored in a hash table of given capacity. When this
81  * number is reached, we must resize.
82  *
83  * The hash table must always have enough free space that we can copy the
84  * entries from the array to it, in ResourceOwnerSort. We also insist that
85  * the initial size is large enough that we don't hit the max size immediately
86  * when it's created. Aside from those limitations, 0.75 is a reasonable fill
87  * factor.
88  */
89 #define RESOWNER_HASH_MAX_ITEMS(capacity) \
90  Min(capacity - RESOWNER_ARRAY_SIZE, (capacity)/4 * 3)
91 
93  "initial hash size too small compared to array size");
94 
95 /*
96  * MAX_RESOWNER_LOCKS is the size of the per-resource owner locks 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  /*
118  * When ResourceOwnerRelease is called, we sort the 'hash' and 'arr' by
119  * the release priority. After that, no new resources can be remembered
120  * or forgotten in retail. We have separate flags because
121  * ResourceOwnerReleaseAllOfKind() temporarily sets 'releasing' without
122  * sorting the arrays.
123  */
124  bool releasing;
125  bool sorted; /* are 'hash' and 'arr' sorted by priority? */
126 
127  /*
128  * Number of items in the locks cache, array, and hash table respectively.
129  * (These are packed together to avoid padding in the struct.)
130  */
131  uint8 nlocks; /* number of owned locks */
132  uint8 narr; /* how many items are stored in the array */
133  uint32 nhash; /* how many items are stored in the hash */
134 
135  /*
136  * The fixed-size array for recent resources.
137  *
138  * If 'sorted' is set, the contents are sorted by release priority.
139  */
141 
142  /*
143  * The hash table. Uses open-addressing. 'nhash' is the number of items
144  * present; if it would exceed 'grow_at', we enlarge it and re-hash.
145  * 'grow_at' should be rather less than 'capacity' so that we don't waste
146  * too much time searching for empty slots.
147  *
148  * If 'sorted' is set, the contents are no longer hashed, but sorted by
149  * release priority. The first 'nhash' elements are occupied, the rest
150  * are empty.
151  */
153  uint32 capacity; /* allocated length of hash[] */
154  uint32 grow_at; /* grow hash when reach this */
155 
156  /* The local locks cache. */
157  LOCALLOCK *locks[MAX_RESOWNER_LOCKS]; /* list of owned locks */
159 
160 
161 /*****************************************************************************
162  * GLOBAL MEMORY *
163  *****************************************************************************/
164 
169 
170 /* #define RESOWNER_STATS */
171 
172 #ifdef RESOWNER_STATS
173 static int narray_lookups = 0;
174 static int nhash_lookups = 0;
175 #endif
176 
177 /*
178  * List of add-on callbacks for resource releasing
179  */
181 {
184  void *arg;
186 
188 
189 
190 /* Internal routines */
191 static inline uint32 hash_resource_elem(Datum value, const ResourceOwnerDesc *kind);
193  const ResourceOwnerDesc *kind);
194 static int resource_priority_cmp(const void *a, const void *b);
195 static void ResourceOwnerSort(ResourceOwner owner);
196 static void ResourceOwnerReleaseAll(ResourceOwner owner,
197  ResourceReleasePhase phase,
198  bool printLeakWarnings);
200  ResourceReleasePhase phase,
201  bool isCommit,
202  bool isTopLevel);
203 static void ReleaseAuxProcessResourcesCallback(int code, Datum arg);
204 
205 
206 /*****************************************************************************
207  * INTERNAL ROUTINES *
208  *****************************************************************************/
209 
210 /*
211  * Hash function for value+kind combination.
212  */
213 static inline uint32
215 {
216  /*
217  * Most resource kinds store a pointer in 'value', and pointers are unique
218  * all on their own. But some resources store plain integers (Files and
219  * Buffers as of this writing), so we want to incorporate the 'kind' in
220  * the hash too, otherwise those resources will collide a lot. But
221  * because there are only a few resource kinds like that - and only a few
222  * resource kinds to begin with - we don't need to work too hard to mix
223  * 'kind' into the hash. Just add it with hash_combine(), it perturbs the
224  * result enough for our purposes.
225  */
226 #if SIZEOF_DATUM == 8
227  return hash_combine64(murmurhash64((uint64) value), (uint64) kind);
228 #else
229  return hash_combine(murmurhash32((uint32) value), (uint32) kind);
230 #endif
231 }
232 
233 /*
234  * Adds 'value' of given 'kind' to the ResourceOwner's hash table
235  */
236 static void
238 {
239  uint32 mask = owner->capacity - 1;
240  uint32 idx;
241 
242  Assert(kind != NULL);
243 
244  /* Insert into first free slot at or after hash location. */
245  idx = hash_resource_elem(value, kind) & mask;
246  for (;;)
247  {
248  if (owner->hash[idx].kind == NULL)
249  break; /* found a free slot */
250  idx = (idx + 1) & mask;
251  }
252  owner->hash[idx].item = value;
253  owner->hash[idx].kind = kind;
254  owner->nhash++;
255 }
256 
257 /*
258  * Comparison function to sort by release phase and priority
259  */
260 static int
261 resource_priority_cmp(const void *a, const void *b)
262 {
263  const ResourceElem *ra = (const ResourceElem *) a;
264  const ResourceElem *rb = (const ResourceElem *) b;
265 
266  /* Note: reverse order */
267  if (ra->kind->release_phase == rb->kind->release_phase)
269  else if (ra->kind->release_phase > rb->kind->release_phase)
270  return -1;
271  else
272  return 1;
273 }
274 
275 /*
276  * Sort resources in reverse release priority.
277  *
278  * If the hash table is in use, all the elements from the fixed-size array are
279  * moved to the hash table, and then the hash table is sorted. If there is no
280  * hash table, then the fixed-size array is sorted directly. In either case,
281  * the result is one sorted array that contains all the resources.
282  */
283 static void
285 {
287  uint32 nitems;
288 
289  if (owner->nhash == 0)
290  {
291  items = owner->arr;
292  nitems = owner->narr;
293  }
294  else
295  {
296  /*
297  * Compact the hash table, so that all the elements are in the
298  * beginning of the 'hash' array, with no empty elements.
299  */
300  uint32 dst = 0;
301 
302  for (int idx = 0; idx < owner->capacity; idx++)
303  {
304  if (owner->hash[idx].kind != NULL)
305  {
306  if (dst != idx)
307  owner->hash[dst] = owner->hash[idx];
308  dst++;
309  }
310  }
311 
312  /*
313  * Move all entries from the fixed-size array to 'hash'.
314  *
315  * RESOWNER_HASH_MAX_ITEMS is defined so that there is always enough
316  * free space to move all the elements from the fixed-size array to
317  * the hash.
318  */
319  Assert(dst + owner->narr <= owner->capacity);
320  for (int idx = 0; idx < owner->narr; idx++)
321  {
322  owner->hash[dst] = owner->arr[idx];
323  dst++;
324  }
325  Assert(dst == owner->nhash + owner->narr);
326  owner->narr = 0;
327  owner->nhash = dst;
328 
329  items = owner->hash;
330  nitems = owner->nhash;
331  }
332 
334 }
335 
336 /*
337  * Call the ReleaseResource callback on entries with given 'phase'.
338  */
339 static void
341  bool printLeakWarnings)
342 {
344  uint32 nitems;
345 
346  /*
347  * ResourceOwnerSort must've been called already. All the resources are
348  * either in the array or the hash.
349  */
350  Assert(owner->releasing);
351  Assert(owner->sorted);
352  if (owner->nhash == 0)
353  {
354  items = owner->arr;
355  nitems = owner->narr;
356  }
357  else
358  {
359  Assert(owner->narr == 0);
360  items = owner->hash;
361  nitems = owner->nhash;
362  }
363 
364  /*
365  * The resources are sorted in reverse priority order. Release them
366  * starting from the end, until we hit the end of the phase that we are
367  * releasing now. We will continue from there when called again for the
368  * next phase.
369  */
370  while (nitems > 0)
371  {
372  uint32 idx = nitems - 1;
373  Datum value = items[idx].item;
374  const ResourceOwnerDesc *kind = items[idx].kind;
375 
376  if (kind->release_phase > phase)
377  break;
378  Assert(kind->release_phase == phase);
379 
380  if (printLeakWarnings)
381  {
382  char *res_str;
383 
384  res_str = kind->DebugPrint ?
385  kind->DebugPrint(value)
386  : psprintf("%s %p", kind->name, DatumGetPointer(value));
387  elog(WARNING, "resource was not closed: %s", res_str);
388  pfree(res_str);
389  }
390  kind->ReleaseResource(value);
391  nitems--;
392  }
393  if (owner->nhash == 0)
394  owner->narr = nitems;
395  else
396  owner->nhash = nitems;
397 }
398 
399 
400 /*****************************************************************************
401  * EXPORTED ROUTINES *
402  *****************************************************************************/
403 
404 
405 /*
406  * ResourceOwnerCreate
407  * Create an empty ResourceOwner.
408  *
409  * All ResourceOwner objects are kept in TopMemoryContext, since they should
410  * only be freed explicitly.
411  */
414 {
415  ResourceOwner owner;
416 
418  sizeof(ResourceOwnerData));
419  owner->name = name;
420 
421  if (parent)
422  {
423  owner->parent = parent;
424  owner->nextchild = parent->firstchild;
425  parent->firstchild = owner;
426  }
427 
428  return owner;
429 }
430 
431 /*
432  * Make sure there is room for at least one more resource in an array.
433  *
434  * This is separate from actually inserting a resource because if we run out
435  * of memory, it's critical to do so *before* acquiring the resource.
436  *
437  * NB: Make sure there are no unrelated ResourceOwnerRemember() calls between
438  * your ResourceOwnerEnlarge() call and the ResourceOwnerRemember() call that
439  * you reserved the space for!
440  */
441 void
443 {
444  /*
445  * Mustn't try to remember more resources after we have already started
446  * releasing
447  */
448  if (owner->releasing)
449  elog(ERROR, "ResourceOwnerEnlarge called after release started");
450 
451  if (owner->narr < RESOWNER_ARRAY_SIZE)
452  return; /* no work needed */
453 
454  /*
455  * Is there space in the hash? If not, enlarge it.
456  */
457  if (owner->narr + owner->nhash >= owner->grow_at)
458  {
459  uint32 i,
460  oldcap,
461  newcap;
462  ResourceElem *oldhash;
463  ResourceElem *newhash;
464 
465  oldhash = owner->hash;
466  oldcap = owner->capacity;
467 
468  /* Double the capacity (it must stay a power of 2!) */
469  newcap = (oldcap > 0) ? oldcap * 2 : RESOWNER_HASH_INIT_SIZE;
471  newcap * sizeof(ResourceElem));
472 
473  /*
474  * We assume we can't fail below this point, so OK to scribble on the
475  * owner
476  */
477  owner->hash = newhash;
478  owner->capacity = newcap;
479  owner->grow_at = RESOWNER_HASH_MAX_ITEMS(newcap);
480  owner->nhash = 0;
481 
482  if (oldhash != NULL)
483  {
484  /*
485  * Transfer any pre-existing entries into the new hash table; they
486  * don't necessarily go where they were before, so this simple
487  * logic is the best way.
488  */
489  for (i = 0; i < oldcap; i++)
490  {
491  if (oldhash[i].kind != NULL)
492  ResourceOwnerAddToHash(owner, oldhash[i].item, oldhash[i].kind);
493  }
494 
495  /* And release old hash table. */
496  pfree(oldhash);
497  }
498  }
499 
500  /* Move items from the array to the hash */
501  for (int i = 0; i < owner->narr; i++)
502  ResourceOwnerAddToHash(owner, owner->arr[i].item, owner->arr[i].kind);
503  owner->narr = 0;
504 
505  Assert(owner->nhash <= owner->grow_at);
506 }
507 
508 /*
509  * Remember that an object is owned by a ResourceOwner
510  *
511  * Caller must have previously done ResourceOwnerEnlarge()
512  */
513 void
515 {
516  uint32 idx;
517 
518  /* sanity check the ResourceOwnerDesc */
519  Assert(kind->release_phase != 0);
520  Assert(kind->release_priority != 0);
521 
522  /*
523  * Mustn't try to remember more resources after we have already started
524  * releasing. We already checked this in ResourceOwnerEnlarge.
525  */
526  Assert(!owner->releasing);
527  Assert(!owner->sorted);
528 
529  if (owner->narr >= RESOWNER_ARRAY_SIZE)
530  {
531  /* forgot to call ResourceOwnerEnlarge? */
532  elog(ERROR, "ResourceOwnerRemember called but array was full");
533  }
534 
535  /* Append to the array. */
536  idx = owner->narr;
537  owner->arr[idx].item = value;
538  owner->arr[idx].kind = kind;
539  owner->narr++;
540 }
541 
542 /*
543  * Forget that an object is owned by a ResourceOwner
544  *
545  * Note: If same resource ID is associated with the ResourceOwner more than
546  * once, one instance is removed.
547  *
548  * Note: Forgetting a resource does not guarantee that there is room to
549  * remember a new resource. One exception is when you forget the most
550  * recently remembered resource; that does make room for a new remember call.
551  * Some code callers rely on that exception.
552  */
553 void
555 {
556  /*
557  * Mustn't call this after we have already started releasing resources.
558  * (Release callback functions are not allowed to release additional
559  * resources.)
560  */
561  if (owner->releasing)
562  elog(ERROR, "ResourceOwnerForget called for %s after release started", kind->name);
563  Assert(!owner->sorted);
564 
565  /* Search through all items in the array first. */
566  for (int i = owner->narr - 1; i >= 0; i--)
567  {
568  if (owner->arr[i].item == value &&
569  owner->arr[i].kind == kind)
570  {
571  owner->arr[i] = owner->arr[owner->narr - 1];
572  owner->narr--;
573 
574 #ifdef RESOWNER_STATS
575  narray_lookups++;
576 #endif
577  return;
578  }
579  }
580 
581  /* Search hash */
582  if (owner->nhash > 0)
583  {
584  uint32 mask = owner->capacity - 1;
585  uint32 idx;
586 
587  idx = hash_resource_elem(value, kind) & mask;
588  for (uint32 i = 0; i < owner->capacity; i++)
589  {
590  if (owner->hash[idx].item == value &&
591  owner->hash[idx].kind == kind)
592  {
593  owner->hash[idx].item = (Datum) 0;
594  owner->hash[idx].kind = NULL;
595  owner->nhash--;
596 
597 #ifdef RESOWNER_STATS
598  nhash_lookups++;
599 #endif
600  return;
601  }
602  idx = (idx + 1) & mask;
603  }
604  }
605 
606  /*
607  * Use %p to print the reference, since most objects tracked by a resource
608  * owner are pointers. It's a bit misleading if it's not a pointer, but
609  * this is a programmer error, anyway.
610  */
611  elog(ERROR, "%s %p is not owned by resource owner %s",
612  kind->name, DatumGetPointer(value), owner->name);
613 }
614 
615 /*
616  * ResourceOwnerRelease
617  * Release all resources owned by a ResourceOwner and its descendants,
618  * but don't delete the owner objects themselves.
619  *
620  * Note that this executes just one phase of release, and so typically
621  * must be called three times. We do it this way because (a) we want to
622  * do all the recursion separately for each phase, thereby preserving
623  * the needed order of operations; and (b) xact.c may have other operations
624  * to do between the phases.
625  *
626  * phase: release phase to execute
627  * isCommit: true for successful completion of a query or transaction,
628  * false for unsuccessful
629  * isTopLevel: true if completing a main transaction, else false
630  *
631  * isCommit is passed because some modules may expect that their resources
632  * were all released already if the transaction or portal finished normally.
633  * If so it is reasonable to give a warning (NOT an error) should any
634  * unreleased resources be present. When isCommit is false, such warnings
635  * are generally inappropriate.
636  *
637  * isTopLevel is passed when we are releasing TopTransactionResourceOwner
638  * at completion of a main transaction. This generally means that *all*
639  * resources will be released, and so we can optimize things a bit.
640  *
641  * NOTE: After starting the release process, by calling this function, no new
642  * resources can be remembered in the resource owner. You also cannot call
643  * ResourceOwnerForget on any previously remembered resources to release
644  * resources "in retail" after that, you must let the bulk release take care
645  * of them.
646  */
647 void
649  ResourceReleasePhase phase,
650  bool isCommit,
651  bool isTopLevel)
652 {
653  /* There's not currently any setup needed before recursing */
654  ResourceOwnerReleaseInternal(owner, phase, isCommit, isTopLevel);
655 
656 #ifdef RESOWNER_STATS
657  if (isTopLevel)
658  {
659  elog(LOG, "RESOWNER STATS: lookups: array %d, hash %d",
660  narray_lookups, nhash_lookups);
661  narray_lookups = 0;
662  nhash_lookups = 0;
663  }
664 #endif
665 }
666 
667 static void
669  ResourceReleasePhase phase,
670  bool isCommit,
671  bool isTopLevel)
672 {
673  ResourceOwner child;
674  ResourceOwner save;
677 
678  /* Recurse to handle descendants */
679  for (child = owner->firstchild; child != NULL; child = child->nextchild)
680  ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel);
681 
682  /*
683  * To release the resources in the right order, sort them by phase and
684  * priority.
685  *
686  * The ReleaseResource callback functions are not allowed to remember or
687  * forget any other resources after this. Otherwise we lose track of where
688  * we are in processing the hash/array.
689  */
690  if (!owner->releasing)
691  {
693  Assert(!owner->sorted);
694  owner->releasing = true;
695  }
696  else
697  {
698  /*
699  * Phase is normally > RESOURCE_RELEASE_BEFORE_LOCKS, if this is not
700  * the first call to ResourceOwnerRelease. But if an error happens
701  * between the release phases, we might get called again for the same
702  * ResourceOwner from AbortTransaction.
703  */
704  }
705  if (!owner->sorted)
706  {
707  ResourceOwnerSort(owner);
708  owner->sorted = true;
709  }
710 
711  /*
712  * Make CurrentResourceOwner point to me, so that the release callback
713  * functions know which resource owner is been released.
714  */
715  save = CurrentResourceOwner;
716  CurrentResourceOwner = owner;
717 
718  if (phase == RESOURCE_RELEASE_BEFORE_LOCKS)
719  {
720  /*
721  * Release all resources that need to be released before the locks.
722  *
723  * During a commit, there shouldn't be any remaining resources ---
724  * that would indicate failure to clean up the executor correctly ---
725  * so issue warnings. In the abort case, just clean up quietly.
726  */
727  ResourceOwnerReleaseAll(owner, phase, isCommit);
728  }
729  else if (phase == RESOURCE_RELEASE_LOCKS)
730  {
731  if (isTopLevel)
732  {
733  /*
734  * For a top-level xact we are going to release all locks (or at
735  * least all non-session locks), so just do a single lmgr call at
736  * the top of the recursion.
737  */
738  if (owner == TopTransactionResourceOwner)
739  {
740  ProcReleaseLocks(isCommit);
741  ReleasePredicateLocks(isCommit, false);
742  }
743  }
744  else
745  {
746  /*
747  * Release locks retail. Note that if we are committing a
748  * subtransaction, we do NOT release its locks yet, but transfer
749  * them to the parent.
750  */
751  LOCALLOCK **locks;
752  int nlocks;
753 
754  Assert(owner->parent != NULL);
755 
756  /*
757  * Pass the list of locks owned by this resource owner to the lock
758  * manager, unless it has overflowed.
759  */
760  if (owner->nlocks > MAX_RESOWNER_LOCKS)
761  {
762  locks = NULL;
763  nlocks = 0;
764  }
765  else
766  {
767  locks = owner->locks;
768  nlocks = owner->nlocks;
769  }
770 
771  if (isCommit)
772  LockReassignCurrentOwner(locks, nlocks);
773  else
774  LockReleaseCurrentOwner(locks, nlocks);
775  }
776  }
777  else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
778  {
779  /*
780  * Release all resources that need to be released after the locks.
781  */
782  ResourceOwnerReleaseAll(owner, phase, isCommit);
783  }
784 
785  /* Let add-on modules get a chance too */
786  for (item = ResourceRelease_callbacks; item; item = next)
787  {
788  /* allow callbacks to unregister themselves when called */
789  next = item->next;
790  item->callback(phase, isCommit, isTopLevel, item->arg);
791  }
792 
793  CurrentResourceOwner = save;
794 }
795 
796 /*
797  * ResourceOwnerReleaseAllOfKind
798  * Release all resources of a certain type held by this owner.
799  */
800 void
802 {
803  /* Mustn't call this after we have already started releasing resources. */
804  if (owner->releasing)
805  elog(ERROR, "ResourceOwnerForget called for %s after release started", kind->name);
806  Assert(!owner->sorted);
807 
808  /*
809  * Temporarily set 'releasing', to prevent calls to ResourceOwnerRemember
810  * while we're scanning the owner. Enlarging the hash would cause us to
811  * lose track of the point we're scanning.
812  */
813  owner->releasing = true;
814 
815  /* Array first */
816  for (int i = 0; i < owner->narr; i++)
817  {
818  if (owner->arr[i].kind == kind)
819  {
820  Datum value = owner->arr[i].item;
821 
822  owner->arr[i] = owner->arr[owner->narr - 1];
823  owner->narr--;
824  i--;
825 
826  kind->ReleaseResource(value);
827  }
828  }
829 
830  /* Then hash */
831  for (int i = 0; i < owner->capacity; i++)
832  {
833  if (owner->hash[i].kind == kind)
834  {
835  Datum value = owner->hash[i].item;
836 
837  owner->hash[i].item = (Datum) 0;
838  owner->hash[i].kind = NULL;
839  owner->nhash--;
840 
841  kind->ReleaseResource(value);
842  }
843  }
844  owner->releasing = false;
845 }
846 
847 /*
848  * ResourceOwnerDelete
849  * Delete an owner object and its descendants.
850  *
851  * The caller must have already released all resources in the object tree.
852  */
853 void
855 {
856  /* We had better not be deleting CurrentResourceOwner ... */
857  Assert(owner != CurrentResourceOwner);
858 
859  /* And it better not own any resources, either */
860  Assert(owner->narr == 0);
861  Assert(owner->nhash == 0);
862  Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1);
863 
864  /*
865  * Delete children. The recursive call will delink the child from me, so
866  * just iterate as long as there is a child.
867  */
868  while (owner->firstchild != NULL)
870 
871  /*
872  * We delink the owner from its parent before deleting it, so that if
873  * there's an error we won't have deleted/busted owners still attached to
874  * the owner tree. Better a leak than a crash.
875  */
876  ResourceOwnerNewParent(owner, NULL);
877 
878  /* And free the object. */
879  if (owner->hash)
880  pfree(owner->hash);
881  pfree(owner);
882 }
883 
884 /*
885  * Fetch parent of a ResourceOwner (returns NULL if top-level owner)
886  */
889 {
890  return owner->parent;
891 }
892 
893 /*
894  * Reassign a ResourceOwner to have a new parent
895  */
896 void
898  ResourceOwner newparent)
899 {
900  ResourceOwner oldparent = owner->parent;
901 
902  if (oldparent)
903  {
904  if (owner == oldparent->firstchild)
905  oldparent->firstchild = owner->nextchild;
906  else
907  {
908  ResourceOwner child;
909 
910  for (child = oldparent->firstchild; child; child = child->nextchild)
911  {
912  if (owner == child->nextchild)
913  {
914  child->nextchild = owner->nextchild;
915  break;
916  }
917  }
918  }
919  }
920 
921  if (newparent)
922  {
923  Assert(owner != newparent);
924  owner->parent = newparent;
925  owner->nextchild = newparent->firstchild;
926  newparent->firstchild = owner;
927  }
928  else
929  {
930  owner->parent = NULL;
931  owner->nextchild = NULL;
932  }
933 }
934 
935 /*
936  * Register or deregister callback functions for resource cleanup
937  *
938  * These functions can be used by dynamically loaded modules. These used
939  * to be the only way for an extension to register custom resource types
940  * with a resource owner, but nowadays it is easier to define a new
941  * ResourceOwnerDesc with custom callbacks.
942  */
943 void
945 {
947 
948  item = (ResourceReleaseCallbackItem *)
951  item->callback = callback;
952  item->arg = arg;
955 }
956 
957 void
959 {
962 
963  prev = NULL;
964  for (item = ResourceRelease_callbacks; item; prev = item, item = item->next)
965  {
966  if (item->callback == callback && item->arg == arg)
967  {
968  if (prev)
969  prev->next = item->next;
970  else
972  pfree(item);
973  break;
974  }
975  }
976 }
977 
978 /*
979  * Establish an AuxProcessResourceOwner for the current process.
980  */
981 void
983 {
985  Assert(CurrentResourceOwner == NULL);
986  AuxProcessResourceOwner = ResourceOwnerCreate(NULL, "AuxiliaryProcess");
988 
989  /*
990  * Register a shmem-exit callback for cleanup of aux-process resource
991  * owner. (This needs to run after, e.g., ShutdownXLOG.)
992  */
994 }
995 
996 /*
997  * Convenience routine to release all resources tracked in
998  * AuxProcessResourceOwner (but that resowner is not destroyed here).
999  * Warn about leaked resources if isCommit is true.
1000  */
1001 void
1003 {
1004  /*
1005  * At this writing, the only thing that could actually get released is
1006  * buffer pins; but we may as well do the full release protocol.
1007  */
1010  isCommit, true);
1013  isCommit, true);
1016  isCommit, true);
1017  /* allow it to be reused */
1020 }
1021 
1022 /*
1023  * Shmem-exit callback for the same.
1024  * Warn about leaked resources if process exit code is zero (ie normal).
1025  */
1026 static void
1028 {
1029  bool isCommit = (code == 0);
1030 
1031  ReleaseAuxProcessResources(isCommit);
1032 }
1033 
1034 /*
1035  * Remember that a Local Lock is owned by a ResourceOwner
1036  *
1037  * This is different from the generic ResourceOwnerRemember in that the list of
1038  * locks is only a lossy cache. It can hold up to MAX_RESOWNER_LOCKS entries,
1039  * and when it overflows, we stop tracking locks. The point of only remembering
1040  * only up to MAX_RESOWNER_LOCKS entries is that if a lot of locks are held,
1041  * ResourceOwnerForgetLock doesn't need to scan through a large array to find
1042  * the entry.
1043  */
1044 void
1046 {
1047  Assert(locallock != NULL);
1048 
1049  if (owner->nlocks > MAX_RESOWNER_LOCKS)
1050  return; /* we have already overflowed */
1051 
1052  if (owner->nlocks < MAX_RESOWNER_LOCKS)
1053  owner->locks[owner->nlocks] = locallock;
1054  else
1055  {
1056  /* overflowed */
1057  }
1058  owner->nlocks++;
1059 }
1060 
1061 /*
1062  * Forget that a Local Lock is owned by a ResourceOwner
1063  */
1064 void
1066 {
1067  int i;
1068 
1069  if (owner->nlocks > MAX_RESOWNER_LOCKS)
1070  return; /* we have overflowed */
1071 
1072  Assert(owner->nlocks > 0);
1073  for (i = owner->nlocks - 1; i >= 0; i--)
1074  {
1075  if (locallock == owner->locks[i])
1076  {
1077  owner->locks[i] = owner->locks[owner->nlocks - 1];
1078  owner->nlocks--;
1079  return;
1080  }
1081  }
1082  elog(ERROR, "lock reference %p is not owned by resource owner %s",
1083  locallock, owner->name);
1084 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
static int32 next
Definition: blutils.c:221
unsigned int uint32
Definition: c.h:506
#define Assert(condition)
Definition: c.h:858
unsigned char uint8
Definition: c.h:504
#define LOG
Definition: elog.h:31
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
static uint64 hash_combine64(uint64 a, uint64 b)
Definition: hashfn.h:80
static uint64 murmurhash64(uint64 data)
Definition: hashfn.h:106
static uint32 hash_combine(uint32 a, uint32 b)
Definition: hashfn.h:68
static uint32 murmurhash32(uint32 data)
Definition: hashfn.h:92
#define nitems(x)
Definition: indent.h:31
static struct @155 value
static int pg_cmp_u32(uint32 a, uint32 b)
Definition: int.h:489
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int i
Definition: isn.c:73
void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks)
Definition: lock.c:2537
void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks)
Definition: lock.c:2442
void pfree(void *pointer)
Definition: mcxt.c:1520
MemoryContext TopMemoryContext
Definition: mcxt.c:149
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1214
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1180
void * arg
#define qsort(a, b, c, d)
Definition: port.h:449
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:3297
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
void ResourceOwnerNewParent(ResourceOwner owner, ResourceOwner newparent)
Definition: resowner.c:897
#define MAX_RESOWNER_LOCKS
Definition: resowner.c:105
void ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock)
Definition: resowner.c:1045
static void ReleaseAuxProcessResourcesCallback(int code, Datum arg)
Definition: resowner.c:1027
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:167
#define RESOWNER_HASH_INIT_SIZE
Definition: resowner.c:77
static void ResourceOwnerReleaseAll(ResourceOwner owner, ResourceReleasePhase phase, bool printLeakWarnings)
Definition: resowner.c:340
void UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
Definition: resowner.c:958
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:413
#define RESOWNER_HASH_MAX_ITEMS(capacity)
Definition: resowner.c:89
void ReleaseAuxProcessResources(bool isCommit)
Definition: resowner.c:1002
ResourceOwner ResourceOwnerGetParent(ResourceOwner owner)
Definition: resowner.c:888
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165
static uint32 hash_resource_elem(Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:214
struct ResourceElem ResourceElem
static ResourceReleaseCallbackItem * ResourceRelease_callbacks
Definition: resowner.c:187
static void ResourceOwnerAddToHash(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:237
void CreateAuxProcessResourceOwner(void)
Definition: resowner.c:982
void ResourceOwnerRelease(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:648
static int resource_priority_cmp(const void *a, const void *b)
Definition: resowner.c:261
void RegisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
Definition: resowner.c:944
static void ResourceOwnerReleaseInternal(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:668
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:554
void ResourceOwnerReleaseAllOfKind(ResourceOwner owner, const ResourceOwnerDesc *kind)
Definition: resowner.c:801
ResourceOwner AuxProcessResourceOwner
Definition: resowner.c:168
struct ResourceReleaseCallbackItem ResourceReleaseCallbackItem
void ResourceOwnerDelete(ResourceOwner owner)
Definition: resowner.c:854
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:166
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:514
#define RESOWNER_ARRAY_SIZE
Definition: resowner.c:71
static void ResourceOwnerSort(ResourceOwner owner)
Definition: resowner.c:284
StaticAssertDecl(RESOWNER_HASH_MAX_ITEMS(RESOWNER_HASH_INIT_SIZE) >=RESOWNER_ARRAY_SIZE, "initial hash size too small compared to array size")
void ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock)
Definition: resowner.c:1065
struct ResourceOwnerData ResourceOwnerData
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:442
ResourceReleasePhase
Definition: resowner.h:53
@ RESOURCE_RELEASE_LOCKS
Definition: resowner.h:55
@ RESOURCE_RELEASE_BEFORE_LOCKS
Definition: resowner.h:54
@ RESOURCE_RELEASE_AFTER_LOCKS
Definition: resowner.h:56
struct ResourceOwnerData * ResourceOwner
Definition: resowner.h:27
void(* ResourceReleaseCallback)(ResourceReleasePhase phase, bool isCommit, bool isTopLevel, void *arg)
Definition: resowner.h:126
void ProcReleaseLocks(bool isCommit)
Definition: proc.c:806
Datum item
Definition: resowner.c:64
const ResourceOwnerDesc * kind
Definition: resowner.c:65
ResourceOwner parent
Definition: resowner.c:112
const char * name
Definition: resowner.c:115
LOCALLOCK * locks[MAX_RESOWNER_LOCKS]
Definition: resowner.c:157
ResourceOwner nextchild
Definition: resowner.c:114
ResourceOwner firstchild
Definition: resowner.c:113
ResourceElem * hash
Definition: resowner.c:152
ResourceElem arr[RESOWNER_ARRAY_SIZE]
Definition: resowner.c:140
char *(* DebugPrint)(Datum res)
Definition: resowner.h:118
ResourceReleasePhase release_phase
Definition: resowner.h:96
void(* ReleaseResource)(Datum res)
Definition: resowner.h:108
ResourceReleasePriority release_priority
Definition: resowner.h:97
const char * name
Definition: resowner.h:93
struct ResourceReleaseCallbackItem * next
Definition: resowner.c:182
ResourceReleaseCallback callback
Definition: resowner.c:183
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46
static ItemArray items
Definition: test_tidstore.c:49
const char * name