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-2004, 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.5 2004/08/29 04:13:00 momjian 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 * ResourceOwner objects look like this
36 typedef struct ResourceOwnerData
38 ResourceOwner parent; /* NULL if no parent (toplevel owner) */
39 ResourceOwner firstchild; /* head of linked list of children */
40 ResourceOwner nextchild; /* next child of same parent */
41 const char *name; /* name (just for debugging) */
43 /* We have built-in support for remembering owned buffers */
44 int nbuffers; /* number of owned buffer pins */
45 Buffer *buffers; /* dynamically allocated array */
46 int maxbuffers; /* currently allocated array size */
48 /* We have built-in support for remembering catcache references */
49 int ncatrefs; /* number of owned catcache pins */
50 HeapTuple *catrefs; /* dynamically allocated array */
51 int maxcatrefs; /* currently allocated array size */
53 int ncatlistrefs; /* number of owned catcache-list pins */
54 CatCList **catlistrefs; /* dynamically allocated array */
55 int maxcatlistrefs; /* currently allocated array size */
57 /* We have built-in support for remembering relcache references */
58 int nrelrefs; /* number of owned relcache pins */
59 Relation *relrefs; /* dynamically allocated array */
60 int maxrelrefs; /* currently allocated array size */
64 /*****************************************************************************
66 *****************************************************************************/
68 ResourceOwner CurrentResourceOwner = NULL;
69 ResourceOwner CurTransactionResourceOwner = NULL;
70 ResourceOwner TopTransactionResourceOwner = NULL;
73 * List of add-on callbacks for resource releasing
75 typedef struct ResourceReleaseCallbackItem
77 struct ResourceReleaseCallbackItem *next;
78 ResourceReleaseCallback callback;
80 } ResourceReleaseCallbackItem;
82 static ResourceReleaseCallbackItem *ResourceRelease_callbacks = NULL;
85 /* Internal routines */
86 static void ResourceOwnerReleaseInternal(ResourceOwner owner,
87 ResourceReleasePhase phase,
92 /*****************************************************************************
94 *****************************************************************************/
99 * Create an empty ResourceOwner.
101 * All ResourceOwner objects are kept in TopMemoryContext, since they should
102 * only be freed explicitly.
105 ResourceOwnerCreate(ResourceOwner parent, const char *name)
109 owner = (ResourceOwner) MemoryContextAllocZero(TopMemoryContext,
110 sizeof(ResourceOwnerData));
115 owner->parent = parent;
116 owner->nextchild = parent->firstchild;
117 parent->firstchild = owner;
124 * ResourceOwnerRelease
125 * Release all resources owned by a ResourceOwner and its descendants,
126 * but don't delete the owner objects themselves.
128 * Note that this executes just one phase of release, and so typically
129 * must be called three times. We do it this way because (a) we want to
130 * do all the recursion separately for each phase, thereby preserving
131 * the needed order of operations; and (b) xact.c may have other operations
132 * to do between the phases.
134 * phase: release phase to execute
135 * isCommit: true for successful completion of a query or transaction,
136 * false for unsuccessful
137 * isTopLevel: true if completing a main transaction, else false
139 * isCommit is passed because some modules may expect that their resources
140 * were all released already if the transaction or portal finished normally.
141 * If so it is reasonable to give a warning (NOT an error) should any
142 * unreleased resources be present. When isCommit is false, such warnings
143 * are generally inappropriate.
145 * isTopLevel is passed when we are releasing TopTransactionResourceOwner
146 * at completion of a main transaction. This generally means that *all*
147 * resources will be released, and so we can optimize things a bit.
150 ResourceOwnerRelease(ResourceOwner owner,
151 ResourceReleasePhase phase,
155 /* Rather than PG_TRY at every level of recursion, set it up once */
158 save = CurrentResourceOwner;
161 ResourceOwnerReleaseInternal(owner, phase, isCommit, isTopLevel);
165 CurrentResourceOwner = save;
169 CurrentResourceOwner = save;
173 ResourceOwnerReleaseInternal(ResourceOwner owner,
174 ResourceReleasePhase phase,
180 ResourceReleaseCallbackItem *item;
182 /* Recurse to handle descendants */
183 for (child = owner->firstchild; child != NULL; child = child->nextchild)
184 ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel);
187 * Make CurrentResourceOwner point to me, so that ReleaseBuffer etc
188 * don't get confused. We needn't PG_TRY here because the outermost
189 * level will fix it on error abort.
191 save = CurrentResourceOwner;
192 CurrentResourceOwner = owner;
194 if (phase == RESOURCE_RELEASE_BEFORE_LOCKS)
196 /* Release buffer pins */
200 * For a top-level xact we are going to release all buffers,
201 * so just do a single bufmgr call at the top of the recursion.
203 if (owner == TopTransactionResourceOwner)
204 AtEOXact_Buffers(isCommit);
205 /* Mark object as owning no buffers, just for sanity */
211 * Release buffers retail. Note that ReleaseBuffer will remove
212 * the buffer entry from my list, so I just have to iterate till
215 * XXX this is fairly inefficient due to multiple BufMgrLock grabs
216 * if there are lots of buffers to be released, but we don't
217 * expect many (indeed none in the success case) so it's probably
218 * not worth optimizing.
220 * We are however careful to release back-to-front, so as to
221 * avoid O(N^2) behavior in ResourceOwnerForgetBuffer().
223 while (owner->nbuffers > 0)
224 ReleaseBuffer(owner->buffers[owner->nbuffers - 1]);
226 /* Release relcache references */
230 * For a top-level xact we are going to release all references,
231 * so just do a single relcache call at the top of the recursion.
233 if (owner == TopTransactionResourceOwner)
234 AtEOXact_RelationCache(isCommit);
235 /* Mark object as owning no relrefs, just for sanity */
241 * Release relcache refs retail. Note that RelationClose will
242 * remove the relref entry from my list, so I just have to iterate
243 * till there are none.
245 while (owner->nrelrefs > 0)
246 RelationClose(owner->relrefs[owner->nrelrefs - 1]);
249 else if (phase == RESOURCE_RELEASE_LOCKS)
254 * For a top-level xact we are going to release all locks (or at
255 * least all non-session locks), so just do a single lmgr call
256 * at the top of the recursion.
258 if (owner == TopTransactionResourceOwner)
259 ProcReleaseLocks(isCommit);
264 * Release locks retail. Note that if we are committing a
265 * subtransaction, we do NOT release its locks yet, but transfer
266 * them to the parent.
268 Assert(owner->parent != NULL);
270 LockReassignCurrentOwner();
272 LockReleaseCurrentOwner();
275 else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
277 /* Release catcache references */
281 * For a top-level xact we are going to release all references,
282 * so just do a single catcache call at the top of the recursion.
284 if (owner == TopTransactionResourceOwner)
285 AtEOXact_CatCache(isCommit);
286 /* Mark object as owning no catrefs, just for sanity */
288 owner->ncatlistrefs = 0;
293 * Release catcache refs retail. Note that ReleaseCatCache will
294 * remove the catref entry from my list, so I just have to iterate
295 * till there are none. Ditto for catcache lists.
297 while (owner->ncatrefs > 0)
298 ReleaseCatCache(owner->catrefs[owner->ncatrefs - 1]);
299 while (owner->ncatlistrefs > 0)
300 ReleaseCatCacheList(owner->catlistrefs[owner->ncatlistrefs - 1]);
302 /* Clean up index scans too */
303 ReleaseResources_gist();
304 ReleaseResources_hash();
305 ReleaseResources_rtree();
308 /* Let add-on modules get a chance too */
309 for (item = ResourceRelease_callbacks; item; item = item->next)
310 (*item->callback) (phase, isCommit, isTopLevel, item->arg);
312 CurrentResourceOwner = save;
316 * ResourceOwnerDelete
317 * Delete an owner object and its descendants.
319 * The caller must have already released all resources in the object tree.
322 ResourceOwnerDelete(ResourceOwner owner)
324 /* We had better not be deleting CurrentResourceOwner ... */
325 Assert(owner != CurrentResourceOwner);
327 /* And it better not own any resources, either */
328 Assert(owner->nbuffers == 0);
329 Assert(owner->ncatrefs == 0);
330 Assert(owner->ncatlistrefs == 0);
331 Assert(owner->nrelrefs == 0);
334 * Delete children. The recursive call will delink the child
335 * from me, so just iterate as long as there is a child.
337 while (owner->firstchild != NULL)
338 ResourceOwnerDelete(owner->firstchild);
341 * We delink the owner from its parent before deleting it, so that
342 * if there's an error we won't have deleted/busted owners still
343 * attached to the owner tree. Better a leak than a crash.
345 ResourceOwnerNewParent(owner, NULL);
347 /* And free the object. */
349 pfree(owner->buffers);
351 pfree(owner->catrefs);
352 if (owner->catlistrefs)
353 pfree(owner->catlistrefs);
355 pfree(owner->relrefs);
361 * Fetch parent of a ResourceOwner (returns NULL if top-level owner)
364 ResourceOwnerGetParent(ResourceOwner owner)
366 return owner->parent;
370 * Reassign a ResourceOwner to have a new parent
373 ResourceOwnerNewParent(ResourceOwner owner,
374 ResourceOwner newparent)
376 ResourceOwner oldparent = owner->parent;
380 if (owner == oldparent->firstchild)
381 oldparent->firstchild = owner->nextchild;
386 for (child = oldparent->firstchild; child; child = child->nextchild)
388 if (owner == child->nextchild)
390 child->nextchild = owner->nextchild;
399 Assert(owner != newparent);
400 owner->parent = newparent;
401 owner->nextchild = newparent->firstchild;
402 newparent->firstchild = owner;
406 owner->parent = NULL;
407 owner->nextchild = NULL;
412 * Register or deregister callback functions for resource cleanup
414 * These functions are intended for use by dynamically loaded modules.
415 * For built-in modules we generally just hardwire the appropriate calls.
417 * Note that the callback occurs post-commit or post-abort, so the callback
418 * functions can only do noncritical cleanup.
421 RegisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
423 ResourceReleaseCallbackItem *item;
425 item = (ResourceReleaseCallbackItem *)
426 MemoryContextAlloc(TopMemoryContext,
427 sizeof(ResourceReleaseCallbackItem));
428 item->callback = callback;
430 item->next = ResourceRelease_callbacks;
431 ResourceRelease_callbacks = item;
435 UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
437 ResourceReleaseCallbackItem *item;
438 ResourceReleaseCallbackItem *prev;
441 for (item = ResourceRelease_callbacks; item; prev = item, item = item->next)
443 if (item->callback == callback && item->arg == arg)
446 prev->next = item->next;
448 ResourceRelease_callbacks = item->next;
457 * Make sure there is room for at least one more entry in a ResourceOwner's
460 * This is separate from actually inserting an entry because if we run out
461 * of memory, it's critical to do so *before* acquiring the resource.
463 * We allow the case owner == NULL because the bufmgr is sometimes invoked
464 * outside any transaction (for example, in the bgwriter).
467 ResourceOwnerEnlargeBuffers(ResourceOwner owner)
472 owner->nbuffers < owner->maxbuffers)
473 return; /* nothing to do */
475 if (owner->buffers == NULL)
478 owner->buffers = (Buffer *)
479 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(Buffer));
480 owner->maxbuffers = newmax;
484 newmax = owner->maxbuffers * 2;
485 owner->buffers = (Buffer *)
486 repalloc(owner->buffers, newmax * sizeof(Buffer));
487 owner->maxbuffers = newmax;
492 * Remember that a buffer pin is owned by a ResourceOwner
494 * Caller must have previously done ResourceOwnerEnlargeBuffers()
496 * We allow the case owner == NULL because the bufmgr is sometimes invoked
497 * outside any transaction (for example, in the bgwriter).
500 ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
504 Assert(owner->nbuffers < owner->maxbuffers);
505 owner->buffers[owner->nbuffers] = buffer;
511 * Forget that a buffer pin is owned by a ResourceOwner
513 * We allow the case owner == NULL because the bufmgr is sometimes invoked
514 * outside any transaction (for example, in the bgwriter).
517 ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
521 Buffer *buffers = owner->buffers;
522 int nb1 = owner->nbuffers - 1;
526 * Scan back-to-front because it's more likely we are releasing
527 * a recently pinned buffer. This isn't always the case of course,
528 * but it's the way to bet.
530 for (i = nb1; i >= 0; i--)
532 if (buffers[i] == buffer)
536 buffers[i] = buffers[i + 1];
539 owner->nbuffers = nb1;
543 elog(ERROR, "buffer %d is not owned by resource owner %s",
544 buffer, owner->name);
549 * Make sure there is room for at least one more entry in a ResourceOwner's
550 * catcache reference array.
552 * This is separate from actually inserting an entry because if we run out
553 * of memory, it's critical to do so *before* acquiring the resource.
556 ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner)
560 if (owner->ncatrefs < owner->maxcatrefs)
561 return; /* nothing to do */
563 if (owner->catrefs == NULL)
566 owner->catrefs = (HeapTuple *)
567 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(HeapTuple));
568 owner->maxcatrefs = newmax;
572 newmax = owner->maxcatrefs * 2;
573 owner->catrefs = (HeapTuple *)
574 repalloc(owner->catrefs, newmax * sizeof(HeapTuple));
575 owner->maxcatrefs = newmax;
580 * Remember that a catcache reference is owned by a ResourceOwner
582 * Caller must have previously done ResourceOwnerEnlargeCatCacheRefs()
585 ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple)
587 Assert(owner->ncatrefs < owner->maxcatrefs);
588 owner->catrefs[owner->ncatrefs] = tuple;
593 * Forget that a catcache reference is owned by a ResourceOwner
596 ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple)
598 HeapTuple *catrefs = owner->catrefs;
599 int nc1 = owner->ncatrefs - 1;
602 for (i = nc1; i >= 0; i--)
604 if (catrefs[i] == tuple)
608 catrefs[i] = catrefs[i + 1];
611 owner->ncatrefs = nc1;
615 elog(ERROR, "catcache reference %p is not owned by resource owner %s",
620 * Make sure there is room for at least one more entry in a ResourceOwner's
621 * catcache-list reference array.
623 * This is separate from actually inserting an entry because if we run out
624 * of memory, it's critical to do so *before* acquiring the resource.
627 ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner)
631 if (owner->ncatlistrefs < owner->maxcatlistrefs)
632 return; /* nothing to do */
634 if (owner->catlistrefs == NULL)
637 owner->catlistrefs = (CatCList **)
638 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(CatCList *));
639 owner->maxcatlistrefs = newmax;
643 newmax = owner->maxcatlistrefs * 2;
644 owner->catlistrefs = (CatCList **)
645 repalloc(owner->catlistrefs, newmax * sizeof(CatCList *));
646 owner->maxcatlistrefs = newmax;
651 * Remember that a catcache-list reference is owned by a ResourceOwner
653 * Caller must have previously done ResourceOwnerEnlargeCatCacheListRefs()
656 ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
658 Assert(owner->ncatlistrefs < owner->maxcatlistrefs);
659 owner->catlistrefs[owner->ncatlistrefs] = list;
660 owner->ncatlistrefs++;
664 * Forget that a catcache-list reference is owned by a ResourceOwner
667 ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list)
669 CatCList **catlistrefs = owner->catlistrefs;
670 int nc1 = owner->ncatlistrefs - 1;
673 for (i = nc1; i >= 0; i--)
675 if (catlistrefs[i] == list)
679 catlistrefs[i] = catlistrefs[i + 1];
682 owner->ncatlistrefs = nc1;
686 elog(ERROR, "catcache list reference %p is not owned by resource owner %s",
691 * Make sure there is room for at least one more entry in a ResourceOwner's
692 * relcache reference array.
694 * This is separate from actually inserting an entry because if we run out
695 * of memory, it's critical to do so *before* acquiring the resource.
698 ResourceOwnerEnlargeRelationRefs(ResourceOwner owner)
702 if (owner->nrelrefs < owner->maxrelrefs)
703 return; /* nothing to do */
705 if (owner->relrefs == NULL)
708 owner->relrefs = (Relation *)
709 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(Relation));
710 owner->maxrelrefs = newmax;
714 newmax = owner->maxrelrefs * 2;
715 owner->relrefs = (Relation *)
716 repalloc(owner->relrefs, newmax * sizeof(Relation));
717 owner->maxrelrefs = newmax;
722 * Remember that a relcache reference is owned by a ResourceOwner
724 * Caller must have previously done ResourceOwnerEnlargeRelationRefs()
727 ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel)
729 Assert(owner->nrelrefs < owner->maxrelrefs);
730 owner->relrefs[owner->nrelrefs] = rel;
735 * Forget that a relcache reference is owned by a ResourceOwner
738 ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
740 Relation *relrefs = owner->relrefs;
741 int nr1 = owner->nrelrefs - 1;
744 for (i = nr1; i >= 0; i--)
746 if (relrefs[i] == rel)
750 relrefs[i] = relrefs[i + 1];
753 owner->nrelrefs = nr1;
757 elog(ERROR, "relcache reference %s is not owned by resource owner %s",
758 RelationGetRelationName(rel), owner->name);