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-2009, PostgreSQL Global Development Group
13 * Portions Copyright (c) 1994, Regents of the University of California
19 *-------------------------------------------------------------------------
23 #include "access/hash.h"
24 #include "storage/bufmgr.h"
25 #include "storage/proc.h"
26 #include "utils/memutils.h"
27 #include "utils/rel.h"
28 #include "utils/resowner.h"
29 #include "utils/snapmgr.h"
33 * ResourceOwner objects look like this
35 typedef struct ResourceOwnerData
37 ResourceOwner parent
; /* NULL if no parent (toplevel owner) */
38 ResourceOwner firstchild
; /* head of linked list of children */
39 ResourceOwner nextchild
; /* next child of same parent */
40 const char *name
; /* name (just for debugging) */
42 /* We have built-in support for remembering owned buffers */
43 int nbuffers
; /* number of owned buffer pins */
44 Buffer
*buffers
; /* dynamically allocated array */
45 int maxbuffers
; /* currently allocated array size */
47 /* We have built-in support for remembering catcache references */
48 int ncatrefs
; /* number of owned catcache pins */
49 HeapTuple
*catrefs
; /* dynamically allocated array */
50 int maxcatrefs
; /* currently allocated array size */
52 int ncatlistrefs
; /* number of owned catcache-list pins */
53 CatCList
**catlistrefs
; /* dynamically allocated array */
54 int maxcatlistrefs
; /* currently allocated array size */
56 /* We have built-in support for remembering relcache references */
57 int nrelrefs
; /* number of owned relcache pins */
58 Relation
*relrefs
; /* dynamically allocated array */
59 int maxrelrefs
; /* currently allocated array size */
61 /* We have built-in support for remembering plancache references */
62 int nplanrefs
; /* number of owned plancache pins */
63 CachedPlan
**planrefs
; /* dynamically allocated array */
64 int maxplanrefs
; /* currently allocated array size */
66 /* We have built-in support for remembering tupdesc references */
67 int ntupdescs
; /* number of owned tupdesc references */
68 TupleDesc
*tupdescs
; /* dynamically allocated array */
69 int maxtupdescs
; /* currently allocated array size */
71 /* We have built-in support for remembering snapshot references */
72 int nsnapshots
; /* number of owned snapshot references */
73 Snapshot
*snapshots
; /* dynamically allocated array */
74 int maxsnapshots
; /* currently allocated array size */
78 /*****************************************************************************
80 *****************************************************************************/
82 ResourceOwner CurrentResourceOwner
= NULL
;
83 ResourceOwner CurTransactionResourceOwner
= NULL
;
84 ResourceOwner TopTransactionResourceOwner
= NULL
;
87 * List of add-on callbacks for resource releasing
89 typedef struct ResourceReleaseCallbackItem
91 struct ResourceReleaseCallbackItem
*next
;
92 ResourceReleaseCallback callback
;
94 } ResourceReleaseCallbackItem
;
96 static ResourceReleaseCallbackItem
*ResourceRelease_callbacks
= NULL
;
99 /* Internal routines */
100 static void ResourceOwnerReleaseInternal(ResourceOwner owner
,
101 ResourceReleasePhase phase
,
104 static void PrintRelCacheLeakWarning(Relation rel
);
105 static void PrintPlanCacheLeakWarning(CachedPlan
*plan
);
106 static void PrintTupleDescLeakWarning(TupleDesc tupdesc
);
107 static void PrintSnapshotLeakWarning(Snapshot snapshot
);
110 /*****************************************************************************
111 * EXPORTED ROUTINES *
112 *****************************************************************************/
116 * ResourceOwnerCreate
117 * Create an empty ResourceOwner.
119 * All ResourceOwner objects are kept in TopMemoryContext, since they should
120 * only be freed explicitly.
123 ResourceOwnerCreate(ResourceOwner parent
, const char *name
)
127 owner
= (ResourceOwner
) MemoryContextAllocZero(TopMemoryContext
,
128 sizeof(ResourceOwnerData
));
133 owner
->parent
= parent
;
134 owner
->nextchild
= parent
->firstchild
;
135 parent
->firstchild
= owner
;
142 * ResourceOwnerRelease
143 * Release all resources owned by a ResourceOwner and its descendants,
144 * but don't delete the owner objects themselves.
146 * Note that this executes just one phase of release, and so typically
147 * must be called three times. We do it this way because (a) we want to
148 * do all the recursion separately for each phase, thereby preserving
149 * the needed order of operations; and (b) xact.c may have other operations
150 * to do between the phases.
152 * phase: release phase to execute
153 * isCommit: true for successful completion of a query or transaction,
154 * false for unsuccessful
155 * isTopLevel: true if completing a main transaction, else false
157 * isCommit is passed because some modules may expect that their resources
158 * were all released already if the transaction or portal finished normally.
159 * If so it is reasonable to give a warning (NOT an error) should any
160 * unreleased resources be present. When isCommit is false, such warnings
161 * are generally inappropriate.
163 * isTopLevel is passed when we are releasing TopTransactionResourceOwner
164 * at completion of a main transaction. This generally means that *all*
165 * resources will be released, and so we can optimize things a bit.
168 ResourceOwnerRelease(ResourceOwner owner
,
169 ResourceReleasePhase phase
,
173 /* Rather than PG_TRY at every level of recursion, set it up once */
176 save
= CurrentResourceOwner
;
179 ResourceOwnerReleaseInternal(owner
, phase
, isCommit
, isTopLevel
);
183 CurrentResourceOwner
= save
;
187 CurrentResourceOwner
= save
;
191 ResourceOwnerReleaseInternal(ResourceOwner owner
,
192 ResourceReleasePhase phase
,
198 ResourceReleaseCallbackItem
*item
;
200 /* Recurse to handle descendants */
201 for (child
= owner
->firstchild
; child
!= NULL
; child
= child
->nextchild
)
202 ResourceOwnerReleaseInternal(child
, phase
, isCommit
, isTopLevel
);
205 * Make CurrentResourceOwner point to me, so that ReleaseBuffer etc don't
206 * get confused. We needn't PG_TRY here because the outermost level will
207 * fix it on error abort.
209 save
= CurrentResourceOwner
;
210 CurrentResourceOwner
= owner
;
212 if (phase
== RESOURCE_RELEASE_BEFORE_LOCKS
)
215 * Release buffer pins. Note that ReleaseBuffer will remove the
216 * buffer entry from my list, so I just have to iterate till there are
219 * During a commit, there shouldn't be any remaining pins --- that
220 * would indicate failure to clean up the executor correctly --- so
221 * issue warnings. In the abort case, just clean up quietly.
223 * We are careful to do the releasing back-to-front, so as to avoid
224 * O(N^2) behavior in ResourceOwnerForgetBuffer().
226 while (owner
->nbuffers
> 0)
229 PrintBufferLeakWarning(owner
->buffers
[owner
->nbuffers
- 1]);
230 ReleaseBuffer(owner
->buffers
[owner
->nbuffers
- 1]);
234 * Release relcache references. Note that RelationClose will remove
235 * the relref entry from my list, so I just have to iterate till there
238 * As with buffer pins, warn if any are left at commit time, and
239 * release back-to-front for speed.
241 while (owner
->nrelrefs
> 0)
244 PrintRelCacheLeakWarning(owner
->relrefs
[owner
->nrelrefs
- 1]);
245 RelationClose(owner
->relrefs
[owner
->nrelrefs
- 1]);
248 else if (phase
== RESOURCE_RELEASE_LOCKS
)
253 * For a top-level xact we are going to release all locks (or at
254 * least all non-session locks), so just do a single lmgr call at
255 * the top of the recursion.
257 if (owner
== TopTransactionResourceOwner
)
258 ProcReleaseLocks(isCommit
);
263 * Release locks retail. Note that if we are committing a
264 * subtransaction, we do NOT release its locks yet, but transfer
265 * them to the parent.
267 Assert(owner
->parent
!= NULL
);
269 LockReassignCurrentOwner();
271 LockReleaseCurrentOwner();
274 else if (phase
== RESOURCE_RELEASE_AFTER_LOCKS
)
277 * Release catcache references. Note that ReleaseCatCache will remove
278 * the catref entry from my list, so I just have to iterate till there
281 * As with buffer pins, warn if any are left at commit time, and
282 * release back-to-front for speed.
284 while (owner
->ncatrefs
> 0)
287 PrintCatCacheLeakWarning(owner
->catrefs
[owner
->ncatrefs
- 1]);
288 ReleaseCatCache(owner
->catrefs
[owner
->ncatrefs
- 1]);
290 /* Ditto for catcache lists */
291 while (owner
->ncatlistrefs
> 0)
294 PrintCatCacheListLeakWarning(owner
->catlistrefs
[owner
->ncatlistrefs
- 1]);
295 ReleaseCatCacheList(owner
->catlistrefs
[owner
->ncatlistrefs
- 1]);
297 /* Ditto for plancache references */
298 while (owner
->nplanrefs
> 0)
301 PrintPlanCacheLeakWarning(owner
->planrefs
[owner
->nplanrefs
- 1]);
302 ReleaseCachedPlan(owner
->planrefs
[owner
->nplanrefs
- 1], true);
304 /* Ditto for tupdesc references */
305 while (owner
->ntupdescs
> 0)
308 PrintTupleDescLeakWarning(owner
->tupdescs
[owner
->ntupdescs
- 1]);
309 DecrTupleDescRefCount(owner
->tupdescs
[owner
->ntupdescs
- 1]);
311 /* Ditto for snapshot references */
312 while (owner
->nsnapshots
> 0)
315 PrintSnapshotLeakWarning(owner
->snapshots
[owner
->nsnapshots
- 1]);
316 UnregisterSnapshot(owner
->snapshots
[owner
->nsnapshots
- 1]);
319 /* Clean up index scans too */
320 ReleaseResources_hash();
323 /* Let add-on modules get a chance too */
324 for (item
= ResourceRelease_callbacks
; item
; item
= item
->next
)
325 (*item
->callback
) (phase
, isCommit
, isTopLevel
, item
->arg
);
327 CurrentResourceOwner
= save
;
331 * ResourceOwnerDelete
332 * Delete an owner object and its descendants.
334 * The caller must have already released all resources in the object tree.
337 ResourceOwnerDelete(ResourceOwner owner
)
339 /* We had better not be deleting CurrentResourceOwner ... */
340 Assert(owner
!= CurrentResourceOwner
);
342 /* And it better not own any resources, either */
343 Assert(owner
->nbuffers
== 0);
344 Assert(owner
->ncatrefs
== 0);
345 Assert(owner
->ncatlistrefs
== 0);
346 Assert(owner
->nrelrefs
== 0);
347 Assert(owner
->nplanrefs
== 0);
348 Assert(owner
->ntupdescs
== 0);
349 Assert(owner
->nsnapshots
== 0);
352 * Delete children. The recursive call will delink the child from me, so
353 * just iterate as long as there is a child.
355 while (owner
->firstchild
!= NULL
)
356 ResourceOwnerDelete(owner
->firstchild
);
359 * We delink the owner from its parent before deleting it, so that if
360 * there's an error we won't have deleted/busted owners still attached to
361 * the owner tree. Better a leak than a crash.
363 ResourceOwnerNewParent(owner
, NULL
);
365 /* And free the object. */
367 pfree(owner
->buffers
);
369 pfree(owner
->catrefs
);
370 if (owner
->catlistrefs
)
371 pfree(owner
->catlistrefs
);
373 pfree(owner
->relrefs
);
375 pfree(owner
->planrefs
);
377 pfree(owner
->tupdescs
);
378 if (owner
->snapshots
)
379 pfree(owner
->snapshots
);
385 * Fetch parent of a ResourceOwner (returns NULL if top-level owner)
388 ResourceOwnerGetParent(ResourceOwner owner
)
390 return owner
->parent
;
394 * Reassign a ResourceOwner to have a new parent
397 ResourceOwnerNewParent(ResourceOwner owner
,
398 ResourceOwner newparent
)
400 ResourceOwner oldparent
= owner
->parent
;
404 if (owner
== oldparent
->firstchild
)
405 oldparent
->firstchild
= owner
->nextchild
;
410 for (child
= oldparent
->firstchild
; child
; child
= child
->nextchild
)
412 if (owner
== child
->nextchild
)
414 child
->nextchild
= owner
->nextchild
;
423 Assert(owner
!= newparent
);
424 owner
->parent
= newparent
;
425 owner
->nextchild
= newparent
->firstchild
;
426 newparent
->firstchild
= owner
;
430 owner
->parent
= NULL
;
431 owner
->nextchild
= NULL
;
436 * Register or deregister callback functions for resource cleanup
438 * These functions are intended for use by dynamically loaded modules.
439 * For built-in modules we generally just hardwire the appropriate calls.
441 * Note that the callback occurs post-commit or post-abort, so the callback
442 * functions can only do noncritical cleanup.
445 RegisterResourceReleaseCallback(ResourceReleaseCallback callback
, void *arg
)
447 ResourceReleaseCallbackItem
*item
;
449 item
= (ResourceReleaseCallbackItem
*)
450 MemoryContextAlloc(TopMemoryContext
,
451 sizeof(ResourceReleaseCallbackItem
));
452 item
->callback
= callback
;
454 item
->next
= ResourceRelease_callbacks
;
455 ResourceRelease_callbacks
= item
;
459 UnregisterResourceReleaseCallback(ResourceReleaseCallback callback
, void *arg
)
461 ResourceReleaseCallbackItem
*item
;
462 ResourceReleaseCallbackItem
*prev
;
465 for (item
= ResourceRelease_callbacks
; item
; prev
= item
, item
= item
->next
)
467 if (item
->callback
== callback
&& item
->arg
== arg
)
470 prev
->next
= item
->next
;
472 ResourceRelease_callbacks
= item
->next
;
481 * Make sure there is room for at least one more entry in a ResourceOwner's
484 * This is separate from actually inserting an entry because if we run out
485 * of memory, it's critical to do so *before* acquiring the resource.
487 * We allow the case owner == NULL because the bufmgr is sometimes invoked
488 * outside any transaction (for example, during WAL recovery).
491 ResourceOwnerEnlargeBuffers(ResourceOwner owner
)
496 owner
->nbuffers
< owner
->maxbuffers
)
497 return; /* nothing to do */
499 if (owner
->buffers
== NULL
)
502 owner
->buffers
= (Buffer
*)
503 MemoryContextAlloc(TopMemoryContext
, newmax
* sizeof(Buffer
));
504 owner
->maxbuffers
= newmax
;
508 newmax
= owner
->maxbuffers
* 2;
509 owner
->buffers
= (Buffer
*)
510 repalloc(owner
->buffers
, newmax
* sizeof(Buffer
));
511 owner
->maxbuffers
= newmax
;
516 * Remember that a buffer pin is owned by a ResourceOwner
518 * Caller must have previously done ResourceOwnerEnlargeBuffers()
520 * We allow the case owner == NULL because the bufmgr is sometimes invoked
521 * outside any transaction (for example, during WAL recovery).
524 ResourceOwnerRememberBuffer(ResourceOwner owner
, Buffer buffer
)
528 Assert(owner
->nbuffers
< owner
->maxbuffers
);
529 owner
->buffers
[owner
->nbuffers
] = buffer
;
535 * Forget that a buffer pin is owned by a ResourceOwner
537 * We allow the case owner == NULL because the bufmgr is sometimes invoked
538 * outside any transaction (for example, during WAL recovery).
541 ResourceOwnerForgetBuffer(ResourceOwner owner
, Buffer buffer
)
545 Buffer
*buffers
= owner
->buffers
;
546 int nb1
= owner
->nbuffers
- 1;
550 * Scan back-to-front because it's more likely we are releasing a
551 * recently pinned buffer. This isn't always the case of course, but
552 * it's the way to bet.
554 for (i
= nb1
; i
>= 0; i
--)
556 if (buffers
[i
] == buffer
)
560 buffers
[i
] = buffers
[i
+ 1];
563 owner
->nbuffers
= nb1
;
567 elog(ERROR
, "buffer %d is not owned by resource owner %s",
568 buffer
, owner
->name
);
573 * Make sure there is room for at least one more entry in a ResourceOwner's
574 * catcache reference array.
576 * This is separate from actually inserting an entry because if we run out
577 * of memory, it's critical to do so *before* acquiring the resource.
580 ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner
)
584 if (owner
->ncatrefs
< owner
->maxcatrefs
)
585 return; /* nothing to do */
587 if (owner
->catrefs
== NULL
)
590 owner
->catrefs
= (HeapTuple
*)
591 MemoryContextAlloc(TopMemoryContext
, newmax
* sizeof(HeapTuple
));
592 owner
->maxcatrefs
= newmax
;
596 newmax
= owner
->maxcatrefs
* 2;
597 owner
->catrefs
= (HeapTuple
*)
598 repalloc(owner
->catrefs
, newmax
* sizeof(HeapTuple
));
599 owner
->maxcatrefs
= newmax
;
604 * Remember that a catcache reference is owned by a ResourceOwner
606 * Caller must have previously done ResourceOwnerEnlargeCatCacheRefs()
609 ResourceOwnerRememberCatCacheRef(ResourceOwner owner
, HeapTuple tuple
)
611 Assert(owner
->ncatrefs
< owner
->maxcatrefs
);
612 owner
->catrefs
[owner
->ncatrefs
] = tuple
;
617 * Forget that a catcache reference is owned by a ResourceOwner
620 ResourceOwnerForgetCatCacheRef(ResourceOwner owner
, HeapTuple tuple
)
622 HeapTuple
*catrefs
= owner
->catrefs
;
623 int nc1
= owner
->ncatrefs
- 1;
626 for (i
= nc1
; i
>= 0; i
--)
628 if (catrefs
[i
] == tuple
)
632 catrefs
[i
] = catrefs
[i
+ 1];
635 owner
->ncatrefs
= nc1
;
639 elog(ERROR
, "catcache reference %p is not owned by resource owner %s",
644 * Make sure there is room for at least one more entry in a ResourceOwner's
645 * catcache-list reference array.
647 * This is separate from actually inserting an entry because if we run out
648 * of memory, it's critical to do so *before* acquiring the resource.
651 ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner
)
655 if (owner
->ncatlistrefs
< owner
->maxcatlistrefs
)
656 return; /* nothing to do */
658 if (owner
->catlistrefs
== NULL
)
661 owner
->catlistrefs
= (CatCList
**)
662 MemoryContextAlloc(TopMemoryContext
, newmax
* sizeof(CatCList
*));
663 owner
->maxcatlistrefs
= newmax
;
667 newmax
= owner
->maxcatlistrefs
* 2;
668 owner
->catlistrefs
= (CatCList
**)
669 repalloc(owner
->catlistrefs
, newmax
* sizeof(CatCList
*));
670 owner
->maxcatlistrefs
= newmax
;
675 * Remember that a catcache-list reference is owned by a ResourceOwner
677 * Caller must have previously done ResourceOwnerEnlargeCatCacheListRefs()
680 ResourceOwnerRememberCatCacheListRef(ResourceOwner owner
, CatCList
*list
)
682 Assert(owner
->ncatlistrefs
< owner
->maxcatlistrefs
);
683 owner
->catlistrefs
[owner
->ncatlistrefs
] = list
;
684 owner
->ncatlistrefs
++;
688 * Forget that a catcache-list reference is owned by a ResourceOwner
691 ResourceOwnerForgetCatCacheListRef(ResourceOwner owner
, CatCList
*list
)
693 CatCList
**catlistrefs
= owner
->catlistrefs
;
694 int nc1
= owner
->ncatlistrefs
- 1;
697 for (i
= nc1
; i
>= 0; i
--)
699 if (catlistrefs
[i
] == list
)
703 catlistrefs
[i
] = catlistrefs
[i
+ 1];
706 owner
->ncatlistrefs
= nc1
;
710 elog(ERROR
, "catcache list reference %p is not owned by resource owner %s",
715 * Make sure there is room for at least one more entry in a ResourceOwner's
716 * relcache reference array.
718 * This is separate from actually inserting an entry because if we run out
719 * of memory, it's critical to do so *before* acquiring the resource.
722 ResourceOwnerEnlargeRelationRefs(ResourceOwner owner
)
726 if (owner
->nrelrefs
< owner
->maxrelrefs
)
727 return; /* nothing to do */
729 if (owner
->relrefs
== NULL
)
732 owner
->relrefs
= (Relation
*)
733 MemoryContextAlloc(TopMemoryContext
, newmax
* sizeof(Relation
));
734 owner
->maxrelrefs
= newmax
;
738 newmax
= owner
->maxrelrefs
* 2;
739 owner
->relrefs
= (Relation
*)
740 repalloc(owner
->relrefs
, newmax
* sizeof(Relation
));
741 owner
->maxrelrefs
= newmax
;
746 * Remember that a relcache reference is owned by a ResourceOwner
748 * Caller must have previously done ResourceOwnerEnlargeRelationRefs()
751 ResourceOwnerRememberRelationRef(ResourceOwner owner
, Relation rel
)
753 Assert(owner
->nrelrefs
< owner
->maxrelrefs
);
754 owner
->relrefs
[owner
->nrelrefs
] = rel
;
759 * Forget that a relcache reference is owned by a ResourceOwner
762 ResourceOwnerForgetRelationRef(ResourceOwner owner
, Relation rel
)
764 Relation
*relrefs
= owner
->relrefs
;
765 int nr1
= owner
->nrelrefs
- 1;
768 for (i
= nr1
; i
>= 0; i
--)
770 if (relrefs
[i
] == rel
)
774 relrefs
[i
] = relrefs
[i
+ 1];
777 owner
->nrelrefs
= nr1
;
781 elog(ERROR
, "relcache reference %s is not owned by resource owner %s",
782 RelationGetRelationName(rel
), owner
->name
);
786 * Debugging subroutine
789 PrintRelCacheLeakWarning(Relation rel
)
791 elog(WARNING
, "relcache reference leak: relation \"%s\" not closed",
792 RelationGetRelationName(rel
));
796 * Make sure there is room for at least one more entry in a ResourceOwner's
797 * plancache reference array.
799 * This is separate from actually inserting an entry because if we run out
800 * of memory, it's critical to do so *before* acquiring the resource.
803 ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner
)
807 if (owner
->nplanrefs
< owner
->maxplanrefs
)
808 return; /* nothing to do */
810 if (owner
->planrefs
== NULL
)
813 owner
->planrefs
= (CachedPlan
**)
814 MemoryContextAlloc(TopMemoryContext
, newmax
* sizeof(CachedPlan
*));
815 owner
->maxplanrefs
= newmax
;
819 newmax
= owner
->maxplanrefs
* 2;
820 owner
->planrefs
= (CachedPlan
**)
821 repalloc(owner
->planrefs
, newmax
* sizeof(CachedPlan
*));
822 owner
->maxplanrefs
= newmax
;
827 * Remember that a plancache reference is owned by a ResourceOwner
829 * Caller must have previously done ResourceOwnerEnlargePlanCacheRefs()
832 ResourceOwnerRememberPlanCacheRef(ResourceOwner owner
, CachedPlan
*plan
)
834 Assert(owner
->nplanrefs
< owner
->maxplanrefs
);
835 owner
->planrefs
[owner
->nplanrefs
] = plan
;
840 * Forget that a plancache reference is owned by a ResourceOwner
843 ResourceOwnerForgetPlanCacheRef(ResourceOwner owner
, CachedPlan
*plan
)
845 CachedPlan
**planrefs
= owner
->planrefs
;
846 int np1
= owner
->nplanrefs
- 1;
849 for (i
= np1
; i
>= 0; i
--)
851 if (planrefs
[i
] == plan
)
855 planrefs
[i
] = planrefs
[i
+ 1];
858 owner
->nplanrefs
= np1
;
862 elog(ERROR
, "plancache reference %p is not owned by resource owner %s",
867 * Debugging subroutine
870 PrintPlanCacheLeakWarning(CachedPlan
*plan
)
872 elog(WARNING
, "plancache reference leak: plan %p not closed", plan
);
876 * Make sure there is room for at least one more entry in a ResourceOwner's
877 * tupdesc reference array.
879 * This is separate from actually inserting an entry because if we run out
880 * of memory, it's critical to do so *before* acquiring the resource.
883 ResourceOwnerEnlargeTupleDescs(ResourceOwner owner
)
887 if (owner
->ntupdescs
< owner
->maxtupdescs
)
888 return; /* nothing to do */
890 if (owner
->tupdescs
== NULL
)
893 owner
->tupdescs
= (TupleDesc
*)
894 MemoryContextAlloc(TopMemoryContext
, newmax
* sizeof(TupleDesc
));
895 owner
->maxtupdescs
= newmax
;
899 newmax
= owner
->maxtupdescs
* 2;
900 owner
->tupdescs
= (TupleDesc
*)
901 repalloc(owner
->tupdescs
, newmax
* sizeof(TupleDesc
));
902 owner
->maxtupdescs
= newmax
;
907 * Remember that a tupdesc reference is owned by a ResourceOwner
909 * Caller must have previously done ResourceOwnerEnlargeTupleDescs()
912 ResourceOwnerRememberTupleDesc(ResourceOwner owner
, TupleDesc tupdesc
)
914 Assert(owner
->ntupdescs
< owner
->maxtupdescs
);
915 owner
->tupdescs
[owner
->ntupdescs
] = tupdesc
;
920 * Forget that a tupdesc reference is owned by a ResourceOwner
923 ResourceOwnerForgetTupleDesc(ResourceOwner owner
, TupleDesc tupdesc
)
925 TupleDesc
*tupdescs
= owner
->tupdescs
;
926 int nt1
= owner
->ntupdescs
- 1;
929 for (i
= nt1
; i
>= 0; i
--)
931 if (tupdescs
[i
] == tupdesc
)
935 tupdescs
[i
] = tupdescs
[i
+ 1];
938 owner
->ntupdescs
= nt1
;
942 elog(ERROR
, "tupdesc reference %p is not owned by resource owner %s",
943 tupdesc
, owner
->name
);
947 * Debugging subroutine
950 PrintTupleDescLeakWarning(TupleDesc tupdesc
)
953 "TupleDesc reference leak: TupleDesc %p (%u,%d) still referenced",
954 tupdesc
, tupdesc
->tdtypeid
, tupdesc
->tdtypmod
);
958 * Make sure there is room for at least one more entry in a ResourceOwner's
959 * snapshot reference array.
961 * This is separate from actually inserting an entry because if we run out
962 * of memory, it's critical to do so *before* acquiring the resource.
965 ResourceOwnerEnlargeSnapshots(ResourceOwner owner
)
969 if (owner
->nsnapshots
< owner
->maxsnapshots
)
970 return; /* nothing to do */
972 if (owner
->snapshots
== NULL
)
975 owner
->snapshots
= (Snapshot
*)
976 MemoryContextAlloc(TopMemoryContext
, newmax
* sizeof(Snapshot
));
977 owner
->maxsnapshots
= newmax
;
981 newmax
= owner
->maxsnapshots
* 2;
982 owner
->snapshots
= (Snapshot
*)
983 repalloc(owner
->snapshots
, newmax
* sizeof(Snapshot
));
984 owner
->maxsnapshots
= newmax
;
989 * Remember that a snapshot reference is owned by a ResourceOwner
991 * Caller must have previously done ResourceOwnerEnlargeSnapshots()
994 ResourceOwnerRememberSnapshot(ResourceOwner owner
, Snapshot snapshot
)
996 Assert(owner
->nsnapshots
< owner
->maxsnapshots
);
997 owner
->snapshots
[owner
->nsnapshots
] = snapshot
;
1002 * Forget that a snapshot reference is owned by a ResourceOwner
1005 ResourceOwnerForgetSnapshot(ResourceOwner owner
, Snapshot snapshot
)
1007 Snapshot
*snapshots
= owner
->snapshots
;
1008 int ns1
= owner
->nsnapshots
- 1;
1011 for (i
= ns1
; i
>= 0; i
--)
1013 if (snapshots
[i
] == snapshot
)
1017 snapshots
[i
] = snapshots
[i
+ 1];
1020 owner
->nsnapshots
= ns1
;
1024 elog(ERROR
, "snapshot reference %p is not owned by resource owner %s",
1025 snapshot
, owner
->name
);
1029 * Debugging subroutine
1032 PrintSnapshotLeakWarning(Snapshot snapshot
)
1035 "Snapshot reference leak: Snapshot %p still referenced",