PostgreSQL Source Code git master
Loading...
Searching...
No Matches
resowner.c File Reference
#include "postgres.h"
#include "common/hashfn.h"
#include "common/int.h"
#include "lib/ilist.h"
#include "storage/aio.h"
#include "storage/ipc.h"
#include "storage/predicate.h"
#include "storage/proc.h"
#include "utils/memutils.h"
#include "utils/resowner.h"
Include dependency graph for resowner.c:

Go to the source code of this file.

Data Structures

struct  ResourceElem
 
struct  ResourceOwnerData
 
struct  ResourceReleaseCallbackItem
 

Macros

#define RESOWNER_ARRAY_SIZE   32
 
#define RESOWNER_HASH_INIT_SIZE   64
 
#define RESOWNER_HASH_MAX_ITEMS(capacity)    Min(capacity - RESOWNER_ARRAY_SIZE, (capacity)/4 * 3)
 
#define MAX_RESOWNER_LOCKS   15
 

Typedefs

typedef struct ResourceElem ResourceElem
 
typedef struct ResourceReleaseCallbackItem ResourceReleaseCallbackItem
 

Functions

 StaticAssertDecl (RESOWNER_HASH_MAX_ITEMS(RESOWNER_HASH_INIT_SIZE) >=RESOWNER_ARRAY_SIZE, "initial hash size too small compared to array size")
 
static uint32 hash_resource_elem (Datum value, const ResourceOwnerDesc *kind)
 
static void ResourceOwnerAddToHash (ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
 
static int resource_priority_cmp (const void *a, const void *b)
 
static void ResourceOwnerSort (ResourceOwner owner)
 
static void ResourceOwnerReleaseAll (ResourceOwner owner, ResourceReleasePhase phase, bool printLeakWarnings)
 
static void ResourceOwnerReleaseInternal (ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
 
static void ReleaseAuxProcessResourcesCallback (int code, Datum arg)
 
ResourceOwner ResourceOwnerCreate (ResourceOwner parent, const char *name)
 
void ResourceOwnerEnlarge (ResourceOwner owner)
 
void ResourceOwnerRemember (ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
 
void ResourceOwnerForget (ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
 
void ResourceOwnerRelease (ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
 
void ResourceOwnerReleaseAllOfKind (ResourceOwner owner, const ResourceOwnerDesc *kind)
 
void ResourceOwnerDelete (ResourceOwner owner)
 
ResourceOwner ResourceOwnerGetParent (ResourceOwner owner)
 
void ResourceOwnerNewParent (ResourceOwner owner, ResourceOwner newparent)
 
void RegisterResourceReleaseCallback (ResourceReleaseCallback callback, void *arg)
 
void UnregisterResourceReleaseCallback (ResourceReleaseCallback callback, void *arg)
 
void CreateAuxProcessResourceOwner (void)
 
void ReleaseAuxProcessResources (bool isCommit)
 
void ResourceOwnerRememberLock (ResourceOwner owner, LOCALLOCK *locallock)
 
void ResourceOwnerForgetLock (ResourceOwner owner, LOCALLOCK *locallock)
 
void ResourceOwnerRememberAioHandle (ResourceOwner owner, struct dlist_node *ioh_node)
 
void ResourceOwnerForgetAioHandle (ResourceOwner owner, struct dlist_node *ioh_node)
 

Variables

ResourceOwner CurrentResourceOwner = NULL
 
ResourceOwner CurTransactionResourceOwner = NULL
 
ResourceOwner TopTransactionResourceOwner = NULL
 
ResourceOwner AuxProcessResourceOwner = NULL
 
static ResourceReleaseCallbackItemResourceRelease_callbacks = NULL
 

Macro Definition Documentation

◆ MAX_RESOWNER_LOCKS

#define MAX_RESOWNER_LOCKS   15

Definition at line 107 of file resowner.c.

◆ RESOWNER_ARRAY_SIZE

#define RESOWNER_ARRAY_SIZE   32

Definition at line 73 of file resowner.c.

◆ RESOWNER_HASH_INIT_SIZE

#define RESOWNER_HASH_INIT_SIZE   64

Definition at line 79 of file resowner.c.

◆ RESOWNER_HASH_MAX_ITEMS

#define RESOWNER_HASH_MAX_ITEMS (   capacity)     Min(capacity - RESOWNER_ARRAY_SIZE, (capacity)/4 * 3)

Definition at line 91 of file resowner.c.

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

Typedef Documentation

◆ ResourceElem

◆ ResourceReleaseCallbackItem

Function Documentation

◆ CreateAuxProcessResourceOwner()

void CreateAuxProcessResourceOwner ( void  )

Definition at line 996 of file resowner.c.

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}

References Assert, AuxProcessResourceOwner, CurrentResourceOwner, fb(), on_shmem_exit(), ReleaseAuxProcessResourcesCallback(), and ResourceOwnerCreate().

Referenced by AuxiliaryProcessMainCommon(), InitPostgres(), and InitWalSender().

◆ hash_resource_elem()

static uint32 hash_resource_elem ( Datum  value,
const ResourceOwnerDesc kind 
)
inlinestatic

Definition at line 222 of file resowner.c.

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}

References fb(), hash_combine64(), murmurhash64(), and value.

Referenced by ResourceOwnerAddToHash(), and ResourceOwnerForget().

◆ RegisterResourceReleaseCallback()

◆ ReleaseAuxProcessResources()

◆ ReleaseAuxProcessResourcesCallback()

static void ReleaseAuxProcessResourcesCallback ( int  code,
Datum  arg 
)
static

Definition at line 1041 of file resowner.c.

1042{
1043 bool isCommit = (code == 0);
1044
1046}

References fb(), and ReleaseAuxProcessResources().

Referenced by CreateAuxProcessResourceOwner().

◆ resource_priority_cmp()

static int resource_priority_cmp ( const void a,
const void b 
)
static

Definition at line 266 of file resowner.c.

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}

References a, b, fb(), and pg_cmp_u32().

Referenced by ResourceOwnerSort().

◆ ResourceOwnerAddToHash()

static void ResourceOwnerAddToHash ( ResourceOwner  owner,
Datum  value,
const ResourceOwnerDesc kind 
)
static

Definition at line 242 of file resowner.c.

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}

References Assert, ResourceOwnerData::capacity, fb(), ResourceOwnerData::hash, hash_resource_elem(), idx(), ResourceElem::item, ResourceElem::kind, ResourceOwnerData::nhash, and value.

Referenced by ResourceOwnerEnlarge().

◆ ResourceOwnerCreate()

◆ ResourceOwnerDelete()

void ResourceOwnerDelete ( ResourceOwner  owner)

Definition at line 868 of file resowner.c.

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 */
891
892 /* And free the object. */
893 if (owner->hash)
894 pfree(owner->hash);
895 pfree(owner);
896}

References Assert, CurrentResourceOwner, fb(), ResourceOwnerData::firstchild, ResourceOwnerData::hash, MAX_RESOWNER_LOCKS, ResourceOwnerData::narr, ResourceOwnerData::nhash, ResourceOwnerData::nlocks, pfree(), ResourceOwnerDelete(), and ResourceOwnerNewParent().

Referenced by CleanupSubTransaction(), CleanupTransaction(), CommitSubTransaction(), CommitTransaction(), plpgsql_call_handler(), plpgsql_inline_handler(), PortalDrop(), PrepareTransaction(), ResourceOwnerDelete(), test_dsa_resowners(), test_resowner_leak(), test_resowner_many(), and test_resowner_priorities().

◆ ResourceOwnerEnlarge()

void ResourceOwnerEnlarge ( ResourceOwner  owner)

Definition at line 449 of file resowner.c.

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;
471
472 oldhash = owner->hash;
473 oldcap = owner->capacity;
474
475 /* Double the capacity (it must stay a power of 2!) */
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;
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}

References ResourceOwnerData::arr, Assert, ResourceOwnerData::capacity, elog, ERROR, fb(), ResourceOwnerData::grow_at, ResourceOwnerData::hash, i, ResourceElem::item, ResourceElem::kind, MemoryContextAllocZero(), ResourceOwnerData::narr, ResourceOwnerData::nhash, pfree(), ResourceOwnerData::releasing, ResourceOwnerAddToHash(), RESOWNER_ARRAY_SIZE, RESOWNER_HASH_INIT_SIZE, RESOWNER_HASH_MAX_ITEMS, and TopMemoryContext.

Referenced by BufferAlloc(), CachedPlanAllowsSimpleValidityCheck(), CachedPlanIsSimplyValid(), CreateWaitEventSet(), dsm_create_descriptor(), dsm_unpin_mapping(), EvictAllUnpinnedBuffers(), EvictRelUnpinnedBuffers(), EvictUnpinnedBuffer(), ExtendBufferedRelLocal(), ExtendBufferedRelShared(), FlushDatabaseBuffers(), FlushRelationBuffers(), FlushRelationsAllBuffers(), GetCachedPlan(), GetLocalVictimBuffer(), GetVictimBuffer(), IncrBufferRefCount(), IncrTupleDescRefCount(), llvm_create_context(), LocalBufferAlloc(), MarkDirtyAllUnpinnedBuffers(), MarkDirtyRelUnpinnedBuffers(), MarkDirtyUnpinnedBuffer(), OpenTemporaryFile(), PathNameCreateTemporaryFile(), PathNameOpenTemporaryFile(), pg_cryptohash_create(), pg_hmac_create(), px_find_cipher(), px_find_digest(), ReadRecentBuffer(), RegisterSnapshotOnOwner(), RelationIncrementReferenceCount(), RememberManyTestResources(), SearchCatCacheInternal(), SearchCatCacheList(), SearchCatCacheMiss(), StartBufferIO(), SyncOneBuffer(), test_resowner_forget_between_phases(), test_resowner_leak(), test_resowner_priorities(), and test_resowner_remember_between_phases().

◆ ResourceOwnerForget()

void ResourceOwnerForget ( ResourceOwner  owner,
Datum  value,
const ResourceOwnerDesc kind 
)

Definition at line 561 of file resowner.c.

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
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
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}

References ResourceOwnerData::arr, Assert, ResourceOwnerData::capacity, DatumGetPointer(), elog, ERROR, fb(), ResourceOwnerData::hash, hash_resource_elem(), i, idx(), ResourceElem::item, ResourceElem::kind, ResourceOwnerData::name, ResourceOwnerDesc::name, ResourceOwnerData::narr, ResourceOwnerData::nhash, ResourceOwnerData::releasing, ResourceOwnerData::sorted, and value.

Referenced by ForgetManyTestResources(), ResourceOwnerForgetBuffer(), ResourceOwnerForgetBufferIO(), ResourceOwnerForgetCatCacheListRef(), ResourceOwnerForgetCatCacheRef(), ResourceOwnerForgetCryptoHash(), ResourceOwnerForgetDSM(), ResourceOwnerForgetFile(), ResourceOwnerForgetHMAC(), ResourceOwnerForgetJIT(), ResourceOwnerForgetOSSLCipher(), ResourceOwnerForgetOSSLDigest(), ResourceOwnerForgetPlanCacheRef(), ResourceOwnerForgetRelationRef(), ResourceOwnerForgetSnapshot(), ResourceOwnerForgetTupleDesc(), ResourceOwnerForgetWaitEventSet(), and test_resowner_forget_between_phases().

◆ ResourceOwnerForgetAioHandle()

void ResourceOwnerForgetAioHandle ( ResourceOwner  owner,
struct dlist_node ioh_node 
)

Definition at line 1107 of file resowner.c.

1108{
1110}

References ResourceOwnerData::aio_handles, dlist_delete_from(), and fb().

Referenced by pgaio_io_reclaim(), and pgaio_io_release_resowner().

◆ ResourceOwnerForgetLock()

void ResourceOwnerForgetLock ( ResourceOwner  owner,
LOCALLOCK locallock 
)

Definition at line 1079 of file resowner.c.

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}

References Assert, elog, ERROR, fb(), i, ResourceOwnerData::locks, MAX_RESOWNER_LOCKS, ResourceOwnerData::name, and ResourceOwnerData::nlocks.

Referenced by LockReassignOwner(), LockRelease(), LockReleaseAll(), ReleaseLockIfHeld(), and RemoveLocalLock().

◆ ResourceOwnerGetParent()

ResourceOwner ResourceOwnerGetParent ( ResourceOwner  owner)

Definition at line 902 of file resowner.c.

903{
904 return owner->parent;
905}

References ResourceOwnerData::parent.

Referenced by LockReassignCurrentOwner().

◆ ResourceOwnerNewParent()

void ResourceOwnerNewParent ( ResourceOwner  owner,
ResourceOwner  newparent 
)

Definition at line 911 of file resowner.c.

913{
915
916 if (oldparent)
917 {
918 if (owner == oldparent->firstchild)
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;
940 newparent->firstchild = owner;
941 }
942 else
943 {
944 owner->parent = NULL;
945 owner->nextchild = NULL;
946 }
947}

References Assert, fb(), ResourceOwnerData::firstchild, ResourceOwnerData::nextchild, and ResourceOwnerData::parent.

Referenced by AtSubAbort_Portals(), AtSubCommit_Portals(), and ResourceOwnerDelete().

◆ ResourceOwnerRelease()

void ResourceOwnerRelease ( ResourceOwner  owner,
ResourceReleasePhase  phase,
bool  isCommit,
bool  isTopLevel 
)

Definition at line 655 of file resowner.c.

659{
660 /* There's not currently any setup needed before recursing */
662
663#ifdef RESOWNER_STATS
664 if (isTopLevel)
665 {
666 elog(LOG, "RESOWNER STATS: lookups: array %d, hash %d",
668 narray_lookups = 0;
669 nhash_lookups = 0;
670 }
671#endif
672}

References elog, fb(), LOG, and ResourceOwnerReleaseInternal().

Referenced by AbortSubTransaction(), AbortTransaction(), CommitSubTransaction(), CommitTransaction(), PortalDrop(), PrepareTransaction(), ReleaseAuxProcessResources(), test_dsa_resowners(), test_resowner_forget_between_phases(), test_resowner_leak(), test_resowner_many(), test_resowner_priorities(), and test_resowner_remember_between_phases().

◆ ResourceOwnerReleaseAll()

static void ResourceOwnerReleaseAll ( ResourceOwner  owner,
ResourceReleasePhase  phase,
bool  printLeakWarnings 
)
static

Definition at line 345 of file resowner.c.

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
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}

References ResourceOwnerData::arr, Assert, DatumGetPointer(), ResourceOwnerDesc::DebugPrint, elog, fb(), ResourceOwnerData::hash, idx(), items, ResourceOwnerDesc::name, ResourceOwnerData::narr, ResourceOwnerData::nhash, nitems, pfree(), psprintf(), ResourceOwnerDesc::release_phase, ResourceOwnerDesc::ReleaseResource, ResourceOwnerData::releasing, ResourceOwnerData::sorted, value, and WARNING.

Referenced by ResourceOwnerReleaseInternal().

◆ ResourceOwnerReleaseAllOfKind()

void ResourceOwnerReleaseAllOfKind ( ResourceOwner  owner,
const ResourceOwnerDesc kind 
)

Definition at line 815 of file resowner.c.

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}

References ResourceOwnerData::arr, Assert, ResourceOwnerData::capacity, elog, ERROR, fb(), ResourceOwnerData::hash, i, ResourceElem::item, ResourceElem::kind, ResourceOwnerDesc::name, ResourceOwnerData::narr, ResourceOwnerData::nhash, ResourceOwnerDesc::ReleaseResource, ResourceOwnerData::releasing, ResourceOwnerData::sorted, and value.

Referenced by ReleaseAllPlanCacheRefsInOwner().

◆ ResourceOwnerReleaseInternal()

static void ResourceOwnerReleaseInternal ( ResourceOwner  owner,
ResourceReleasePhase  phase,
bool  isCommit,
bool  isTopLevel 
)
static

Definition at line 675 of file resowner.c.

679{
680 ResourceOwner child;
684
685 /* Recurse to handle descendants */
686 for (child = owner->firstchild; child != NULL; child = child->nextchild)
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
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 {
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}

References ResourceOwnerData::aio_handles, ResourceReleaseCallbackItem::arg, Assert, ResourceReleaseCallbackItem::callback, CurrentResourceOwner, dlist_head_node(), dlist_is_empty(), fb(), ResourceOwnerData::firstchild, LockReassignCurrentOwner(), LockReleaseCurrentOwner(), ResourceOwnerData::locks, MAX_RESOWNER_LOCKS, next, ResourceReleaseCallbackItem::next, ResourceOwnerData::nextchild, ResourceOwnerData::nlocks, ResourceOwnerData::parent, pgaio_io_release_resowner(), ProcReleaseLocks(), ReleasePredicateLocks(), ResourceOwnerData::releasing, RESOURCE_RELEASE_AFTER_LOCKS, RESOURCE_RELEASE_BEFORE_LOCKS, RESOURCE_RELEASE_LOCKS, ResourceOwnerReleaseAll(), ResourceOwnerReleaseInternal(), ResourceOwnerSort(), ResourceRelease_callbacks, ResourceOwnerData::sorted, and TopTransactionResourceOwner.

Referenced by ResourceOwnerRelease(), and ResourceOwnerReleaseInternal().

◆ ResourceOwnerRemember()

void ResourceOwnerRemember ( ResourceOwner  owner,
Datum  value,
const ResourceOwnerDesc kind 
)

Definition at line 521 of file resowner.c.

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}

References ResourceOwnerData::arr, Assert, elog, ERROR, idx(), ResourceElem::item, ResourceElem::kind, ResourceOwnerData::narr, ResourceOwnerDesc::release_phase, ResourceOwnerDesc::release_priority, ResourceOwnerData::releasing, RESOWNER_ARRAY_SIZE, ResourceOwnerData::sorted, and value.

Referenced by RememberManyTestResources(), ResourceOwnerRememberBuffer(), ResourceOwnerRememberBufferIO(), ResourceOwnerRememberCatCacheListRef(), ResourceOwnerRememberCatCacheRef(), ResourceOwnerRememberCryptoHash(), ResourceOwnerRememberDSM(), ResourceOwnerRememberFile(), ResourceOwnerRememberHMAC(), ResourceOwnerRememberJIT(), ResourceOwnerRememberOSSLCipher(), ResourceOwnerRememberOSSLDigest(), ResourceOwnerRememberPlanCacheRef(), ResourceOwnerRememberRelationRef(), ResourceOwnerRememberSnapshot(), ResourceOwnerRememberTupleDesc(), ResourceOwnerRememberWaitEventSet(), test_resowner_forget_between_phases(), test_resowner_leak(), test_resowner_priorities(), and test_resowner_remember_between_phases().

◆ ResourceOwnerRememberAioHandle()

void ResourceOwnerRememberAioHandle ( ResourceOwner  owner,
struct dlist_node ioh_node 
)

Definition at line 1101 of file resowner.c.

1102{
1104}

References ResourceOwnerData::aio_handles, dlist_push_tail(), and fb().

Referenced by pgaio_io_resowner_register().

◆ ResourceOwnerRememberLock()

void ResourceOwnerRememberLock ( ResourceOwner  owner,
LOCALLOCK locallock 
)

Definition at line 1059 of file resowner.c.

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}

References Assert, fb(), ResourceOwnerData::locks, MAX_RESOWNER_LOCKS, and ResourceOwnerData::nlocks.

Referenced by GrantLockLocal(), and LockReassignOwner().

◆ ResourceOwnerSort()

static void ResourceOwnerSort ( ResourceOwner  owner)
static

Definition at line 289 of file resowner.c.

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}

References ResourceOwnerData::arr, Assert, ResourceOwnerData::capacity, fb(), ResourceOwnerData::hash, idx(), items, ResourceElem::kind, ResourceOwnerData::narr, ResourceOwnerData::nhash, nitems, qsort, and resource_priority_cmp().

Referenced by ResourceOwnerReleaseInternal().

◆ StaticAssertDecl()

StaticAssertDecl ( RESOWNER_HASH_MAX_ITEMS(RESOWNER_HASH_INIT_SIZE) >=  RESOWNER_ARRAY_SIZE,
"initial hash size too small compared to array size"   
)

◆ UnregisterResourceReleaseCallback()

void UnregisterResourceReleaseCallback ( ResourceReleaseCallback  callback,
void arg 
)

Definition at line 972 of file resowner.c.

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}

References ResourceReleaseCallbackItem::arg, arg, ResourceReleaseCallbackItem::callback, callback(), fb(), ResourceReleaseCallbackItem::next, pfree(), and ResourceRelease_callbacks.

Variable Documentation

◆ AuxProcessResourceOwner

◆ CurrentResourceOwner

ResourceOwner CurrentResourceOwner = NULL

Definition at line 173 of file resowner.c.

Referenced by _SPI_execute_plan(), apply_spooled_messages(), AssignTransactionId(), AsyncReadBuffers(), AtAbort_ResourceOwner(), AtStart_ResourceOwner(), AtSubAbort_ResourceOwner(), AtSubStart_ResourceOwner(), attach_internal(), buffer_call_start_io(), buffer_stage_common(), BufferAlloc(), CleanupSubTransaction(), CleanupTransaction(), close_lo_relation(), CommitSubTransaction(), CommitTransaction(), create_internal(), CreateAuxProcessResourceOwner(), DecrTupleDescRefCount(), dsm_create_descriptor(), dsm_unpin_mapping(), EvictAllUnpinnedBuffers(), EvictRelUnpinnedBuffers(), EvictUnpinnedBuffer(), exec_eval_simple_expr(), exec_init_tuple_store(), exec_simple_check_plan(), exec_stmt_block(), ExecAppendAsyncEventWait(), ExplainExecuteQuery(), ExtendBufferedRelLocal(), ExtendBufferedRelShared(), extendBufFile(), FlushDatabaseBuffers(), FlushRelationBuffers(), FlushRelationsAllBuffers(), get_segment_by_index(), GetCurrentFDWTuplestore(), GetLocalVictimBuffer(), GetVictimBuffer(), handle_get(), handle_get_and_error(), handle_get_release(), handle_get_twice(), IncrBufferRefCount(), IncrTupleDescRefCount(), init_execution_state(), InitPostgres(), llvm_create_context(), LocalBufferAlloc(), lock_and_open_sequence(), LockAcquireExtended(), LockReassignCurrentOwner(), LockReassignOwner(), LockRelease(), LogicalSlotAdvanceAndCheckSnapState(), make_callstmt_target(), make_new_segment(), makeBufFileCommon(), MakeTransitionCaptureState(), MarkDirtyAllUnpinnedBuffers(), MarkDirtyRelUnpinnedBuffers(), MarkDirtyUnpinnedBuffer(), open_lo_relation(), OpenTemporaryFile(), PathNameCreateTemporaryFile(), PathNameOpenTemporaryFile(), perform_base_backup(), PersistHoldablePortal(), pg_cryptohash_create(), pg_hmac_create(), pg_logical_slot_get_changes_guts(), PinBuffer(), PinLocalBuffer(), plperl_spi_exec(), plperl_spi_exec_prepared(), plperl_spi_fetchrow(), plperl_spi_prepare(), plperl_spi_query(), plperl_spi_query_prepared(), plpgsql_estate_setup(), pltcl_func_handler(), pltcl_init_tuple_store(), pltcl_returnnext(), pltcl_SPI_execute(), pltcl_SPI_execute_plan(), pltcl_SPI_prepare(), pltcl_subtrans_abort(), pltcl_subtrans_commit(), pltcl_subtransaction(), PLy_abort_open_subtransactions(), PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_cursor_plan(), PLy_cursor_query(), PLy_spi_execute_plan(), PLy_spi_execute_query(), PLy_spi_prepare(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_commit(), PLy_subtransaction_enter(), PLy_subtransaction_exit(), PopTransaction(), PortalCleanup(), PortalRun(), PortalRunFetch(), PortalStart(), PrepareTransaction(), px_find_cipher(), px_find_digest(), read_rel_block_ll(), ReadRecentBuffer(), RegisterSnapshot(), RegisterTemporaryFile(), RelationDecrementReferenceCount(), RelationIncrementReferenceCount(), ReleaseCatCache(), ReleaseCatCacheList(), ReleaseLockIfHeld(), ReorderBufferImmediateInvalidation(), ReorderBufferProcessTXN(), ResourceOwnerDelete(), ResourceOwnerReleaseInternal(), SearchCatCacheInternal(), SearchCatCacheList(), SearchCatCacheMiss(), ShutdownXLOG(), SnapBuildClearExportedSnapshot(), SnapBuildExportSnapshot(), SPI_plan_get_cached_plan(), StartBufferIO(), StartupXLOG(), SyncOneBuffer(), TerminateBufferIO(), test_dsa_resowners(), test_resowner_forget_between_phases(), test_resowner_leak(), test_resowner_many(), test_resowner_priorities(), test_resowner_remember_between_phases(), TrackNewBufferPin(), tuplestore_begin_common(), tuplestore_puttuple_common(), UnpinBuffer(), UnpinLocalBuffer(), UnregisterSnapshot(), UploadManifest(), and WaitLatchOrSocket().

◆ CurTransactionResourceOwner

◆ ResourceRelease_callbacks

◆ TopTransactionResourceOwner