1 /*-------------------------------------------------------------------------
4 * POSTGRES resource owner management code.
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.
12 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
13 * Portions Copyright (c) 1994, Regents of the University of California
17 * $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.3 2004/08/25 18:43:43 tgl Exp $
19 *-------------------------------------------------------------------------
23 #include "utils/resowner.h"
24 #include "access/gistscan.h"
25 #include "access/hash.h"
26 #include "access/rtree.h"
27 #include "storage/bufmgr.h"
28 #include "storage/proc.h"
29 #include "utils/memutils.h"
30 #include "utils/relcache.h"
34 * Info needed to identify/release a lock
36 typedef struct LockIdData
38 /* we assume lockmethodid is part of locktag */
46 * ResourceOwner objects look like this
48 typedef struct ResourceOwnerData
50 ResourceOwner parent; /* NULL if no parent (toplevel owner) */
51 ResourceOwner firstchild; /* head of linked list of children */
52 ResourceOwner nextchild; /* next child of same parent */
53 const char *name; /* name (just for debugging) */
55 /* We have built-in support for remembering owned buffers */
56 int nbuffers; /* number of owned buffer pins */
57 Buffer *buffers; /* dynamically allocated array */
58 int maxbuffers; /* currently allocated array size */
60 /* We have built-in support for remembering owned locks */
61 int nlocks; /* number of owned locks */
62 LockIdData *locks; /* dynamically allocated array */
63 int maxlocks; /* currently allocated array size */
65 /* We have built-in support for remembering catcache references */
66 int ncatrefs; /* number of owned catcache pins */
67 HeapTuple *catrefs; /* dynamically allocated array */
68 int maxcatrefs; /* currently allocated array size */
70 int ncatlistrefs; /* number of owned catcache-list pins */
71 CatCList **catlistrefs; /* dynamically allocated array */
72 int maxcatlistrefs; /* currently allocated array size */
74 /* We have built-in support for remembering relcache references */
75 int nrelrefs; /* number of owned relcache pins */
76 Relation *relrefs; /* dynamically allocated array */
77 int maxrelrefs; /* currently allocated array size */
81 /*****************************************************************************
83 *****************************************************************************/
85 ResourceOwner CurrentResourceOwner = NULL;
86 ResourceOwner CurTransactionResourceOwner = NULL;
87 ResourceOwner TopTransactionResourceOwner = NULL;
90 * List of add-on callbacks for resource releasing
92 typedef struct ResourceReleaseCallbackItem
94 struct ResourceReleaseCallbackItem *next;
95 ResourceReleaseCallback callback;
97 } ResourceReleaseCallbackItem;
99 static ResourceReleaseCallbackItem *ResourceRelease_callbacks = NULL;
102 /* Internal routines */
103 static void ResourceOwnerReleaseInternal(ResourceOwner owner,
104 ResourceReleasePhase phase,
109 /*****************************************************************************
110 * EXPORTED ROUTINES *
111 *****************************************************************************/
115 * ResourceOwnerCreate
116 * Create an empty ResourceOwner.
118 * All ResourceOwner objects are kept in TopMemoryContext, since they should
119 * only be freed explicitly.
122 ResourceOwnerCreate(ResourceOwner parent, const char *name)
126 owner = (ResourceOwner) MemoryContextAllocZero(TopMemoryContext,
127 sizeof(ResourceOwnerData));
132 owner->parent = parent;
133 owner->nextchild = parent->firstchild;
134 parent->firstchild = owner;
141 * ResourceOwnerRelease
142 * Release all resources owned by a ResourceOwner and its descendants,
143 * but don't delete the owner objects themselves.
145 * Note that this executes just one phase of release, and so typically
146 * must be called three times. We do it this way because (a) we want to
147 * do all the recursion separately for each phase, thereby preserving
148 * the needed order of operations; and (b) xact.c may have other operations
149 * to do between the phases.
151 * phase: release phase to execute
152 * isCommit: true for successful completion of a query or transaction,
153 * false for unsuccessful
154 * isTopLevel: true if completing a main transaction, else false
156 * isCommit is passed because some modules may expect that their resources
157 * were all released already if the transaction or portal finished normally.
158 * If so it is reasonable to give a warning (NOT an error) should any
159 * unreleased resources be present. When isCommit is false, such warnings
160 * are generally inappropriate.
162 * isTopLevel is passed when we are releasing TopTransactionResourceOwner
163 * at completion of a main transaction. This generally means that *all*
164 * resources will be released, and so we can optimize things a bit.
167 ResourceOwnerRelease(ResourceOwner owner,
168 ResourceReleasePhase phase,
172 /* Rather than PG_TRY at every level of recursion, set it up once */
175 save = CurrentResourceOwner;
178 ResourceOwnerReleaseInternal(owner, phase, isCommit, isTopLevel);
182 CurrentResourceOwner = save;
186 CurrentResourceOwner = save;
190 ResourceOwnerReleaseInternal(ResourceOwner owner,
191 ResourceReleasePhase phase,
197 ResourceReleaseCallbackItem *item;
199 /* Recurse to handle descendants */
200 for (child = owner->firstchild; child != NULL; child = child->nextchild)
201 ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel);
204 * Make CurrentResourceOwner point to me, so that ReleaseBuffer etc
205 * don't get confused. We needn't PG_TRY here because the outermost
206 * level will fix it on error abort.
208 save = CurrentResourceOwner;
209 CurrentResourceOwner = owner;
211 if (phase == RESOURCE_RELEASE_BEFORE_LOCKS)
213 /* Release buffer pins */
217 * For a top-level xact we are going to release all buffers,
218 * so just do a single bufmgr call at the top of the recursion.
220 if (owner == TopTransactionResourceOwner)
221 AtEOXact_Buffers(isCommit);
222 /* Mark object as owning no buffers, just for sanity */
228 * Release buffers retail. Note that ReleaseBuffer will remove
229 * the buffer entry from my list, so I just have to iterate till
232 * XXX this is fairly inefficient due to multiple BufMgrLock grabs
233 * if there are lots of buffers to be released, but we don't
234 * expect many (indeed none in the success case) so it's probably
235 * not worth optimizing.
237 * We are however careful to release back-to-front, so as to
238 * avoid O(N^2) behavior in ResourceOwnerForgetBuffer().
240 while (owner->nbuffers > 0)
241 ReleaseBuffer(owner->buffers[owner->nbuffers - 1]);
243 /* Release relcache references */
247 * For a top-level xact we are going to release all references,
248 * so just do a single relcache call at the top of the recursion.
250 if (owner == TopTransactionResourceOwner)
251 AtEOXact_RelationCache(isCommit);
252 /* Mark object as owning no relrefs, just for sanity */
258 * Release relcache refs retail. Note that RelationClose will
259 * remove the relref entry from my list, so I just have to iterate
260 * till there are none.
262 while (owner->nrelrefs > 0)
263 RelationClose(owner->relrefs[owner->nrelrefs - 1]);
266 else if (phase == RESOURCE_RELEASE_LOCKS)
271 * For a top-level xact we are going to release all locks (or at
272 * least all non-session locks), so just do a single lmgr call
273 * at the top of the recursion.
275 if (owner == TopTransactionResourceOwner)
276 ProcReleaseLocks(isCommit);
277 /* Mark object as holding no locks, just for sanity */
283 * Release locks retail. Note that LockRelease will remove
284 * the lock entry from my list, so I just have to iterate till
285 * there are none. Also note that if we are committing a
286 * subtransaction, we do NOT release its locks yet, but transfer
287 * them to the parent.
289 * XXX as above, this is a bit inefficient but probably not worth
290 * the trouble to optimize more.
292 Assert(owner->parent != NULL);
293 while (owner->nlocks > 0)
295 LockIdData *lockid = &owner->locks[owner->nlocks - 1];
299 ResourceOwnerEnlargeLocks(owner->parent);
300 ResourceOwnerRememberLock(owner->parent,
308 LockRelease(lockid->locktag.lockmethodid,
312 /* LockRelease will have removed the entry from list */
317 else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
319 /* Release catcache references */
323 * For a top-level xact we are going to release all references,
324 * so just do a single catcache call at the top of the recursion.
326 if (owner == TopTransactionResourceOwner)
327 AtEOXact_CatCache(isCommit);
328 /* Mark object as owning no catrefs, just for sanity */
330 owner->ncatlistrefs = 0;
335 * Release catcache refs retail. Note that ReleaseCatCache will
336 * remove the catref entry from my list, so I just have to iterate
337 * till there are none. Ditto for catcache lists.
339 while (owner->ncatrefs > 0)
340 ReleaseCatCache(owner->catrefs[owner->ncatrefs - 1]);
341 while (owner->ncatlistrefs > 0)
342 ReleaseCatCacheList(owner->catlistrefs[owner->ncatlistrefs - 1]);
344 /* Clean up index scans too */
345 ReleaseResources_gist();
346 ReleaseResources_hash();
347 ReleaseResources_rtree();
350 /* Let add-on modules get a chance too */
351 for (item = ResourceRelease_callbacks; item; item = item->next)
352 (*item->callback) (phase, isCommit, isTopLevel, item->arg);
354 CurrentResourceOwner = save;
358 * ResourceOwnerDelete
359 * Delete an owner object and its descendants.
361 * The caller must have already released all resources in the object tree.
364 ResourceOwnerDelete(ResourceOwner owner)
366 /* We had better not be deleting CurrentResourceOwner ... */
367 Assert(owner != CurrentResourceOwner);
369 /* And it better not own any resources, either */
370 Assert(owner->nbuffers == 0);
371 Assert(owner->nlocks == 0);
372 Assert(owner->ncatrefs == 0);
373 Assert(owner->ncatlistrefs == 0);
374 Assert(owner->nrelrefs == 0);
377 * Delete children. The recursive call will delink the child
378 * from me, so just iterate as long as there is a child.
380 while (owner->firstchild != NULL)
381 ResourceOwnerDelete(owner->firstchild);
384 * We delink the owner from its parent before deleting it, so that
385 * if there's an error we won't have deleted/busted owners still
386 * attached to the owner tree. Better a leak than a crash.
388 ResourceOwnerNewParent(owner, NULL);
390 /* And free the object. */
392 pfree(owner->buffers);
396 pfree(owner->catrefs);
397 if (owner->catlistrefs)
398 pfree(owner->catlistrefs);
400 pfree(owner->relrefs);
406 * Reassign a ResourceOwner to have a new parent
409 ResourceOwnerNewParent(ResourceOwner owner,
410 ResourceOwner newparent)
412 ResourceOwner oldparent = owner->parent;
416 if (owner == oldparent->firstchild)
417 oldparent->firstchild = owner->nextchild;
422 for (child = oldparent->firstchild; child; child = child->nextchild)
424 if (owner == child->nextchild)
426 child->nextchild = owner->nextchild;
435 Assert(owner != newparent);
436 owner->parent = newparent;
437 owner->nextchild = newparent->firstchild;
438 newparent->firstchild = owner;
442 owner->parent = NULL;
443 owner->nextchild = NULL;
448 * Register or deregister callback functions for resource cleanup
450 * These functions are intended for use by dynamically loaded modules.
451 * For built-in modules we generally just hardwire the appropriate calls.
453 * Note that the callback occurs post-commit or post-abort, so the callback
454 * functions can only do noncritical cleanup.
457 RegisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
459 ResourceReleaseCallbackItem *item;
461 item = (ResourceReleaseCallbackItem *)
462 MemoryContextAlloc(TopMemoryContext,
463 sizeof(ResourceReleaseCallbackItem));
464 item->callback = callback;
466 item->next = ResourceRelease_callbacks;
467 ResourceRelease_callbacks = item;
471 UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
473 ResourceReleaseCallbackItem *item;
474 ResourceReleaseCallbackItem *prev;
477 for (item = ResourceRelease_callbacks; item; prev = item, item = item->next)
479 if (item->callback == callback && item->arg == arg)
482 prev->next = item->next;
484 ResourceRelease_callbacks = item->next;
493 * Make sure there is room for at least one more entry in a ResourceOwner's
496 * This is separate from actually inserting an entry because if we run out
497 * of memory, it's critical to do so *before* acquiring the resource.
499 * We allow the case owner == NULL because the bufmgr is sometimes invoked
500 * outside any transaction (for example, in the bgwriter).
503 ResourceOwnerEnlargeBuffers(ResourceOwner owner)
508 owner->nbuffers < owner->maxbuffers)
509 return; /* nothing to do */
511 if (owner->buffers == NULL)
514 owner->buffers = (Buffer *)
515 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(Buffer));
516 owner->maxbuffers = newmax;
520 newmax = owner->maxbuffers * 2;
521 owner->buffers = (Buffer *)
522 repalloc(owner->buffers, newmax * sizeof(Buffer));
523 owner->maxbuffers = newmax;
528 * Remember that a buffer pin is owned by a ResourceOwner
530 * Caller must have previously done ResourceOwnerEnlargeBuffers()
532 * We allow the case owner == NULL because the bufmgr is sometimes invoked
533 * outside any transaction (for example, in the bgwriter).
536 ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
540 Assert(owner->nbuffers < owner->maxbuffers);
541 owner->buffers[owner->nbuffers] = buffer;
547 * Forget that a buffer pin is owned by a ResourceOwner
549 * We allow the case owner == NULL because the bufmgr is sometimes invoked
550 * outside any transaction (for example, in the bgwriter).
553 ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
557 Buffer *buffers = owner->buffers;
558 int nb1 = owner->nbuffers - 1;
562 * Scan back-to-front because it's more likely we are releasing
563 * a recently pinned buffer. This isn't always the case of course,
564 * but it's the way to bet.
566 for (i = nb1; i >= 0; i--)
568 if (buffers[i] == buffer)
572 buffers[i] = buffers[i + 1];
575 owner->nbuffers = nb1;
579 elog(ERROR, "buffer %d is not owned by resource owner %s",
580 buffer, owner->name);
585 * Make sure there is room for at least one more entry in a ResourceOwner's
588 * This is separate from actually inserting an entry because if we run out
589 * of memory, it's critical to do so *before* acquiring the resource.
592 ResourceOwnerEnlargeLocks(ResourceOwner owner)
596 if (owner->nlocks < owner->maxlocks)
597 return; /* nothing to do */
599 if (owner->locks == NULL)
602 owner->locks = (LockIdData *)
603 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(LockIdData));
604 owner->maxlocks = newmax;
608 newmax = owner->maxlocks * 2;
609 owner->locks = (LockIdData *)
610 repalloc(owner->locks, newmax * sizeof(LockIdData));
611 owner->maxlocks = newmax;
616 * Remember that a lock is owned by a ResourceOwner
618 * Caller must have previously done ResourceOwnerEnlargeLocks()
621 ResourceOwnerRememberLock(ResourceOwner owner,
626 /* Session locks and user locks are not transactional */
627 if (xid != InvalidTransactionId &&
628 locktag->lockmethodid == DEFAULT_LOCKMETHOD)
630 Assert(owner->nlocks < owner->maxlocks);
631 owner->locks[owner->nlocks].locktag = *locktag;
632 owner->locks[owner->nlocks].xid = xid;
633 owner->locks[owner->nlocks].lockmode = lockmode;
639 * Forget that a lock is owned by a ResourceOwner
642 ResourceOwnerForgetLock(ResourceOwner owner,
647 /* Session locks and user locks are not transactional */
648 if (xid != InvalidTransactionId &&
649 locktag->lockmethodid == DEFAULT_LOCKMETHOD)
651 LockIdData *locks = owner->locks;
652 int nl1 = owner->nlocks - 1;
655 for (i = nl1; i >= 0; i--)
657 if (memcmp(&locks[i].locktag, locktag, sizeof(LOCKTAG)) == 0 &&
658 locks[i].xid == xid &&
659 locks[i].lockmode == lockmode)
663 locks[i] = locks[i + 1];
670 elog(ERROR, "lock %u/%u/%u is not owned by resource owner %s",
671 locktag->relId, locktag->dbId, locktag->objId.xid, owner->name);
676 * Make sure there is room for at least one more entry in a ResourceOwner's
677 * catcache reference array.
679 * This is separate from actually inserting an entry because if we run out
680 * of memory, it's critical to do so *before* acquiring the resource.
683 ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner)
687 if (owner->ncatrefs < owner->maxcatrefs)
688 return; /* nothing to do */
690 if (owner->catrefs == NULL)
693 owner->catrefs = (HeapTuple *)
694 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(HeapTuple));
695 owner->maxcatrefs = newmax;
699 newmax = owner->maxcatrefs * 2;
700 owner->catrefs = (HeapTuple *)
701 repalloc(owner->catrefs, newmax * sizeof(HeapTuple));
702 owner->maxcatrefs = newmax;
707 * Remember that a catcache reference is owned by a ResourceOwner
709 * Caller must have previously done ResourceOwnerEnlargeCatCacheRefs()
712 ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple)
714 Assert(owner->ncatrefs < owner->maxcatrefs);
715 owner->catrefs[owner->ncatrefs] = tuple;
720 * Forget that a catcache reference is owned by a ResourceOwner
723 ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple)
725 HeapTuple *catrefs = owner->catrefs;
726 int nc1 = owner->ncatrefs - 1;
729 for (i = nc1; i >= 0; i--)
731 if (catrefs[i] == tuple)
735 catrefs[i] = catrefs[i + 1];
738 owner->ncatrefs = nc1;
742 elog(ERROR, "catcache reference %p is not owned by resource owner %s",
747 * Make sure there is room for at least one more entry in a ResourceOwner's
748 * catcache-list reference array.
750 * This is separate from actually inserting an entry because if we run out
751 * of memory, it's critical to do so *before* acquiring the resource.
754 ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner)
758 if (owner->ncatlistrefs < owner->maxcatlistrefs)
759 return; /* nothing to do */
761 if (owner->catlistrefs == NULL)
764 owner->catlistrefs = (CatCList **)
765 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(CatCList *));
766 owner->maxcatlistrefs = newmax;
770 newmax = owner->maxcatlistrefs * 2;
771 owner->catlistrefs = (CatCList **)
772 repalloc(owner->catlistrefs, newmax * sizeof(CatCList *));
773 owner->maxcatlistrefs = newmax;
778 * Remember that a catcache-list reference is owned by a ResourceOwner
780 * Caller must have previously done ResourceOwnerEnlargeCatCacheListRefs()
783 ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
785 Assert(owner->ncatlistrefs < owner->maxcatlistrefs);
786 owner->catlistrefs[owner->ncatlistrefs] = list;
787 owner->ncatlistrefs++;
791 * Forget that a catcache-list reference is owned by a ResourceOwner
794 ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list)
796 CatCList **catlistrefs = owner->catlistrefs;
797 int nc1 = owner->ncatlistrefs - 1;
800 for (i = nc1; i >= 0; i--)
802 if (catlistrefs[i] == list)
806 catlistrefs[i] = catlistrefs[i + 1];
809 owner->ncatlistrefs = nc1;
813 elog(ERROR, "catcache list reference %p is not owned by resource owner %s",
818 * Make sure there is room for at least one more entry in a ResourceOwner's
819 * relcache reference array.
821 * This is separate from actually inserting an entry because if we run out
822 * of memory, it's critical to do so *before* acquiring the resource.
825 ResourceOwnerEnlargeRelationRefs(ResourceOwner owner)
829 if (owner->nrelrefs < owner->maxrelrefs)
830 return; /* nothing to do */
832 if (owner->relrefs == NULL)
835 owner->relrefs = (Relation *)
836 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(Relation));
837 owner->maxrelrefs = newmax;
841 newmax = owner->maxrelrefs * 2;
842 owner->relrefs = (Relation *)
843 repalloc(owner->relrefs, newmax * sizeof(Relation));
844 owner->maxrelrefs = newmax;
849 * Remember that a relcache reference is owned by a ResourceOwner
851 * Caller must have previously done ResourceOwnerEnlargeRelationRefs()
854 ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel)
856 Assert(owner->nrelrefs < owner->maxrelrefs);
857 owner->relrefs[owner->nrelrefs] = rel;
862 * Forget that a relcache reference is owned by a ResourceOwner
865 ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
867 Relation *relrefs = owner->relrefs;
868 int nr1 = owner->nrelrefs - 1;
871 for (i = nr1; i >= 0; i--)
873 if (relrefs[i] == rel)
877 relrefs[i] = relrefs[i + 1];
880 owner->nrelrefs = nr1;
884 elog(ERROR, "relcache reference %s is not owned by resource owner %s",
885 RelationGetRelationName(rel), owner->name);