Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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-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 */
235 (uint64) (uintptr_t) kind);
236}
237
238/*
239 * Adds 'value' of given 'kind' to the ResourceOwner's hash table
240 */
241static void
243{
244 uint32 mask = owner->capacity - 1;
245 uint32 idx;
246
247 Assert(kind != NULL);
248
249 /* Insert into first free slot at or after hash location. */
250 idx = hash_resource_elem(value, kind) & mask;
251 for (;;)
252 {
253 if (owner->hash[idx].kind == NULL)
254 break; /* found a free slot */
255 idx = (idx + 1) & mask;
256 }
257 owner->hash[idx].item = value;
258 owner->hash[idx].kind = kind;
259 owner->nhash++;
260}
261
262/*
263 * Comparison function to sort by release phase and priority
264 */
265static int
266resource_priority_cmp(const void *a, const void *b)
267{
268 const ResourceElem *ra = (const ResourceElem *) a;
269 const ResourceElem *rb = (const ResourceElem *) b;
270
271 /* Note: reverse order */
272 if (ra->kind->release_phase == rb->kind->release_phase)
274 else if (ra->kind->release_phase > rb->kind->release_phase)
275 return -1;
276 else
277 return 1;
278}
279
280/*
281 * Sort resources in reverse release priority.
282 *
283 * If the hash table is in use, all the elements from the fixed-size array are
284 * moved to the hash table, and then the hash table is sorted. If there is no
285 * hash table, then the fixed-size array is sorted directly. In either case,
286 * the result is one sorted array that contains all the resources.
287 */
288static void
290{
293
294 if (owner->nhash == 0)
295 {
296 items = owner->arr;
297 nitems = owner->narr;
298 }
299 else
300 {
301 /*
302 * Compact the hash table, so that all the elements are in the
303 * beginning of the 'hash' array, with no empty elements.
304 */
305 uint32 dst = 0;
306
307 for (int idx = 0; idx < owner->capacity; idx++)
308 {
309 if (owner->hash[idx].kind != NULL)
310 {
311 if (dst != idx)
312 owner->hash[dst] = owner->hash[idx];
313 dst++;
314 }
315 }
316
317 /*
318 * Move all entries from the fixed-size array to 'hash'.
319 *
320 * RESOWNER_HASH_MAX_ITEMS is defined so that there is always enough
321 * free space to move all the elements from the fixed-size array to
322 * the hash.
323 */
324 Assert(dst + owner->narr <= owner->capacity);
325 for (int idx = 0; idx < owner->narr; idx++)
326 {
327 owner->hash[dst] = owner->arr[idx];
328 dst++;
329 }
330 Assert(dst == owner->nhash + owner->narr);
331 owner->narr = 0;
332 owner->nhash = dst;
333
334 items = owner->hash;
335 nitems = owner->nhash;
336 }
337
339}
340
341/*
342 * Call the ReleaseResource callback on entries with given 'phase'.
343 */
344static void
346 bool printLeakWarnings)
347{
350
351 /*
352 * ResourceOwnerSort must've been called already. All the resources are
353 * either in the array or the hash.
354 */
355 Assert(owner->releasing);
356 Assert(owner->sorted);
357 if (owner->nhash == 0)
358 {
359 items = owner->arr;
360 nitems = owner->narr;
361 }
362 else
363 {
364 Assert(owner->narr == 0);
365 items = owner->hash;
366 nitems = owner->nhash;
367 }
368
369 /*
370 * The resources are sorted in reverse priority order. Release them
371 * starting from the end, until we hit the end of the phase that we are
372 * releasing now. We will continue from there when called again for the
373 * next phase.
374 */
375 while (nitems > 0)
376 {
377 uint32 idx = nitems - 1;
378 Datum value = items[idx].item;
379 const ResourceOwnerDesc *kind = items[idx].kind;
380
381 if (kind->release_phase > phase)
382 break;
383 Assert(kind->release_phase == phase);
384
385 if (printLeakWarnings)
386 {
387 char *res_str;
388
389 res_str = kind->DebugPrint ?
390 kind->DebugPrint(value)
391 : psprintf("%s %p", kind->name, DatumGetPointer(value));
392 elog(WARNING, "resource was not closed: %s", res_str);
393 pfree(res_str);
394 }
395 kind->ReleaseResource(value);
396 nitems--;
397 }
398 if (owner->nhash == 0)
399 owner->narr = nitems;
400 else
401 owner->nhash = nitems;
402}
403
404
405/*****************************************************************************
406 * EXPORTED ROUTINES *
407 *****************************************************************************/
408
409
410/*
411 * ResourceOwnerCreate
412 * Create an empty ResourceOwner.
413 *
414 * All ResourceOwner objects are kept in TopMemoryContext, since they should
415 * only be freed explicitly.
416 */
419{
420 ResourceOwner owner;
421
423 sizeof(struct ResourceOwnerData));
424 owner->name = name;
425
426 if (parent)
427 {
428 owner->parent = parent;
429 owner->nextchild = parent->firstchild;
430 parent->firstchild = owner;
431 }
432
433 dlist_init(&owner->aio_handles);
434
435 return owner;
436}
437
438/*
439 * Make sure there is room for at least one more resource in an array.
440 *
441 * This is separate from actually inserting a resource because if we run out
442 * of memory, it's critical to do so *before* acquiring the resource.
443 *
444 * NB: Make sure there are no unrelated ResourceOwnerRemember() calls between
445 * your ResourceOwnerEnlarge() call and the ResourceOwnerRemember() call that
446 * you reserved the space for!
447 */
448void
450{
451 /*
452 * Mustn't try to remember more resources after we have already started
453 * releasing
454 */
455 if (owner->releasing)
456 elog(ERROR, "ResourceOwnerEnlarge called after release started");
457
458 if (owner->narr < RESOWNER_ARRAY_SIZE)
459 return; /* no work needed */
460
461 /*
462 * Is there space in the hash? If not, enlarge it.
463 */
464 if (owner->narr + owner->nhash >= owner->grow_at)
465 {
466 uint32 i,
467 oldcap,
468 newcap;
469 ResourceElem *oldhash;
470 ResourceElem *newhash;
471
472 oldhash = owner->hash;
473 oldcap = owner->capacity;
474
475 /* Double the capacity (it must stay a power of 2!) */
476 newcap = (oldcap > 0) ? oldcap * 2 : RESOWNER_HASH_INIT_SIZE;
478 newcap * sizeof(ResourceElem));
479
480 /*
481 * We assume we can't fail below this point, so OK to scribble on the
482 * owner
483 */
484 owner->hash = newhash;
485 owner->capacity = newcap;
486 owner->grow_at = RESOWNER_HASH_MAX_ITEMS(newcap);
487 owner->nhash = 0;
488
489 if (oldhash != NULL)
490 {
491 /*
492 * Transfer any pre-existing entries into the new hash table; they
493 * don't necessarily go where they were before, so this simple
494 * logic is the best way.
495 */
496 for (i = 0; i < oldcap; i++)
497 {
498 if (oldhash[i].kind != NULL)
499 ResourceOwnerAddToHash(owner, oldhash[i].item, oldhash[i].kind);
500 }
501
502 /* And release old hash table. */
503 pfree(oldhash);
504 }
505 }
506
507 /* Move items from the array to the hash */
508 for (int i = 0; i < owner->narr; i++)
509 ResourceOwnerAddToHash(owner, owner->arr[i].item, owner->arr[i].kind);
510 owner->narr = 0;
511
512 Assert(owner->nhash <= owner->grow_at);
513}
514
515/*
516 * Remember that an object is owned by a ResourceOwner
517 *
518 * Caller must have previously done ResourceOwnerEnlarge()
519 */
520void
522{
523 uint32 idx;
524
525 /* sanity check the ResourceOwnerDesc */
526 Assert(kind->release_phase != 0);
527 Assert(kind->release_priority != 0);
528
529 /*
530 * Mustn't try to remember more resources after we have already started
531 * releasing. We already checked this in ResourceOwnerEnlarge.
532 */
533 Assert(!owner->releasing);
534 Assert(!owner->sorted);
535
536 if (owner->narr >= RESOWNER_ARRAY_SIZE)
537 {
538 /* forgot to call ResourceOwnerEnlarge? */
539 elog(ERROR, "ResourceOwnerRemember called but array was full");
540 }
541
542 /* Append to the array. */
543 idx = owner->narr;
544 owner->arr[idx].item = value;
545 owner->arr[idx].kind = kind;
546 owner->narr++;
547}
548
549/*
550 * Forget that an object is owned by a ResourceOwner
551 *
552 * Note: If same resource ID is associated with the ResourceOwner more than
553 * once, one instance is removed.
554 *
555 * Note: Forgetting a resource does not guarantee that there is room to
556 * remember a new resource. One exception is when you forget the most
557 * recently remembered resource; that does make room for a new remember call.
558 * Some code callers rely on that exception.
559 */
560void
562{
563 /*
564 * Mustn't call this after we have already started releasing resources.
565 * (Release callback functions are not allowed to release additional
566 * resources.)
567 */
568 if (owner->releasing)
569 elog(ERROR, "ResourceOwnerForget called for %s after release started", kind->name);
570 Assert(!owner->sorted);
571
572 /* Search through all items in the array first. */
573 for (int i = owner->narr - 1; i >= 0; i--)
574 {
575 if (owner->arr[i].item == value &&
576 owner->arr[i].kind == kind)
577 {
578 owner->arr[i] = owner->arr[owner->narr - 1];
579 owner->narr--;
580
581#ifdef RESOWNER_STATS
582 narray_lookups++;
583#endif
584 return;
585 }
586 }
587
588 /* Search hash */
589 if (owner->nhash > 0)
590 {
591 uint32 mask = owner->capacity - 1;
592 uint32 idx;
593
594 idx = hash_resource_elem(value, kind) & mask;
595 for (uint32 i = 0; i < owner->capacity; i++)
596 {
597 if (owner->hash[idx].item == value &&
598 owner->hash[idx].kind == kind)
599 {
600 owner->hash[idx].item = (Datum) 0;
601 owner->hash[idx].kind = NULL;
602 owner->nhash--;
603
604#ifdef RESOWNER_STATS
605 nhash_lookups++;
606#endif
607 return;
608 }
609 idx = (idx + 1) & mask;
610 }
611 }
612
613 /*
614 * Use %p to print the reference, since most objects tracked by a resource
615 * owner are pointers. It's a bit misleading if it's not a pointer, but
616 * this is a programmer error, anyway.
617 */
618 elog(ERROR, "%s %p is not owned by resource owner %s",
619 kind->name, DatumGetPointer(value), owner->name);
620}
621
622/*
623 * ResourceOwnerRelease
624 * Release all resources owned by a ResourceOwner and its descendants,
625 * but don't delete the owner objects themselves.
626 *
627 * Note that this executes just one phase of release, and so typically
628 * must be called three times. We do it this way because (a) we want to
629 * do all the recursion separately for each phase, thereby preserving
630 * the needed order of operations; and (b) xact.c may have other operations
631 * to do between the phases.
632 *
633 * phase: release phase to execute
634 * isCommit: true for successful completion of a query or transaction,
635 * false for unsuccessful
636 * isTopLevel: true if completing a main transaction, else false
637 *
638 * isCommit is passed because some modules may expect that their resources
639 * were all released already if the transaction or portal finished normally.
640 * If so it is reasonable to give a warning (NOT an error) should any
641 * unreleased resources be present. When isCommit is false, such warnings
642 * are generally inappropriate.
643 *
644 * isTopLevel is passed when we are releasing TopTransactionResourceOwner
645 * at completion of a main transaction. This generally means that *all*
646 * resources will be released, and so we can optimize things a bit.
647 *
648 * NOTE: After starting the release process, by calling this function, no new
649 * resources can be remembered in the resource owner. You also cannot call
650 * ResourceOwnerForget on any previously remembered resources to release
651 * resources "in retail" after that, you must let the bulk release take care
652 * of them.
653 */
654void
657 bool isCommit,
658 bool isTopLevel)
659{
660 /* There's not currently any setup needed before recursing */
661 ResourceOwnerReleaseInternal(owner, phase, isCommit, isTopLevel);
662
663#ifdef RESOWNER_STATS
664 if (isTopLevel)
665 {
666 elog(LOG, "RESOWNER STATS: lookups: array %d, hash %d",
667 narray_lookups, nhash_lookups);
668 narray_lookups = 0;
669 nhash_lookups = 0;
670 }
671#endif
672}
673
674static void
677 bool isCommit,
678 bool isTopLevel)
679{
680 ResourceOwner child;
681 ResourceOwner save;
684
685 /* Recurse to handle descendants */
686 for (child = owner->firstchild; child != NULL; child = child->nextchild)
687 ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel);
688
689 /*
690 * To release the resources in the right order, sort them by phase and
691 * priority.
692 *
693 * The ReleaseResource callback functions are not allowed to remember or
694 * forget any other resources after this. Otherwise we lose track of where
695 * we are in processing the hash/array.
696 */
697 if (!owner->releasing)
698 {
700 Assert(!owner->sorted);
701 owner->releasing = true;
702 }
703 else
704 {
705 /*
706 * Phase is normally > RESOURCE_RELEASE_BEFORE_LOCKS, if this is not
707 * the first call to ResourceOwnerRelease. But if an error happens
708 * between the release phases, we might get called again for the same
709 * ResourceOwner from AbortTransaction.
710 */
711 }
712 if (!owner->sorted)
713 {
714 ResourceOwnerSort(owner);
715 owner->sorted = true;
716 }
717
718 /*
719 * Make CurrentResourceOwner point to me, so that the release callback
720 * functions know which resource owner is been released.
721 */
723 CurrentResourceOwner = owner;
724
726 {
727 /*
728 * Release all resources that need to be released before the locks.
729 *
730 * During a commit, there shouldn't be any remaining resources ---
731 * that would indicate failure to clean up the executor correctly ---
732 * so issue warnings. In the abort case, just clean up quietly.
733 */
734 ResourceOwnerReleaseAll(owner, phase, isCommit);
735
736 while (!dlist_is_empty(&owner->aio_handles))
737 {
738 dlist_node *node = dlist_head_node(&owner->aio_handles);
739
740 pgaio_io_release_resowner(node, !isCommit);
741 }
742 }
743 else if (phase == RESOURCE_RELEASE_LOCKS)
744 {
745 if (isTopLevel)
746 {
747 /*
748 * For a top-level xact we are going to release all locks (or at
749 * least all non-session locks), so just do a single lmgr call at
750 * the top of the recursion.
751 */
752 if (owner == TopTransactionResourceOwner)
753 {
754 ProcReleaseLocks(isCommit);
755 ReleasePredicateLocks(isCommit, false);
756 }
757 }
758 else
759 {
760 /*
761 * Release locks retail. Note that if we are committing a
762 * subtransaction, we do NOT release its locks yet, but transfer
763 * them to the parent.
764 */
765 LOCALLOCK **locks;
766 int nlocks;
767
768 Assert(owner->parent != NULL);
769
770 /*
771 * Pass the list of locks owned by this resource owner to the lock
772 * manager, unless it has overflowed.
773 */
774 if (owner->nlocks > MAX_RESOWNER_LOCKS)
775 {
776 locks = NULL;
777 nlocks = 0;
778 }
779 else
780 {
781 locks = owner->locks;
782 nlocks = owner->nlocks;
783 }
784
785 if (isCommit)
786 LockReassignCurrentOwner(locks, nlocks);
787 else
788 LockReleaseCurrentOwner(locks, nlocks);
789 }
790 }
791 else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
792 {
793 /*
794 * Release all resources that need to be released after the locks.
795 */
796 ResourceOwnerReleaseAll(owner, phase, isCommit);
797 }
798
799 /* Let add-on modules get a chance too */
800 for (item = ResourceRelease_callbacks; item; item = next)
801 {
802 /* allow callbacks to unregister themselves when called */
803 next = item->next;
804 item->callback(phase, isCommit, isTopLevel, item->arg);
805 }
806
808}
809
810/*
811 * ResourceOwnerReleaseAllOfKind
812 * Release all resources of a certain type held by this owner.
813 */
814void
816{
817 /* Mustn't call this after we have already started releasing resources. */
818 if (owner->releasing)
819 elog(ERROR, "ResourceOwnerForget called for %s after release started", kind->name);
820 Assert(!owner->sorted);
821
822 /*
823 * Temporarily set 'releasing', to prevent calls to ResourceOwnerRemember
824 * while we're scanning the owner. Enlarging the hash would cause us to
825 * lose track of the point we're scanning.
826 */
827 owner->releasing = true;
828
829 /* Array first */
830 for (int i = 0; i < owner->narr; i++)
831 {
832 if (owner->arr[i].kind == kind)
833 {
834 Datum value = owner->arr[i].item;
835
836 owner->arr[i] = owner->arr[owner->narr - 1];
837 owner->narr--;
838 i--;
839
840 kind->ReleaseResource(value);
841 }
842 }
843
844 /* Then hash */
845 for (int i = 0; i < owner->capacity; i++)
846 {
847 if (owner->hash[i].kind == kind)
848 {
849 Datum value = owner->hash[i].item;
850
851 owner->hash[i].item = (Datum) 0;
852 owner->hash[i].kind = NULL;
853 owner->nhash--;
854
855 kind->ReleaseResource(value);
856 }
857 }
858 owner->releasing = false;
859}
860
861/*
862 * ResourceOwnerDelete
863 * Delete an owner object and its descendants.
864 *
865 * The caller must have already released all resources in the object tree.
866 */
867void
869{
870 /* We had better not be deleting CurrentResourceOwner ... */
872
873 /* And it better not own any resources, either */
874 Assert(owner->narr == 0);
875 Assert(owner->nhash == 0);
876 Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1);
877
878 /*
879 * Delete children. The recursive call will delink the child from me, so
880 * just iterate as long as there is a child.
881 */
882 while (owner->firstchild != NULL)
884
885 /*
886 * We delink the owner from its parent before deleting it, so that if
887 * there's an error we won't have deleted/busted owners still attached to
888 * the owner tree. Better a leak than a crash.
889 */
890 ResourceOwnerNewParent(owner, NULL);
891
892 /* And free the object. */
893 if (owner->hash)
894 pfree(owner->hash);
895 pfree(owner);
896}
897
898/*
899 * Fetch parent of a ResourceOwner (returns NULL if top-level owner)
900 */
903{
904 return owner->parent;
905}
906
907/*
908 * Reassign a ResourceOwner to have a new parent
909 */
910void
912 ResourceOwner newparent)
913{
914 ResourceOwner oldparent = owner->parent;
915
916 if (oldparent)
917 {
918 if (owner == oldparent->firstchild)
919 oldparent->firstchild = owner->nextchild;
920 else
921 {
922 ResourceOwner child;
923
924 for (child = oldparent->firstchild; child; child = child->nextchild)
925 {
926 if (owner == child->nextchild)
927 {
928 child->nextchild = owner->nextchild;
929 break;
930 }
931 }
932 }
933 }
934
935 if (newparent)
936 {
937 Assert(owner != newparent);
938 owner->parent = newparent;
939 owner->nextchild = newparent->firstchild;
940 newparent->firstchild = owner;
941 }
942 else
943 {
944 owner->parent = NULL;
945 owner->nextchild = NULL;
946 }
947}
948
949/*
950 * Register or deregister callback functions for resource cleanup
951 *
952 * These functions can be used by dynamically loaded modules. These used
953 * to be the only way for an extension to register custom resource types
954 * with a resource owner, but nowadays it is easier to define a new
955 * ResourceOwnerDesc with custom callbacks.
956 */
957void
959{
961
965 item->callback = callback;
966 item->arg = arg;
969}
970
971void
973{
976
977 prev = NULL;
978 for (item = ResourceRelease_callbacks; item; prev = item, item = item->next)
979 {
980 if (item->callback == callback && item->arg == arg)
981 {
982 if (prev)
983 prev->next = item->next;
984 else
986 pfree(item);
987 break;
988 }
989 }
990}
991
992/*
993 * Establish an AuxProcessResourceOwner for the current process.
994 */
995void
997{
1000 AuxProcessResourceOwner = ResourceOwnerCreate(NULL, "AuxiliaryProcess");
1002
1003 /*
1004 * Register a shmem-exit callback for cleanup of aux-process resource
1005 * owner. (This needs to run after, e.g., ShutdownXLOG.)
1006 */
1008}
1009
1010/*
1011 * Convenience routine to release all resources tracked in
1012 * AuxProcessResourceOwner (but that resowner is not destroyed here).
1013 * Warn about leaked resources if isCommit is true.
1014 */
1015void
1017{
1018 /*
1019 * At this writing, the only thing that could actually get released is
1020 * buffer pins; but we may as well do the full release protocol.
1021 */
1024 isCommit, true);
1027 isCommit, true);
1030 isCommit, true);
1031 /* allow it to be reused */
1034}
1035
1036/*
1037 * Shmem-exit callback for the same.
1038 * Warn about leaked resources if process exit code is zero (ie normal).
1039 */
1040static void
1042{
1043 bool isCommit = (code == 0);
1044
1046}
1047
1048/*
1049 * Remember that a Local Lock is owned by a ResourceOwner
1050 *
1051 * This is different from the generic ResourceOwnerRemember in that the list of
1052 * locks is only a lossy cache. It can hold up to MAX_RESOWNER_LOCKS entries,
1053 * and when it overflows, we stop tracking locks. The point of only remembering
1054 * only up to MAX_RESOWNER_LOCKS entries is that if a lot of locks are held,
1055 * ResourceOwnerForgetLock doesn't need to scan through a large array to find
1056 * the entry.
1057 */
1058void
1060{
1061 Assert(locallock != NULL);
1062
1063 if (owner->nlocks > MAX_RESOWNER_LOCKS)
1064 return; /* we have already overflowed */
1065
1066 if (owner->nlocks < MAX_RESOWNER_LOCKS)
1067 owner->locks[owner->nlocks] = locallock;
1068 else
1069 {
1070 /* overflowed */
1071 }
1072 owner->nlocks++;
1073}
1074
1075/*
1076 * Forget that a Local Lock is owned by a ResourceOwner
1077 */
1078void
1080{
1081 int i;
1082
1083 if (owner->nlocks > MAX_RESOWNER_LOCKS)
1084 return; /* we have overflowed */
1085
1086 Assert(owner->nlocks > 0);
1087 for (i = owner->nlocks - 1; i >= 0; i--)
1088 {
1089 if (locallock == owner->locks[i])
1090 {
1091 owner->locks[i] = owner->locks[owner->nlocks - 1];
1092 owner->nlocks--;
1093 return;
1094 }
1095 }
1096 elog(ERROR, "lock reference %p is not owned by resource owner %s",
1097 locallock, owner->name);
1098}
1099
1100void
1102{
1103 dlist_push_tail(&owner->aio_handles, ioh_node);
1104}
1105
1106void
1108{
1109 dlist_delete_from(&owner->aio_handles, ioh_node);
1110}
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:263
static int32 next
Definition: blutils.c:224
uint8_t uint8
Definition: c.h:537
uint64_t uint64
Definition: c.h:540
uint32_t uint32
Definition: c.h:539
#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
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 @166 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:2706
void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks)
Definition: lock.c:2611
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1229
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1263
void pfree(void *pointer)
Definition: mcxt.c:1594
MemoryContext TopMemoryContext
Definition: mcxt.c:166
void * arg
#define qsort(a, b, c, d)
Definition: port.h:479
uint64_t Datum
Definition: postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:322
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:911
#define MAX_RESOWNER_LOCKS
Definition: resowner.c:107
void ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock)
Definition: resowner.c:1059
static void ReleaseAuxProcessResourcesCallback(int code, Datum arg)
Definition: resowner.c:1041
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:345
void UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
Definition: resowner.c:972
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:418
#define RESOWNER_HASH_MAX_ITEMS(capacity)
Definition: resowner.c:91
void ReleaseAuxProcessResources(bool isCommit)
Definition: resowner.c:1016
ResourceOwner ResourceOwnerGetParent(ResourceOwner owner)
Definition: resowner.c:902
ResourceOwner CurrentResourceOwner
Definition: resowner.c:173
void ResourceOwnerRememberAioHandle(ResourceOwner owner, struct dlist_node *ioh_node)
Definition: resowner.c:1101
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:242
void CreateAuxProcessResourceOwner(void)
Definition: resowner.c:996
void ResourceOwnerRelease(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:655
static int resource_priority_cmp(const void *a, const void *b)
Definition: resowner.c:266
void RegisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
Definition: resowner.c:958
static void ResourceOwnerReleaseInternal(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:675
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:561
void ResourceOwnerReleaseAllOfKind(ResourceOwner owner, const ResourceOwnerDesc *kind)
Definition: resowner.c:815
ResourceOwner AuxProcessResourceOwner
Definition: resowner.c:176
struct ResourceReleaseCallbackItem ResourceReleaseCallbackItem
void ResourceOwnerDelete(ResourceOwner owner)
Definition: resowner.c:868
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:174
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:521
#define RESOWNER_ARRAY_SIZE
Definition: resowner.c:73
static void ResourceOwnerSort(ResourceOwner owner)
Definition: resowner.c:289
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:1079
void ResourceOwnerForgetAioHandle(ResourceOwner owner, struct dlist_node *ioh_node)
Definition: resowner.c:1107
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:449
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:891
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