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-2007, 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.25 2007/11/15 21:14:41 momjian Exp $
19 *-------------------------------------------------------------------------
23 #include "access/hash.h"
24 #include "storage/proc.h"
25 #include "utils/memutils.h"
26 #include "utils/resowner.h"
27 #include "utils/relcache.h"
31 * ResourceOwner objects look like this
33 typedef struct ResourceOwnerData
35 ResourceOwner parent; /* NULL if no parent (toplevel owner) */
36 ResourceOwner firstchild; /* head of linked list of children */
37 ResourceOwner nextchild; /* next child of same parent */
38 const char *name; /* name (just for debugging) */
40 /* We have built-in support for remembering owned buffers */
41 int nbuffers; /* number of owned buffer pins */
42 Buffer *buffers; /* dynamically allocated array */
43 int maxbuffers; /* currently allocated array size */
45 /* We have built-in support for remembering catcache references */
46 int ncatrefs; /* number of owned catcache pins */
47 HeapTuple *catrefs; /* dynamically allocated array */
48 int maxcatrefs; /* currently allocated array size */
50 int ncatlistrefs; /* number of owned catcache-list pins */
51 CatCList **catlistrefs; /* dynamically allocated array */
52 int maxcatlistrefs; /* currently allocated array size */
54 /* We have built-in support for remembering relcache references */
55 int nrelrefs; /* number of owned relcache pins */
56 Relation *relrefs; /* dynamically allocated array */
57 int maxrelrefs; /* currently allocated array size */
59 /* We have built-in support for remembering plancache references */
60 int nplanrefs; /* number of owned plancache pins */
61 CachedPlan **planrefs; /* dynamically allocated array */
62 int maxplanrefs; /* currently allocated array size */
64 /* We have built-in support for remembering tupdesc references */
65 int ntupdescs; /* number of owned tupdesc references */
66 TupleDesc *tupdescs; /* dynamically allocated array */
67 int maxtupdescs; /* currently allocated array size */
71 /*****************************************************************************
73 *****************************************************************************/
75 ResourceOwner CurrentResourceOwner = NULL;
76 ResourceOwner CurTransactionResourceOwner = NULL;
77 ResourceOwner TopTransactionResourceOwner = NULL;
80 * List of add-on callbacks for resource releasing
82 typedef struct ResourceReleaseCallbackItem
84 struct ResourceReleaseCallbackItem *next;
85 ResourceReleaseCallback callback;
87 } ResourceReleaseCallbackItem;
89 static ResourceReleaseCallbackItem *ResourceRelease_callbacks = NULL;
92 /* Internal routines */
93 static void ResourceOwnerReleaseInternal(ResourceOwner owner,
94 ResourceReleasePhase phase,
97 static void PrintRelCacheLeakWarning(Relation rel);
98 static void PrintPlanCacheLeakWarning(CachedPlan * plan);
99 static void PrintTupleDescLeakWarning(TupleDesc tupdesc);
102 /*****************************************************************************
103 * EXPORTED ROUTINES *
104 *****************************************************************************/
108 * ResourceOwnerCreate
109 * Create an empty ResourceOwner.
111 * All ResourceOwner objects are kept in TopMemoryContext, since they should
112 * only be freed explicitly.
115 ResourceOwnerCreate(ResourceOwner parent, const char *name)
119 owner = (ResourceOwner) MemoryContextAllocZero(TopMemoryContext,
120 sizeof(ResourceOwnerData));
125 owner->parent = parent;
126 owner->nextchild = parent->firstchild;
127 parent->firstchild = owner;
134 * ResourceOwnerRelease
135 * Release all resources owned by a ResourceOwner and its descendants,
136 * but don't delete the owner objects themselves.
138 * Note that this executes just one phase of release, and so typically
139 * must be called three times. We do it this way because (a) we want to
140 * do all the recursion separately for each phase, thereby preserving
141 * the needed order of operations; and (b) xact.c may have other operations
142 * to do between the phases.
144 * phase: release phase to execute
145 * isCommit: true for successful completion of a query or transaction,
146 * false for unsuccessful
147 * isTopLevel: true if completing a main transaction, else false
149 * isCommit is passed because some modules may expect that their resources
150 * were all released already if the transaction or portal finished normally.
151 * If so it is reasonable to give a warning (NOT an error) should any
152 * unreleased resources be present. When isCommit is false, such warnings
153 * are generally inappropriate.
155 * isTopLevel is passed when we are releasing TopTransactionResourceOwner
156 * at completion of a main transaction. This generally means that *all*
157 * resources will be released, and so we can optimize things a bit.
160 ResourceOwnerRelease(ResourceOwner owner,
161 ResourceReleasePhase phase,
165 /* Rather than PG_TRY at every level of recursion, set it up once */
168 save = CurrentResourceOwner;
171 ResourceOwnerReleaseInternal(owner, phase, isCommit, isTopLevel);
175 CurrentResourceOwner = save;
179 CurrentResourceOwner = save;
183 ResourceOwnerReleaseInternal(ResourceOwner owner,
184 ResourceReleasePhase phase,
190 ResourceReleaseCallbackItem *item;
192 /* Recurse to handle descendants */
193 for (child = owner->firstchild; child != NULL; child = child->nextchild)
194 ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel);
197 * Make CurrentResourceOwner point to me, so that ReleaseBuffer etc don't
198 * get confused. We needn't PG_TRY here because the outermost level will
199 * fix it on error abort.
201 save = CurrentResourceOwner;
202 CurrentResourceOwner = owner;
204 if (phase == RESOURCE_RELEASE_BEFORE_LOCKS)
207 * Release buffer pins. Note that ReleaseBuffer will remove the
208 * buffer entry from my list, so I just have to iterate till there are
211 * During a commit, there shouldn't be any remaining pins --- that
212 * would indicate failure to clean up the executor correctly --- so
213 * issue warnings. In the abort case, just clean up quietly.
215 * We are careful to do the releasing back-to-front, so as to avoid
216 * O(N^2) behavior in ResourceOwnerForgetBuffer().
218 while (owner->nbuffers > 0)
221 PrintBufferLeakWarning(owner->buffers[owner->nbuffers - 1]);
222 ReleaseBuffer(owner->buffers[owner->nbuffers - 1]);
226 * Release relcache references. Note that RelationClose will remove
227 * the relref entry from my list, so I just have to iterate till there
230 * As with buffer pins, warn if any are left at commit time, and
231 * release back-to-front for speed.
233 while (owner->nrelrefs > 0)
236 PrintRelCacheLeakWarning(owner->relrefs[owner->nrelrefs - 1]);
237 RelationClose(owner->relrefs[owner->nrelrefs - 1]);
240 else if (phase == RESOURCE_RELEASE_LOCKS)
245 * For a top-level xact we are going to release all locks (or at
246 * least all non-session locks), so just do a single lmgr call at
247 * the top of the recursion.
249 if (owner == TopTransactionResourceOwner)
250 ProcReleaseLocks(isCommit);
255 * Release locks retail. Note that if we are committing a
256 * subtransaction, we do NOT release its locks yet, but transfer
257 * them to the parent.
259 Assert(owner->parent != NULL);
261 LockReassignCurrentOwner();
263 LockReleaseCurrentOwner();
266 else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
269 * Release catcache references. Note that ReleaseCatCache will remove
270 * the catref entry from my list, so I just have to iterate till there
273 * As with buffer pins, warn if any are left at commit time, and
274 * release back-to-front for speed.
276 while (owner->ncatrefs > 0)
279 PrintCatCacheLeakWarning(owner->catrefs[owner->ncatrefs - 1]);
280 ReleaseCatCache(owner->catrefs[owner->ncatrefs - 1]);
282 /* Ditto for catcache lists */
283 while (owner->ncatlistrefs > 0)
286 PrintCatCacheListLeakWarning(owner->catlistrefs[owner->ncatlistrefs - 1]);
287 ReleaseCatCacheList(owner->catlistrefs[owner->ncatlistrefs - 1]);
289 /* Ditto for plancache references */
290 while (owner->nplanrefs > 0)
293 PrintPlanCacheLeakWarning(owner->planrefs[owner->nplanrefs - 1]);
294 ReleaseCachedPlan(owner->planrefs[owner->nplanrefs - 1], true);
296 /* Ditto for tupdesc references */
297 while (owner->ntupdescs > 0)
300 PrintTupleDescLeakWarning(owner->tupdescs[owner->ntupdescs - 1]);
301 DecrTupleDescRefCount(owner->tupdescs[owner->ntupdescs - 1]);
304 /* Clean up index scans too */
305 ReleaseResources_hash();
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);
332 Assert(owner->nplanrefs == 0);
333 Assert(owner->ntupdescs == 0);
336 * Delete children. The recursive call will delink the child from me, so
337 * just iterate as long as there is a child.
339 while (owner->firstchild != NULL)
340 ResourceOwnerDelete(owner->firstchild);
343 * We delink the owner from its parent before deleting it, so that if
344 * there's an error we won't have deleted/busted owners still attached to
345 * the owner tree. Better a leak than a crash.
347 ResourceOwnerNewParent(owner, NULL);
349 /* And free the object. */
351 pfree(owner->buffers);
353 pfree(owner->catrefs);
354 if (owner->catlistrefs)
355 pfree(owner->catlistrefs);
357 pfree(owner->relrefs);
359 pfree(owner->planrefs);
361 pfree(owner->tupdescs);
367 * Fetch parent of a ResourceOwner (returns NULL if top-level owner)
370 ResourceOwnerGetParent(ResourceOwner owner)
372 return owner->parent;
376 * Reassign a ResourceOwner to have a new parent
379 ResourceOwnerNewParent(ResourceOwner owner,
380 ResourceOwner newparent)
382 ResourceOwner oldparent = owner->parent;
386 if (owner == oldparent->firstchild)
387 oldparent->firstchild = owner->nextchild;
392 for (child = oldparent->firstchild; child; child = child->nextchild)
394 if (owner == child->nextchild)
396 child->nextchild = owner->nextchild;
405 Assert(owner != newparent);
406 owner->parent = newparent;
407 owner->nextchild = newparent->firstchild;
408 newparent->firstchild = owner;
412 owner->parent = NULL;
413 owner->nextchild = NULL;
418 * Register or deregister callback functions for resource cleanup
420 * These functions are intended for use by dynamically loaded modules.
421 * For built-in modules we generally just hardwire the appropriate calls.
423 * Note that the callback occurs post-commit or post-abort, so the callback
424 * functions can only do noncritical cleanup.
427 RegisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
429 ResourceReleaseCallbackItem *item;
431 item = (ResourceReleaseCallbackItem *)
432 MemoryContextAlloc(TopMemoryContext,
433 sizeof(ResourceReleaseCallbackItem));
434 item->callback = callback;
436 item->next = ResourceRelease_callbacks;
437 ResourceRelease_callbacks = item;
441 UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
443 ResourceReleaseCallbackItem *item;
444 ResourceReleaseCallbackItem *prev;
447 for (item = ResourceRelease_callbacks; item; prev = item, item = item->next)
449 if (item->callback == callback && item->arg == arg)
452 prev->next = item->next;
454 ResourceRelease_callbacks = item->next;
463 * Make sure there is room for at least one more entry in a ResourceOwner's
466 * This is separate from actually inserting an entry because if we run out
467 * of memory, it's critical to do so *before* acquiring the resource.
469 * We allow the case owner == NULL because the bufmgr is sometimes invoked
470 * outside any transaction (for example, during WAL recovery).
473 ResourceOwnerEnlargeBuffers(ResourceOwner owner)
478 owner->nbuffers < owner->maxbuffers)
479 return; /* nothing to do */
481 if (owner->buffers == NULL)
484 owner->buffers = (Buffer *)
485 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(Buffer));
486 owner->maxbuffers = newmax;
490 newmax = owner->maxbuffers * 2;
491 owner->buffers = (Buffer *)
492 repalloc(owner->buffers, newmax * sizeof(Buffer));
493 owner->maxbuffers = newmax;
498 * Remember that a buffer pin is owned by a ResourceOwner
500 * Caller must have previously done ResourceOwnerEnlargeBuffers()
502 * We allow the case owner == NULL because the bufmgr is sometimes invoked
503 * outside any transaction (for example, during WAL recovery).
506 ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
510 Assert(owner->nbuffers < owner->maxbuffers);
511 owner->buffers[owner->nbuffers] = buffer;
517 * Forget that a buffer pin is owned by a ResourceOwner
519 * We allow the case owner == NULL because the bufmgr is sometimes invoked
520 * outside any transaction (for example, during WAL recovery).
523 ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
527 Buffer *buffers = owner->buffers;
528 int nb1 = owner->nbuffers - 1;
532 * Scan back-to-front because it's more likely we are releasing a
533 * recently pinned buffer. This isn't always the case of course, but
534 * it's the way to bet.
536 for (i = nb1; i >= 0; i--)
538 if (buffers[i] == buffer)
542 buffers[i] = buffers[i + 1];
545 owner->nbuffers = nb1;
549 elog(ERROR, "buffer %d is not owned by resource owner %s",
550 buffer, owner->name);
555 * Make sure there is room for at least one more entry in a ResourceOwner's
556 * catcache reference array.
558 * This is separate from actually inserting an entry because if we run out
559 * of memory, it's critical to do so *before* acquiring the resource.
562 ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner)
566 if (owner->ncatrefs < owner->maxcatrefs)
567 return; /* nothing to do */
569 if (owner->catrefs == NULL)
572 owner->catrefs = (HeapTuple *)
573 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(HeapTuple));
574 owner->maxcatrefs = newmax;
578 newmax = owner->maxcatrefs * 2;
579 owner->catrefs = (HeapTuple *)
580 repalloc(owner->catrefs, newmax * sizeof(HeapTuple));
581 owner->maxcatrefs = newmax;
586 * Remember that a catcache reference is owned by a ResourceOwner
588 * Caller must have previously done ResourceOwnerEnlargeCatCacheRefs()
591 ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple)
593 Assert(owner->ncatrefs < owner->maxcatrefs);
594 owner->catrefs[owner->ncatrefs] = tuple;
599 * Forget that a catcache reference is owned by a ResourceOwner
602 ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple)
604 HeapTuple *catrefs = owner->catrefs;
605 int nc1 = owner->ncatrefs - 1;
608 for (i = nc1; i >= 0; i--)
610 if (catrefs[i] == tuple)
614 catrefs[i] = catrefs[i + 1];
617 owner->ncatrefs = nc1;
621 elog(ERROR, "catcache reference %p is not owned by resource owner %s",
626 * Make sure there is room for at least one more entry in a ResourceOwner's
627 * catcache-list reference array.
629 * This is separate from actually inserting an entry because if we run out
630 * of memory, it's critical to do so *before* acquiring the resource.
633 ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner)
637 if (owner->ncatlistrefs < owner->maxcatlistrefs)
638 return; /* nothing to do */
640 if (owner->catlistrefs == NULL)
643 owner->catlistrefs = (CatCList **)
644 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(CatCList *));
645 owner->maxcatlistrefs = newmax;
649 newmax = owner->maxcatlistrefs * 2;
650 owner->catlistrefs = (CatCList **)
651 repalloc(owner->catlistrefs, newmax * sizeof(CatCList *));
652 owner->maxcatlistrefs = newmax;
657 * Remember that a catcache-list reference is owned by a ResourceOwner
659 * Caller must have previously done ResourceOwnerEnlargeCatCacheListRefs()
662 ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
664 Assert(owner->ncatlistrefs < owner->maxcatlistrefs);
665 owner->catlistrefs[owner->ncatlistrefs] = list;
666 owner->ncatlistrefs++;
670 * Forget that a catcache-list reference is owned by a ResourceOwner
673 ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list)
675 CatCList **catlistrefs = owner->catlistrefs;
676 int nc1 = owner->ncatlistrefs - 1;
679 for (i = nc1; i >= 0; i--)
681 if (catlistrefs[i] == list)
685 catlistrefs[i] = catlistrefs[i + 1];
688 owner->ncatlistrefs = nc1;
692 elog(ERROR, "catcache list reference %p is not owned by resource owner %s",
697 * Make sure there is room for at least one more entry in a ResourceOwner's
698 * relcache reference array.
700 * This is separate from actually inserting an entry because if we run out
701 * of memory, it's critical to do so *before* acquiring the resource.
704 ResourceOwnerEnlargeRelationRefs(ResourceOwner owner)
708 if (owner->nrelrefs < owner->maxrelrefs)
709 return; /* nothing to do */
711 if (owner->relrefs == NULL)
714 owner->relrefs = (Relation *)
715 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(Relation));
716 owner->maxrelrefs = newmax;
720 newmax = owner->maxrelrefs * 2;
721 owner->relrefs = (Relation *)
722 repalloc(owner->relrefs, newmax * sizeof(Relation));
723 owner->maxrelrefs = newmax;
728 * Remember that a relcache reference is owned by a ResourceOwner
730 * Caller must have previously done ResourceOwnerEnlargeRelationRefs()
733 ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel)
735 Assert(owner->nrelrefs < owner->maxrelrefs);
736 owner->relrefs[owner->nrelrefs] = rel;
741 * Forget that a relcache reference is owned by a ResourceOwner
744 ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
746 Relation *relrefs = owner->relrefs;
747 int nr1 = owner->nrelrefs - 1;
750 for (i = nr1; i >= 0; i--)
752 if (relrefs[i] == rel)
756 relrefs[i] = relrefs[i + 1];
759 owner->nrelrefs = nr1;
763 elog(ERROR, "relcache reference %s is not owned by resource owner %s",
764 RelationGetRelationName(rel), owner->name);
768 * Debugging subroutine
771 PrintRelCacheLeakWarning(Relation rel)
773 elog(WARNING, "relcache reference leak: relation \"%s\" not closed",
774 RelationGetRelationName(rel));
778 * Make sure there is room for at least one more entry in a ResourceOwner's
779 * plancache reference array.
781 * This is separate from actually inserting an entry because if we run out
782 * of memory, it's critical to do so *before* acquiring the resource.
785 ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
789 if (owner->nplanrefs < owner->maxplanrefs)
790 return; /* nothing to do */
792 if (owner->planrefs == NULL)
795 owner->planrefs = (CachedPlan **)
796 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(CachedPlan *));
797 owner->maxplanrefs = newmax;
801 newmax = owner->maxplanrefs * 2;
802 owner->planrefs = (CachedPlan **)
803 repalloc(owner->planrefs, newmax * sizeof(CachedPlan *));
804 owner->maxplanrefs = newmax;
809 * Remember that a plancache reference is owned by a ResourceOwner
811 * Caller must have previously done ResourceOwnerEnlargePlanCacheRefs()
814 ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan * plan)
816 Assert(owner->nplanrefs < owner->maxplanrefs);
817 owner->planrefs[owner->nplanrefs] = plan;
822 * Forget that a plancache reference is owned by a ResourceOwner
825 ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan * plan)
827 CachedPlan **planrefs = owner->planrefs;
828 int np1 = owner->nplanrefs - 1;
831 for (i = np1; i >= 0; i--)
833 if (planrefs[i] == plan)
837 planrefs[i] = planrefs[i + 1];
840 owner->nplanrefs = np1;
844 elog(ERROR, "plancache reference %p is not owned by resource owner %s",
849 * Debugging subroutine
852 PrintPlanCacheLeakWarning(CachedPlan * plan)
854 elog(WARNING, "plancache reference leak: plan %p not closed", plan);
858 * Make sure there is room for at least one more entry in a ResourceOwner's
859 * tupdesc reference array.
861 * This is separate from actually inserting an entry because if we run out
862 * of memory, it's critical to do so *before* acquiring the resource.
865 ResourceOwnerEnlargeTupleDescs(ResourceOwner owner)
869 if (owner->ntupdescs < owner->maxtupdescs)
870 return; /* nothing to do */
872 if (owner->tupdescs == NULL)
875 owner->tupdescs = (TupleDesc *)
876 MemoryContextAlloc(TopMemoryContext, newmax * sizeof(TupleDesc));
877 owner->maxtupdescs = newmax;
881 newmax = owner->maxtupdescs * 2;
882 owner->tupdescs = (TupleDesc *)
883 repalloc(owner->tupdescs, newmax * sizeof(TupleDesc));
884 owner->maxtupdescs = newmax;
889 * Remember that a tupdesc reference is owned by a ResourceOwner
891 * Caller must have previously done ResourceOwnerEnlargeTupleDescs()
894 ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
896 Assert(owner->ntupdescs < owner->maxtupdescs);
897 owner->tupdescs[owner->ntupdescs] = tupdesc;
902 * Forget that a tupdesc reference is owned by a ResourceOwner
905 ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
907 TupleDesc *tupdescs = owner->tupdescs;
908 int nt1 = owner->ntupdescs - 1;
911 for (i = nt1; i >= 0; i--)
913 if (tupdescs[i] == tupdesc)
917 tupdescs[i] = tupdescs[i + 1];
920 owner->ntupdescs = nt1;
924 elog(ERROR, "tupdesc reference %p is not owned by resource owner %s",
925 tupdesc, owner->name);
929 * Debugging subroutine
932 PrintTupleDescLeakWarning(TupleDesc tupdesc)
935 "TupleDesc reference leak: TupleDesc %p (%u,%d) still referenced",
936 tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);