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