PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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 */
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)
273 return pg_cmp_u32(rb->kind->release_priority, ra->kind->release_priority);
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
347{
350 bool using_arr;
351
352 /*
353 * ResourceOwnerSort must've been called already. All the resources are
354 * either in the array or the hash.
355 */
356 Assert(owner->releasing);
357 Assert(owner->sorted);
358 if (owner->nhash == 0)
359 {
360 items = owner->arr;
361 nitems = owner->narr;
362 using_arr = true;
363 }
364 else
365 {
366 Assert(owner->narr == 0);
367 items = owner->hash;
368 nitems = owner->nhash;
369 using_arr = false;
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
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
399 /*
400 * Update stored count to forget the item before calling its
401 * ReleaseResource method. This avoids double-free crashes in case an
402 * error gets thrown within ReleaseResource.
403 */
404 nitems--;
405 if (using_arr)
406 owner->narr = nitems;
407 else
408 owner->nhash = nitems;
409
410 kind->ReleaseResource(value);
411 }
412}
413
414
415/*****************************************************************************
416 * EXPORTED ROUTINES *
417 *****************************************************************************/
418
419
420/*
421 * ResourceOwnerCreate
422 * Create an empty ResourceOwner.
423 *
424 * All ResourceOwner objects are kept in TopMemoryContext, since they should
425 * only be freed explicitly.
426 */
429{
430 ResourceOwner owner;
431
433 sizeof(struct ResourceOwnerData));
434 owner->name = name;
435
436 if (parent)
437 {
438 owner->parent = parent;
439 owner->nextchild = parent->firstchild;
440 parent->firstchild = owner;
441 }
442
443 dlist_init(&owner->aio_handles);
444
445 return owner;
446}
447
448/*
449 * Make sure there is room for at least one more resource in an array.
450 *
451 * This is separate from actually inserting a resource because if we run out
452 * of memory, it's critical to do so *before* acquiring the resource.
453 *
454 * NB: Make sure there are no unrelated ResourceOwnerRemember() calls between
455 * your ResourceOwnerEnlarge() call and the ResourceOwnerRemember() call that
456 * you reserved the space for!
457 */
458void
460{
461 /*
462 * Mustn't try to remember more resources after we have already started
463 * releasing
464 */
465 if (owner->releasing)
466 elog(ERROR, "ResourceOwnerEnlarge called after release started");
467
468 if (owner->narr < RESOWNER_ARRAY_SIZE)
469 return; /* no work needed */
470
471 /*
472 * Is there space in the hash? If not, enlarge it.
473 */
474 if (owner->narr + owner->nhash >= owner->grow_at)
475 {
476 uint32 i,
477 oldcap,
478 newcap;
481
482 oldhash = owner->hash;
483 oldcap = owner->capacity;
484
485 /* Double the capacity (it must stay a power of 2!) */
488 newcap * sizeof(ResourceElem));
489
490 /*
491 * We assume we can't fail below this point, so OK to scribble on the
492 * owner
493 */
494 owner->hash = newhash;
495 owner->capacity = newcap;
497 owner->nhash = 0;
498
499 if (oldhash != NULL)
500 {
501 /*
502 * Transfer any pre-existing entries into the new hash table; they
503 * don't necessarily go where they were before, so this simple
504 * logic is the best way.
505 */
506 for (i = 0; i < oldcap; i++)
507 {
508 if (oldhash[i].kind != NULL)
509 ResourceOwnerAddToHash(owner, oldhash[i].item, oldhash[i].kind);
510 }
511
512 /* And release old hash table. */
513 pfree(oldhash);
514 }
515 }
516
517 /* Move items from the array to the hash */
518 for (int i = 0; i < owner->narr; i++)
519 ResourceOwnerAddToHash(owner, owner->arr[i].item, owner->arr[i].kind);
520 owner->narr = 0;
521
522 Assert(owner->nhash <= owner->grow_at);
523}
524
525/*
526 * Remember that an object is owned by a ResourceOwner
527 *
528 * Caller must have previously done ResourceOwnerEnlarge()
529 */
530void
532{
533 uint32 idx;
534
535 /* sanity check the ResourceOwnerDesc */
536 Assert(kind->release_phase != 0);
537 Assert(kind->release_priority != 0);
538
539 /*
540 * Mustn't try to remember more resources after we have already started
541 * releasing. We already checked this in ResourceOwnerEnlarge.
542 */
543 Assert(!owner->releasing);
544 Assert(!owner->sorted);
545
546 if (owner->narr >= RESOWNER_ARRAY_SIZE)
547 {
548 /* forgot to call ResourceOwnerEnlarge? */
549 elog(ERROR, "ResourceOwnerRemember called but array was full");
550 }
551
552 /* Append to the array. */
553 idx = owner->narr;
554 owner->arr[idx].item = value;
555 owner->arr[idx].kind = kind;
556 owner->narr++;
557}
558
559/*
560 * Forget that an object is owned by a ResourceOwner
561 *
562 * Note: If same resource ID is associated with the ResourceOwner more than
563 * once, one instance is removed.
564 *
565 * Note: Forgetting a resource does not guarantee that there is room to
566 * remember a new resource. One exception is when you forget the most
567 * recently remembered resource; that does make room for a new remember call.
568 * Some code callers rely on that exception.
569 */
570void
572{
573 /*
574 * Mustn't call this after we have already started releasing resources.
575 * (Release callback functions are not allowed to release additional
576 * resources.)
577 */
578 if (owner->releasing)
579 elog(ERROR, "ResourceOwnerForget called for %s after release started", kind->name);
580 Assert(!owner->sorted);
581
582 /* Search through all items in the array first. */
583 for (int i = owner->narr - 1; i >= 0; i--)
584 {
585 if (owner->arr[i].item == value &&
586 owner->arr[i].kind == kind)
587 {
588 owner->arr[i] = owner->arr[owner->narr - 1];
589 owner->narr--;
590
591#ifdef RESOWNER_STATS
593#endif
594 return;
595 }
596 }
597
598 /* Search hash */
599 if (owner->nhash > 0)
600 {
601 uint32 mask = owner->capacity - 1;
602 uint32 idx;
603
604 idx = hash_resource_elem(value, kind) & mask;
605 for (uint32 i = 0; i < owner->capacity; i++)
606 {
607 if (owner->hash[idx].item == value &&
608 owner->hash[idx].kind == kind)
609 {
610 owner->hash[idx].item = (Datum) 0;
611 owner->hash[idx].kind = NULL;
612 owner->nhash--;
613
614#ifdef RESOWNER_STATS
616#endif
617 return;
618 }
619 idx = (idx + 1) & mask;
620 }
621 }
622
623 /*
624 * Use %p to print the reference, since most objects tracked by a resource
625 * owner are pointers. It's a bit misleading if it's not a pointer, but
626 * this is a programmer error, anyway.
627 */
628 elog(ERROR, "%s %p is not owned by resource owner %s",
629 kind->name, DatumGetPointer(value), owner->name);
630}
631
632/*
633 * ResourceOwnerRelease
634 * Release all resources owned by a ResourceOwner and its descendants,
635 * but don't delete the owner objects themselves.
636 *
637 * Note that this executes just one phase of release, and so typically
638 * must be called three times. We do it this way because (a) we want to
639 * do all the recursion separately for each phase, thereby preserving
640 * the needed order of operations; and (b) xact.c may have other operations
641 * to do between the phases.
642 *
643 * phase: release phase to execute
644 * isCommit: true for successful completion of a query or transaction,
645 * false for unsuccessful
646 * isTopLevel: true if completing a main transaction, else false
647 *
648 * isCommit is passed because some modules may expect that their resources
649 * were all released already if the transaction or portal finished normally.
650 * If so it is reasonable to give a warning (NOT an error) should any
651 * unreleased resources be present. When isCommit is false, such warnings
652 * are generally inappropriate.
653 *
654 * isTopLevel is passed when we are releasing TopTransactionResourceOwner
655 * at completion of a main transaction. This generally means that *all*
656 * resources will be released, and so we can optimize things a bit.
657 *
658 * NOTE: After starting the release process, by calling this function, no new
659 * resources can be remembered in the resource owner. You also cannot call
660 * ResourceOwnerForget on any previously remembered resources to release
661 * resources "in retail" after that, you must let the bulk release take care
662 * of them.
663 */
664void
667 bool isCommit,
668 bool isTopLevel)
669{
670 /* There's not currently any setup needed before recursing */
672
673#ifdef RESOWNER_STATS
674 if (isTopLevel)
675 {
676 elog(LOG, "RESOWNER STATS: lookups: array %d, hash %d",
678 narray_lookups = 0;
679 nhash_lookups = 0;
680 }
681#endif
682}
683
684static void
687 bool isCommit,
688 bool isTopLevel)
689{
690 ResourceOwner child;
694
695 /* Recurse to handle descendants */
696 for (child = owner->firstchild; child != NULL; child = child->nextchild)
698
699 /*
700 * To release the resources in the right order, sort them by phase and
701 * priority.
702 *
703 * The ReleaseResource callback functions are not allowed to remember or
704 * forget any other resources after this. Otherwise we lose track of where
705 * we are in processing the hash/array.
706 */
707 if (!owner->releasing)
708 {
710 Assert(!owner->sorted);
711 owner->releasing = true;
712 }
713 else
714 {
715 /*
716 * Phase is normally > RESOURCE_RELEASE_BEFORE_LOCKS, if this is not
717 * the first call to ResourceOwnerRelease. But if an error happens
718 * between the release phases, we might get called again for the same
719 * ResourceOwner from AbortTransaction.
720 */
721 }
722 if (!owner->sorted)
723 {
724 ResourceOwnerSort(owner);
725 owner->sorted = true;
726 }
727
728 /*
729 * Make CurrentResourceOwner point to me, so that the release callback
730 * functions know which resource owner is been released.
731 */
733 CurrentResourceOwner = owner;
734
736 {
737 /*
738 * Release all resources that need to be released before the locks.
739 *
740 * During a commit, there shouldn't be any remaining resources ---
741 * that would indicate failure to clean up the executor correctly ---
742 * so issue warnings. In the abort case, just clean up quietly.
743 */
744 ResourceOwnerReleaseAll(owner, phase, isCommit);
745
746 while (!dlist_is_empty(&owner->aio_handles))
747 {
748 dlist_node *node = dlist_head_node(&owner->aio_handles);
749
751 }
752 }
753 else if (phase == RESOURCE_RELEASE_LOCKS)
754 {
755 if (isTopLevel)
756 {
757 /*
758 * For a top-level xact we are going to release all locks (or at
759 * least all non-session locks), so just do a single lmgr call at
760 * the top of the recursion.
761 */
762 if (owner == TopTransactionResourceOwner)
763 {
766 }
767 }
768 else
769 {
770 /*
771 * Release locks retail. Note that if we are committing a
772 * subtransaction, we do NOT release its locks yet, but transfer
773 * them to the parent.
774 */
775 LOCALLOCK **locks;
776 int nlocks;
777
778 Assert(owner->parent != NULL);
779
780 /*
781 * Pass the list of locks owned by this resource owner to the lock
782 * manager, unless it has overflowed.
783 */
784 if (owner->nlocks > MAX_RESOWNER_LOCKS)
785 {
786 locks = NULL;
787 nlocks = 0;
788 }
789 else
790 {
791 locks = owner->locks;
792 nlocks = owner->nlocks;
793 }
794
795 if (isCommit)
796 LockReassignCurrentOwner(locks, nlocks);
797 else
798 LockReleaseCurrentOwner(locks, nlocks);
799 }
800 }
801 else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
802 {
803 /*
804 * Release all resources that need to be released after the locks.
805 */
806 ResourceOwnerReleaseAll(owner, phase, isCommit);
807 }
808
809 /* Let add-on modules get a chance too */
810 for (item = ResourceRelease_callbacks; item; item = next)
811 {
812 /* allow callbacks to unregister themselves when called */
813 next = item->next;
814 item->callback(phase, isCommit, isTopLevel, item->arg);
815 }
816
818}
819
820/*
821 * ResourceOwnerReleaseAllOfKind
822 * Release all resources of a certain type held by this owner.
823 */
824void
826{
827 /* Mustn't call this after we have already started releasing resources. */
828 if (owner->releasing)
829 elog(ERROR, "ResourceOwnerForget called for %s after release started", kind->name);
830 Assert(!owner->sorted);
831
832 /*
833 * Temporarily set 'releasing', to prevent calls to ResourceOwnerRemember
834 * while we're scanning the owner. Enlarging the hash would cause us to
835 * lose track of the point we're scanning.
836 */
837 owner->releasing = true;
838
839 /* Array first */
840 for (int i = 0; i < owner->narr; i++)
841 {
842 if (owner->arr[i].kind == kind)
843 {
844 Datum value = owner->arr[i].item;
845
846 owner->arr[i] = owner->arr[owner->narr - 1];
847 owner->narr--;
848 i--;
849
850 kind->ReleaseResource(value);
851 }
852 }
853
854 /* Then hash */
855 for (int i = 0; i < owner->capacity; i++)
856 {
857 if (owner->hash[i].kind == kind)
858 {
859 Datum value = owner->hash[i].item;
860
861 owner->hash[i].item = (Datum) 0;
862 owner->hash[i].kind = NULL;
863 owner->nhash--;
864
865 kind->ReleaseResource(value);
866 }
867 }
868 owner->releasing = false;
869}
870
871/*
872 * ResourceOwnerDelete
873 * Delete an owner object and its descendants.
874 *
875 * The caller must have already released all resources in the object tree.
876 */
877void
879{
880 /* We had better not be deleting CurrentResourceOwner ... */
882
883 /* And it better not own any resources, either */
884 Assert(owner->narr == 0);
885 Assert(owner->nhash == 0);
886 Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1);
887
888 /*
889 * Delete children. The recursive call will delink the child from me, so
890 * just iterate as long as there is a child.
891 */
892 while (owner->firstchild != NULL)
894
895 /*
896 * We delink the owner from its parent before deleting it, so that if
897 * there's an error we won't have deleted/busted owners still attached to
898 * the owner tree. Better a leak than a crash.
899 */
901
902 /* And free the object. */
903 if (owner->hash)
904 pfree(owner->hash);
905 pfree(owner);
906}
907
908/*
909 * Fetch parent of a ResourceOwner (returns NULL if top-level owner)
910 */
913{
914 return owner->parent;
915}
916
917/*
918 * Reassign a ResourceOwner to have a new parent
919 */
920void
923{
925
926 if (oldparent)
927 {
928 if (owner == oldparent->firstchild)
930 else
931 {
932 ResourceOwner child;
933
934 for (child = oldparent->firstchild; child; child = child->nextchild)
935 {
936 if (owner == child->nextchild)
937 {
938 child->nextchild = owner->nextchild;
939 break;
940 }
941 }
942 }
943 }
944
945 if (newparent)
946 {
947 Assert(owner != newparent);
948 owner->parent = newparent;
950 newparent->firstchild = owner;
951 }
952 else
953 {
954 owner->parent = NULL;
955 owner->nextchild = NULL;
956 }
957}
958
959/*
960 * Register or deregister callback functions for resource cleanup
961 *
962 * These functions can be used by dynamically loaded modules. These used
963 * to be the only way for an extension to register custom resource types
964 * with a resource owner, but nowadays it is easier to define a new
965 * ResourceOwnerDesc with custom callbacks.
966 */
967void
980
981void
983{
986
987 prev = NULL;
988 for (item = ResourceRelease_callbacks; item; prev = item, item = item->next)
989 {
990 if (item->callback == callback && item->arg == arg)
991 {
992 if (prev)
993 prev->next = item->next;
994 else
996 pfree(item);
997 break;
998 }
999 }
1000}
1001
1002/*
1003 * Establish an AuxProcessResourceOwner for the current process.
1004 */
1005void
1007{
1010 AuxProcessResourceOwner = ResourceOwnerCreate(NULL, "AuxiliaryProcess");
1012
1013 /*
1014 * Register a shmem-exit callback for cleanup of aux-process resource
1015 * owner. (This needs to run after, e.g., ShutdownXLOG.)
1016 */
1018}
1019
1020/*
1021 * Convenience routine to release all resources tracked in
1022 * AuxProcessResourceOwner (but that resowner is not destroyed here).
1023 * Warn about leaked resources if isCommit is true.
1024 */
1025void
1027{
1028 /*
1029 * At this writing, the only thing that could actually get released is
1030 * buffer pins; but we may as well do the full release protocol.
1031 */
1034 isCommit, true);
1037 isCommit, true);
1040 isCommit, true);
1041 /* allow it to be reused */
1044}
1045
1046/*
1047 * Shmem-exit callback for the same.
1048 * Warn about leaked resources if process exit code is zero (ie normal).
1049 */
1050static void
1052{
1053 bool isCommit = (code == 0);
1054
1056}
1057
1058/*
1059 * Remember that a Local Lock is owned by a ResourceOwner
1060 *
1061 * This is different from the generic ResourceOwnerRemember in that the list of
1062 * locks is only a lossy cache. It can hold up to MAX_RESOWNER_LOCKS entries,
1063 * and when it overflows, we stop tracking locks. The point of only remembering
1064 * only up to MAX_RESOWNER_LOCKS entries is that if a lot of locks are held,
1065 * ResourceOwnerForgetLock doesn't need to scan through a large array to find
1066 * the entry.
1067 */
1068void
1070{
1071 Assert(locallock != NULL);
1072
1073 if (owner->nlocks > MAX_RESOWNER_LOCKS)
1074 return; /* we have already overflowed */
1075
1076 if (owner->nlocks < MAX_RESOWNER_LOCKS)
1077 owner->locks[owner->nlocks] = locallock;
1078 else
1079 {
1080 /* overflowed */
1081 }
1082 owner->nlocks++;
1083}
1084
1085/*
1086 * Forget that a Local Lock is owned by a ResourceOwner
1087 */
1088void
1090{
1091 int i;
1092
1093 if (owner->nlocks > MAX_RESOWNER_LOCKS)
1094 return; /* we have overflowed */
1095
1096 Assert(owner->nlocks > 0);
1097 for (i = owner->nlocks - 1; i >= 0; i--)
1098 {
1099 if (locallock == owner->locks[i])
1100 {
1101 owner->locks[i] = owner->locks[owner->nlocks - 1];
1102 owner->nlocks--;
1103 return;
1104 }
1105 }
1106 elog(ERROR, "lock reference %p is not owned by resource owner %s",
1107 locallock, owner->name);
1108}
1109
1110void
1115
1116void
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:263
void pgaio_io_release_resowner(dlist_node *ioh_node, bool on_error)
Definition aio.c:266
static int32 next
Definition blutils.c:225
uint8_t uint8
Definition c.h:622
#define Assert(condition)
Definition c.h:943
uint64_t uint64
Definition c.h:625
uint32_t uint32
Definition c.h:624
#define StaticAssertDecl(condition, errmessage)
Definition c.h:1008
Datum arg
Definition elog.c:1323
#define LOG
Definition elog.h:32
#define WARNING
Definition elog.h:37
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
static uint64 hash_combine64(uint64 a, uint64 b)
Definition hashfn.h:80
static uint64 murmurhash64(uint64 data)
Definition hashfn.h:106
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 @177 value
static int pg_cmp_u32(uint32 a, uint32 b)
Definition int.h:719
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition ipc.c:372
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:2714
void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks)
Definition lock.c:2619
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1235
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1269
void pfree(void *pointer)
Definition mcxt.c:1619
MemoryContext TopMemoryContext
Definition mcxt.c:167
#define qsort(a, b, c, d)
Definition port.h:496
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition predicate.c:3241
static int fb(int x)
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
void ResourceOwnerNewParent(ResourceOwner owner, ResourceOwner newparent)
Definition resowner.c:921
#define MAX_RESOWNER_LOCKS
Definition resowner.c:107
void ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock)
Definition resowner.c:1069
static void ReleaseAuxProcessResourcesCallback(int code, Datum arg)
Definition resowner.c:1051
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:982
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition resowner.c:428
#define RESOWNER_HASH_MAX_ITEMS(capacity)
Definition resowner.c:91
void ReleaseAuxProcessResources(bool isCommit)
Definition resowner.c:1026
ResourceOwner ResourceOwnerGetParent(ResourceOwner owner)
Definition resowner.c:912
ResourceOwner CurrentResourceOwner
Definition resowner.c:173
void ResourceOwnerRememberAioHandle(ResourceOwner owner, struct dlist_node *ioh_node)
Definition resowner.c:1111
static uint32 hash_resource_elem(Datum value, const ResourceOwnerDesc *kind)
Definition resowner.c:222
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:1006
void ResourceOwnerRelease(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition resowner.c:665
static int resource_priority_cmp(const void *a, const void *b)
Definition resowner.c:266
void RegisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
Definition resowner.c:968
static void ResourceOwnerReleaseInternal(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition resowner.c:685
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition resowner.c:571
void ResourceOwnerReleaseAllOfKind(ResourceOwner owner, const ResourceOwnerDesc *kind)
Definition resowner.c:825
ResourceOwner AuxProcessResourceOwner
Definition resowner.c:176
void ResourceOwnerDelete(ResourceOwner owner)
Definition resowner.c:878
ResourceOwner CurTransactionResourceOwner
Definition resowner.c:174
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition resowner.c:531
#define RESOWNER_ARRAY_SIZE
Definition resowner.c:73
static void ResourceOwnerSort(ResourceOwner owner)
Definition resowner.c:289
void ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock)
Definition resowner.c:1089
void ResourceOwnerForgetAioHandle(ResourceOwner owner, struct dlist_node *ioh_node)
Definition resowner.c:1117
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition resowner.c:459
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:896
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)
static ItemArray items
const char * name