OSDN Git Service

8.4 pgindent run, with new combined Linux/FreeBSD/MinGW typedef list
[pg-rex/syncrep.git] / src / backend / utils / resowner / resowner.c
1 /*-------------------------------------------------------------------------
2  *
3  * resowner.c
4  *        POSTGRES resource owner management code.
5  *
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.
10  *
11  *
12  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
13  * Portions Copyright (c) 1994, Regents of the University of California
14  *
15  *
16  * IDENTIFICATION
17  *        $PostgreSQL: pgsql/src/backend/utils/resowner/resowner.c,v 1.32 2009/06/11 14:49:06 momjian Exp $
18  *
19  *-------------------------------------------------------------------------
20  */
21 #include "postgres.h"
22
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"
30
31
32 /*
33  * ResourceOwner objects look like this
34  */
35 typedef struct ResourceOwnerData
36 {
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) */
41
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 */
46
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 */
51
52         int                     ncatlistrefs;   /* number of owned catcache-list pins */
53         CatCList  **catlistrefs;        /* dynamically allocated array */
54         int                     maxcatlistrefs; /* currently allocated array size */
55
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 */
60
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 */
65
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 */
70
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 */
75 } ResourceOwnerData;
76
77
78 /*****************************************************************************
79  *        GLOBAL MEMORY                                                                                                                  *
80  *****************************************************************************/
81
82 ResourceOwner CurrentResourceOwner = NULL;
83 ResourceOwner CurTransactionResourceOwner = NULL;
84 ResourceOwner TopTransactionResourceOwner = NULL;
85
86 /*
87  * List of add-on callbacks for resource releasing
88  */
89 typedef struct ResourceReleaseCallbackItem
90 {
91         struct ResourceReleaseCallbackItem *next;
92         ResourceReleaseCallback callback;
93         void       *arg;
94 } ResourceReleaseCallbackItem;
95
96 static ResourceReleaseCallbackItem *ResourceRelease_callbacks = NULL;
97
98
99 /* Internal routines */
100 static void ResourceOwnerReleaseInternal(ResourceOwner owner,
101                                                          ResourceReleasePhase phase,
102                                                          bool isCommit,
103                                                          bool isTopLevel);
104 static void PrintRelCacheLeakWarning(Relation rel);
105 static void PrintPlanCacheLeakWarning(CachedPlan *plan);
106 static void PrintTupleDescLeakWarning(TupleDesc tupdesc);
107 static void PrintSnapshotLeakWarning(Snapshot snapshot);
108
109
110 /*****************************************************************************
111  *        EXPORTED ROUTINES                                                                                                              *
112  *****************************************************************************/
113
114
115 /*
116  * ResourceOwnerCreate
117  *              Create an empty ResourceOwner.
118  *
119  * All ResourceOwner objects are kept in TopMemoryContext, since they should
120  * only be freed explicitly.
121  */
122 ResourceOwner
123 ResourceOwnerCreate(ResourceOwner parent, const char *name)
124 {
125         ResourceOwner owner;
126
127         owner = (ResourceOwner) MemoryContextAllocZero(TopMemoryContext,
128                                                                                                    sizeof(ResourceOwnerData));
129         owner->name = name;
130
131         if (parent)
132         {
133                 owner->parent = parent;
134                 owner->nextchild = parent->firstchild;
135                 parent->firstchild = owner;
136         }
137
138         return owner;
139 }
140
141 /*
142  * ResourceOwnerRelease
143  *              Release all resources owned by a ResourceOwner and its descendants,
144  *              but don't delete the owner objects themselves.
145  *
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.
151  *
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
156  *
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.
162  *
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.
166  */
167 void
168 ResourceOwnerRelease(ResourceOwner owner,
169                                          ResourceReleasePhase phase,
170                                          bool isCommit,
171                                          bool isTopLevel)
172 {
173         /* Rather than PG_TRY at every level of recursion, set it up once */
174         ResourceOwner save;
175
176         save = CurrentResourceOwner;
177         PG_TRY();
178         {
179                 ResourceOwnerReleaseInternal(owner, phase, isCommit, isTopLevel);
180         }
181         PG_CATCH();
182         {
183                 CurrentResourceOwner = save;
184                 PG_RE_THROW();
185         }
186         PG_END_TRY();
187         CurrentResourceOwner = save;
188 }
189
190 static void
191 ResourceOwnerReleaseInternal(ResourceOwner owner,
192                                                          ResourceReleasePhase phase,
193                                                          bool isCommit,
194                                                          bool isTopLevel)
195 {
196         ResourceOwner child;
197         ResourceOwner save;
198         ResourceReleaseCallbackItem *item;
199
200         /* Recurse to handle descendants */
201         for (child = owner->firstchild; child != NULL; child = child->nextchild)
202                 ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel);
203
204         /*
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.
208          */
209         save = CurrentResourceOwner;
210         CurrentResourceOwner = owner;
211
212         if (phase == RESOURCE_RELEASE_BEFORE_LOCKS)
213         {
214                 /*
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
217                  * none.
218                  *
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.
222                  *
223                  * We are careful to do the releasing back-to-front, so as to avoid
224                  * O(N^2) behavior in ResourceOwnerForgetBuffer().
225                  */
226                 while (owner->nbuffers > 0)
227                 {
228                         if (isCommit)
229                                 PrintBufferLeakWarning(owner->buffers[owner->nbuffers - 1]);
230                         ReleaseBuffer(owner->buffers[owner->nbuffers - 1]);
231                 }
232
233                 /*
234                  * Release relcache references.  Note that RelationClose will remove
235                  * the relref entry from my list, so I just have to iterate till there
236                  * are none.
237                  *
238                  * As with buffer pins, warn if any are left at commit time, and
239                  * release back-to-front for speed.
240                  */
241                 while (owner->nrelrefs > 0)
242                 {
243                         if (isCommit)
244                                 PrintRelCacheLeakWarning(owner->relrefs[owner->nrelrefs - 1]);
245                         RelationClose(owner->relrefs[owner->nrelrefs - 1]);
246                 }
247         }
248         else if (phase == RESOURCE_RELEASE_LOCKS)
249         {
250                 if (isTopLevel)
251                 {
252                         /*
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.
256                          */
257                         if (owner == TopTransactionResourceOwner)
258                                 ProcReleaseLocks(isCommit);
259                 }
260                 else
261                 {
262                         /*
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.
266                          */
267                         Assert(owner->parent != NULL);
268                         if (isCommit)
269                                 LockReassignCurrentOwner();
270                         else
271                                 LockReleaseCurrentOwner();
272                 }
273         }
274         else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
275         {
276                 /*
277                  * Release catcache references.  Note that ReleaseCatCache will remove
278                  * the catref entry from my list, so I just have to iterate till there
279                  * are none.
280                  *
281                  * As with buffer pins, warn if any are left at commit time, and
282                  * release back-to-front for speed.
283                  */
284                 while (owner->ncatrefs > 0)
285                 {
286                         if (isCommit)
287                                 PrintCatCacheLeakWarning(owner->catrefs[owner->ncatrefs - 1]);
288                         ReleaseCatCache(owner->catrefs[owner->ncatrefs - 1]);
289                 }
290                 /* Ditto for catcache lists */
291                 while (owner->ncatlistrefs > 0)
292                 {
293                         if (isCommit)
294                                 PrintCatCacheListLeakWarning(owner->catlistrefs[owner->ncatlistrefs - 1]);
295                         ReleaseCatCacheList(owner->catlistrefs[owner->ncatlistrefs - 1]);
296                 }
297                 /* Ditto for plancache references */
298                 while (owner->nplanrefs > 0)
299                 {
300                         if (isCommit)
301                                 PrintPlanCacheLeakWarning(owner->planrefs[owner->nplanrefs - 1]);
302                         ReleaseCachedPlan(owner->planrefs[owner->nplanrefs - 1], true);
303                 }
304                 /* Ditto for tupdesc references */
305                 while (owner->ntupdescs > 0)
306                 {
307                         if (isCommit)
308                                 PrintTupleDescLeakWarning(owner->tupdescs[owner->ntupdescs - 1]);
309                         DecrTupleDescRefCount(owner->tupdescs[owner->ntupdescs - 1]);
310                 }
311                 /* Ditto for snapshot references */
312                 while (owner->nsnapshots > 0)
313                 {
314                         if (isCommit)
315                                 PrintSnapshotLeakWarning(owner->snapshots[owner->nsnapshots - 1]);
316                         UnregisterSnapshot(owner->snapshots[owner->nsnapshots - 1]);
317                 }
318
319                 /* Clean up index scans too */
320                 ReleaseResources_hash();
321         }
322
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);
326
327         CurrentResourceOwner = save;
328 }
329
330 /*
331  * ResourceOwnerDelete
332  *              Delete an owner object and its descendants.
333  *
334  * The caller must have already released all resources in the object tree.
335  */
336 void
337 ResourceOwnerDelete(ResourceOwner owner)
338 {
339         /* We had better not be deleting CurrentResourceOwner ... */
340         Assert(owner != CurrentResourceOwner);
341
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);
350
351         /*
352          * Delete children.  The recursive call will delink the child from me, so
353          * just iterate as long as there is a child.
354          */
355         while (owner->firstchild != NULL)
356                 ResourceOwnerDelete(owner->firstchild);
357
358         /*
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.
362          */
363         ResourceOwnerNewParent(owner, NULL);
364
365         /* And free the object. */
366         if (owner->buffers)
367                 pfree(owner->buffers);
368         if (owner->catrefs)
369                 pfree(owner->catrefs);
370         if (owner->catlistrefs)
371                 pfree(owner->catlistrefs);
372         if (owner->relrefs)
373                 pfree(owner->relrefs);
374         if (owner->planrefs)
375                 pfree(owner->planrefs);
376         if (owner->tupdescs)
377                 pfree(owner->tupdescs);
378         if (owner->snapshots)
379                 pfree(owner->snapshots);
380
381         pfree(owner);
382 }
383
384 /*
385  * Fetch parent of a ResourceOwner (returns NULL if top-level owner)
386  */
387 ResourceOwner
388 ResourceOwnerGetParent(ResourceOwner owner)
389 {
390         return owner->parent;
391 }
392
393 /*
394  * Reassign a ResourceOwner to have a new parent
395  */
396 void
397 ResourceOwnerNewParent(ResourceOwner owner,
398                                            ResourceOwner newparent)
399 {
400         ResourceOwner oldparent = owner->parent;
401
402         if (oldparent)
403         {
404                 if (owner == oldparent->firstchild)
405                         oldparent->firstchild = owner->nextchild;
406                 else
407                 {
408                         ResourceOwner child;
409
410                         for (child = oldparent->firstchild; child; child = child->nextchild)
411                         {
412                                 if (owner == child->nextchild)
413                                 {
414                                         child->nextchild = owner->nextchild;
415                                         break;
416                                 }
417                         }
418                 }
419         }
420
421         if (newparent)
422         {
423                 Assert(owner != newparent);
424                 owner->parent = newparent;
425                 owner->nextchild = newparent->firstchild;
426                 newparent->firstchild = owner;
427         }
428         else
429         {
430                 owner->parent = NULL;
431                 owner->nextchild = NULL;
432         }
433 }
434
435 /*
436  * Register or deregister callback functions for resource cleanup
437  *
438  * These functions are intended for use by dynamically loaded modules.
439  * For built-in modules we generally just hardwire the appropriate calls.
440  *
441  * Note that the callback occurs post-commit or post-abort, so the callback
442  * functions can only do noncritical cleanup.
443  */
444 void
445 RegisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
446 {
447         ResourceReleaseCallbackItem *item;
448
449         item = (ResourceReleaseCallbackItem *)
450                 MemoryContextAlloc(TopMemoryContext,
451                                                    sizeof(ResourceReleaseCallbackItem));
452         item->callback = callback;
453         item->arg = arg;
454         item->next = ResourceRelease_callbacks;
455         ResourceRelease_callbacks = item;
456 }
457
458 void
459 UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
460 {
461         ResourceReleaseCallbackItem *item;
462         ResourceReleaseCallbackItem *prev;
463
464         prev = NULL;
465         for (item = ResourceRelease_callbacks; item; prev = item, item = item->next)
466         {
467                 if (item->callback == callback && item->arg == arg)
468                 {
469                         if (prev)
470                                 prev->next = item->next;
471                         else
472                                 ResourceRelease_callbacks = item->next;
473                         pfree(item);
474                         break;
475                 }
476         }
477 }
478
479
480 /*
481  * Make sure there is room for at least one more entry in a ResourceOwner's
482  * buffer array.
483  *
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.
486  *
487  * We allow the case owner == NULL because the bufmgr is sometimes invoked
488  * outside any transaction (for example, during WAL recovery).
489  */
490 void
491 ResourceOwnerEnlargeBuffers(ResourceOwner owner)
492 {
493         int                     newmax;
494
495         if (owner == NULL ||
496                 owner->nbuffers < owner->maxbuffers)
497                 return;                                 /* nothing to do */
498
499         if (owner->buffers == NULL)
500         {
501                 newmax = 16;
502                 owner->buffers = (Buffer *)
503                         MemoryContextAlloc(TopMemoryContext, newmax * sizeof(Buffer));
504                 owner->maxbuffers = newmax;
505         }
506         else
507         {
508                 newmax = owner->maxbuffers * 2;
509                 owner->buffers = (Buffer *)
510                         repalloc(owner->buffers, newmax * sizeof(Buffer));
511                 owner->maxbuffers = newmax;
512         }
513 }
514
515 /*
516  * Remember that a buffer pin is owned by a ResourceOwner
517  *
518  * Caller must have previously done ResourceOwnerEnlargeBuffers()
519  *
520  * We allow the case owner == NULL because the bufmgr is sometimes invoked
521  * outside any transaction (for example, during WAL recovery).
522  */
523 void
524 ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
525 {
526         if (owner != NULL)
527         {
528                 Assert(owner->nbuffers < owner->maxbuffers);
529                 owner->buffers[owner->nbuffers] = buffer;
530                 owner->nbuffers++;
531         }
532 }
533
534 /*
535  * Forget that a buffer pin is owned by a ResourceOwner
536  *
537  * We allow the case owner == NULL because the bufmgr is sometimes invoked
538  * outside any transaction (for example, during WAL recovery).
539  */
540 void
541 ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
542 {
543         if (owner != NULL)
544         {
545                 Buffer     *buffers = owner->buffers;
546                 int                     nb1 = owner->nbuffers - 1;
547                 int                     i;
548
549                 /*
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.
553                  */
554                 for (i = nb1; i >= 0; i--)
555                 {
556                         if (buffers[i] == buffer)
557                         {
558                                 while (i < nb1)
559                                 {
560                                         buffers[i] = buffers[i + 1];
561                                         i++;
562                                 }
563                                 owner->nbuffers = nb1;
564                                 return;
565                         }
566                 }
567                 elog(ERROR, "buffer %d is not owned by resource owner %s",
568                          buffer, owner->name);
569         }
570 }
571
572 /*
573  * Make sure there is room for at least one more entry in a ResourceOwner's
574  * catcache reference array.
575  *
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.
578  */
579 void
580 ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner)
581 {
582         int                     newmax;
583
584         if (owner->ncatrefs < owner->maxcatrefs)
585                 return;                                 /* nothing to do */
586
587         if (owner->catrefs == NULL)
588         {
589                 newmax = 16;
590                 owner->catrefs = (HeapTuple *)
591                         MemoryContextAlloc(TopMemoryContext, newmax * sizeof(HeapTuple));
592                 owner->maxcatrefs = newmax;
593         }
594         else
595         {
596                 newmax = owner->maxcatrefs * 2;
597                 owner->catrefs = (HeapTuple *)
598                         repalloc(owner->catrefs, newmax * sizeof(HeapTuple));
599                 owner->maxcatrefs = newmax;
600         }
601 }
602
603 /*
604  * Remember that a catcache reference is owned by a ResourceOwner
605  *
606  * Caller must have previously done ResourceOwnerEnlargeCatCacheRefs()
607  */
608 void
609 ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple)
610 {
611         Assert(owner->ncatrefs < owner->maxcatrefs);
612         owner->catrefs[owner->ncatrefs] = tuple;
613         owner->ncatrefs++;
614 }
615
616 /*
617  * Forget that a catcache reference is owned by a ResourceOwner
618  */
619 void
620 ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple)
621 {
622         HeapTuple  *catrefs = owner->catrefs;
623         int                     nc1 = owner->ncatrefs - 1;
624         int                     i;
625
626         for (i = nc1; i >= 0; i--)
627         {
628                 if (catrefs[i] == tuple)
629                 {
630                         while (i < nc1)
631                         {
632                                 catrefs[i] = catrefs[i + 1];
633                                 i++;
634                         }
635                         owner->ncatrefs = nc1;
636                         return;
637                 }
638         }
639         elog(ERROR, "catcache reference %p is not owned by resource owner %s",
640                  tuple, owner->name);
641 }
642
643 /*
644  * Make sure there is room for at least one more entry in a ResourceOwner's
645  * catcache-list reference array.
646  *
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.
649  */
650 void
651 ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner)
652 {
653         int                     newmax;
654
655         if (owner->ncatlistrefs < owner->maxcatlistrefs)
656                 return;                                 /* nothing to do */
657
658         if (owner->catlistrefs == NULL)
659         {
660                 newmax = 16;
661                 owner->catlistrefs = (CatCList **)
662                         MemoryContextAlloc(TopMemoryContext, newmax * sizeof(CatCList *));
663                 owner->maxcatlistrefs = newmax;
664         }
665         else
666         {
667                 newmax = owner->maxcatlistrefs * 2;
668                 owner->catlistrefs = (CatCList **)
669                         repalloc(owner->catlistrefs, newmax * sizeof(CatCList *));
670                 owner->maxcatlistrefs = newmax;
671         }
672 }
673
674 /*
675  * Remember that a catcache-list reference is owned by a ResourceOwner
676  *
677  * Caller must have previously done ResourceOwnerEnlargeCatCacheListRefs()
678  */
679 void
680 ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
681 {
682         Assert(owner->ncatlistrefs < owner->maxcatlistrefs);
683         owner->catlistrefs[owner->ncatlistrefs] = list;
684         owner->ncatlistrefs++;
685 }
686
687 /*
688  * Forget that a catcache-list reference is owned by a ResourceOwner
689  */
690 void
691 ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list)
692 {
693         CatCList  **catlistrefs = owner->catlistrefs;
694         int                     nc1 = owner->ncatlistrefs - 1;
695         int                     i;
696
697         for (i = nc1; i >= 0; i--)
698         {
699                 if (catlistrefs[i] == list)
700                 {
701                         while (i < nc1)
702                         {
703                                 catlistrefs[i] = catlistrefs[i + 1];
704                                 i++;
705                         }
706                         owner->ncatlistrefs = nc1;
707                         return;
708                 }
709         }
710         elog(ERROR, "catcache list reference %p is not owned by resource owner %s",
711                  list, owner->name);
712 }
713
714 /*
715  * Make sure there is room for at least one more entry in a ResourceOwner's
716  * relcache reference array.
717  *
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.
720  */
721 void
722 ResourceOwnerEnlargeRelationRefs(ResourceOwner owner)
723 {
724         int                     newmax;
725
726         if (owner->nrelrefs < owner->maxrelrefs)
727                 return;                                 /* nothing to do */
728
729         if (owner->relrefs == NULL)
730         {
731                 newmax = 16;
732                 owner->relrefs = (Relation *)
733                         MemoryContextAlloc(TopMemoryContext, newmax * sizeof(Relation));
734                 owner->maxrelrefs = newmax;
735         }
736         else
737         {
738                 newmax = owner->maxrelrefs * 2;
739                 owner->relrefs = (Relation *)
740                         repalloc(owner->relrefs, newmax * sizeof(Relation));
741                 owner->maxrelrefs = newmax;
742         }
743 }
744
745 /*
746  * Remember that a relcache reference is owned by a ResourceOwner
747  *
748  * Caller must have previously done ResourceOwnerEnlargeRelationRefs()
749  */
750 void
751 ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel)
752 {
753         Assert(owner->nrelrefs < owner->maxrelrefs);
754         owner->relrefs[owner->nrelrefs] = rel;
755         owner->nrelrefs++;
756 }
757
758 /*
759  * Forget that a relcache reference is owned by a ResourceOwner
760  */
761 void
762 ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
763 {
764         Relation   *relrefs = owner->relrefs;
765         int                     nr1 = owner->nrelrefs - 1;
766         int                     i;
767
768         for (i = nr1; i >= 0; i--)
769         {
770                 if (relrefs[i] == rel)
771                 {
772                         while (i < nr1)
773                         {
774                                 relrefs[i] = relrefs[i + 1];
775                                 i++;
776                         }
777                         owner->nrelrefs = nr1;
778                         return;
779                 }
780         }
781         elog(ERROR, "relcache reference %s is not owned by resource owner %s",
782                  RelationGetRelationName(rel), owner->name);
783 }
784
785 /*
786  * Debugging subroutine
787  */
788 static void
789 PrintRelCacheLeakWarning(Relation rel)
790 {
791         elog(WARNING, "relcache reference leak: relation \"%s\" not closed",
792                  RelationGetRelationName(rel));
793 }
794
795 /*
796  * Make sure there is room for at least one more entry in a ResourceOwner's
797  * plancache reference array.
798  *
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.
801  */
802 void
803 ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
804 {
805         int                     newmax;
806
807         if (owner->nplanrefs < owner->maxplanrefs)
808                 return;                                 /* nothing to do */
809
810         if (owner->planrefs == NULL)
811         {
812                 newmax = 16;
813                 owner->planrefs = (CachedPlan **)
814                         MemoryContextAlloc(TopMemoryContext, newmax * sizeof(CachedPlan *));
815                 owner->maxplanrefs = newmax;
816         }
817         else
818         {
819                 newmax = owner->maxplanrefs * 2;
820                 owner->planrefs = (CachedPlan **)
821                         repalloc(owner->planrefs, newmax * sizeof(CachedPlan *));
822                 owner->maxplanrefs = newmax;
823         }
824 }
825
826 /*
827  * Remember that a plancache reference is owned by a ResourceOwner
828  *
829  * Caller must have previously done ResourceOwnerEnlargePlanCacheRefs()
830  */
831 void
832 ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
833 {
834         Assert(owner->nplanrefs < owner->maxplanrefs);
835         owner->planrefs[owner->nplanrefs] = plan;
836         owner->nplanrefs++;
837 }
838
839 /*
840  * Forget that a plancache reference is owned by a ResourceOwner
841  */
842 void
843 ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
844 {
845         CachedPlan **planrefs = owner->planrefs;
846         int                     np1 = owner->nplanrefs - 1;
847         int                     i;
848
849         for (i = np1; i >= 0; i--)
850         {
851                 if (planrefs[i] == plan)
852                 {
853                         while (i < np1)
854                         {
855                                 planrefs[i] = planrefs[i + 1];
856                                 i++;
857                         }
858                         owner->nplanrefs = np1;
859                         return;
860                 }
861         }
862         elog(ERROR, "plancache reference %p is not owned by resource owner %s",
863                  plan, owner->name);
864 }
865
866 /*
867  * Debugging subroutine
868  */
869 static void
870 PrintPlanCacheLeakWarning(CachedPlan *plan)
871 {
872         elog(WARNING, "plancache reference leak: plan %p not closed", plan);
873 }
874
875 /*
876  * Make sure there is room for at least one more entry in a ResourceOwner's
877  * tupdesc reference array.
878  *
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.
881  */
882 void
883 ResourceOwnerEnlargeTupleDescs(ResourceOwner owner)
884 {
885         int                     newmax;
886
887         if (owner->ntupdescs < owner->maxtupdescs)
888                 return;                                 /* nothing to do */
889
890         if (owner->tupdescs == NULL)
891         {
892                 newmax = 16;
893                 owner->tupdescs = (TupleDesc *)
894                         MemoryContextAlloc(TopMemoryContext, newmax * sizeof(TupleDesc));
895                 owner->maxtupdescs = newmax;
896         }
897         else
898         {
899                 newmax = owner->maxtupdescs * 2;
900                 owner->tupdescs = (TupleDesc *)
901                         repalloc(owner->tupdescs, newmax * sizeof(TupleDesc));
902                 owner->maxtupdescs = newmax;
903         }
904 }
905
906 /*
907  * Remember that a tupdesc reference is owned by a ResourceOwner
908  *
909  * Caller must have previously done ResourceOwnerEnlargeTupleDescs()
910  */
911 void
912 ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
913 {
914         Assert(owner->ntupdescs < owner->maxtupdescs);
915         owner->tupdescs[owner->ntupdescs] = tupdesc;
916         owner->ntupdescs++;
917 }
918
919 /*
920  * Forget that a tupdesc reference is owned by a ResourceOwner
921  */
922 void
923 ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
924 {
925         TupleDesc  *tupdescs = owner->tupdescs;
926         int                     nt1 = owner->ntupdescs - 1;
927         int                     i;
928
929         for (i = nt1; i >= 0; i--)
930         {
931                 if (tupdescs[i] == tupdesc)
932                 {
933                         while (i < nt1)
934                         {
935                                 tupdescs[i] = tupdescs[i + 1];
936                                 i++;
937                         }
938                         owner->ntupdescs = nt1;
939                         return;
940                 }
941         }
942         elog(ERROR, "tupdesc reference %p is not owned by resource owner %s",
943                  tupdesc, owner->name);
944 }
945
946 /*
947  * Debugging subroutine
948  */
949 static void
950 PrintTupleDescLeakWarning(TupleDesc tupdesc)
951 {
952         elog(WARNING,
953                  "TupleDesc reference leak: TupleDesc %p (%u,%d) still referenced",
954                  tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
955 }
956
957 /*
958  * Make sure there is room for at least one more entry in a ResourceOwner's
959  * snapshot reference array.
960  *
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.
963  */
964 void
965 ResourceOwnerEnlargeSnapshots(ResourceOwner owner)
966 {
967         int                     newmax;
968
969         if (owner->nsnapshots < owner->maxsnapshots)
970                 return;                                 /* nothing to do */
971
972         if (owner->snapshots == NULL)
973         {
974                 newmax = 16;
975                 owner->snapshots = (Snapshot *)
976                         MemoryContextAlloc(TopMemoryContext, newmax * sizeof(Snapshot));
977                 owner->maxsnapshots = newmax;
978         }
979         else
980         {
981                 newmax = owner->maxsnapshots * 2;
982                 owner->snapshots = (Snapshot *)
983                         repalloc(owner->snapshots, newmax * sizeof(Snapshot));
984                 owner->maxsnapshots = newmax;
985         }
986 }
987
988 /*
989  * Remember that a snapshot reference is owned by a ResourceOwner
990  *
991  * Caller must have previously done ResourceOwnerEnlargeSnapshots()
992  */
993 void
994 ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot)
995 {
996         Assert(owner->nsnapshots < owner->maxsnapshots);
997         owner->snapshots[owner->nsnapshots] = snapshot;
998         owner->nsnapshots++;
999 }
1000
1001 /*
1002  * Forget that a snapshot reference is owned by a ResourceOwner
1003  */
1004 void
1005 ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot)
1006 {
1007         Snapshot   *snapshots = owner->snapshots;
1008         int                     ns1 = owner->nsnapshots - 1;
1009         int                     i;
1010
1011         for (i = ns1; i >= 0; i--)
1012         {
1013                 if (snapshots[i] == snapshot)
1014                 {
1015                         while (i < ns1)
1016                         {
1017                                 snapshots[i] = snapshots[i + 1];
1018                                 i++;
1019                         }
1020                         owner->nsnapshots = ns1;
1021                         return;
1022                 }
1023         }
1024         elog(ERROR, "snapshot reference %p is not owned by resource owner %s",
1025                  snapshot, owner->name);
1026 }
1027
1028 /*
1029  * Debugging subroutine
1030  */
1031 static void
1032 PrintSnapshotLeakWarning(Snapshot snapshot)
1033 {
1034         elog(WARNING,
1035                  "Snapshot reference leak: Snapshot %p still referenced",
1036                  snapshot);
1037 }