TLA Line data Source code
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-2023, PostgreSQL Global Development Group
13 : * Portions Copyright (c) 1994, Regents of the University of California
14 : *
15 : *
16 : * IDENTIFICATION
17 : * src/backend/utils/resowner/resowner.c
18 : *
19 : *-------------------------------------------------------------------------
20 : */
21 : #include "postgres.h"
22 :
23 : #include "common/cryptohash.h"
24 : #include "common/hashfn.h"
25 : #include "common/hmac.h"
26 : #include "jit/jit.h"
27 : #include "storage/bufmgr.h"
28 : #include "storage/ipc.h"
29 : #include "storage/predicate.h"
30 : #include "storage/proc.h"
31 : #include "utils/memutils.h"
32 : #include "utils/rel.h"
33 : #include "utils/resowner_private.h"
34 : #include "utils/snapmgr.h"
35 :
36 :
37 : /*
38 : * All resource IDs managed by this code are required to fit into a Datum,
39 : * which is fine since they are generally pointers or integers.
40 : *
41 : * Provide Datum conversion macros for a couple of things that are really
42 : * just "int".
43 : */
44 : #define FileGetDatum(file) Int32GetDatum(file)
45 : #define DatumGetFile(datum) ((File) DatumGetInt32(datum))
46 : #define BufferGetDatum(buffer) Int32GetDatum(buffer)
47 : #define DatumGetBuffer(datum) ((Buffer) DatumGetInt32(datum))
48 :
49 : /*
50 : * ResourceArray is a common structure for storing all types of resource IDs.
51 : *
52 : * We manage small sets of resource IDs by keeping them in a simple array:
53 : * itemsarr[k] holds an ID, for 0 <= k < nitems <= maxitems = capacity.
54 : *
55 : * If a set grows large, we switch over to using open-addressing hashing.
56 : * Then, itemsarr[] is a hash table of "capacity" slots, with each
57 : * slot holding either an ID or "invalidval". nitems is the number of valid
58 : * items present; if it would exceed maxitems, we enlarge the array and
59 : * re-hash. In this mode, maxitems should be rather less than capacity so
60 : * that we don't waste too much time searching for empty slots.
61 : *
62 : * In either mode, lastidx remembers the location of the last item inserted
63 : * or returned by GetAny; this speeds up searches in ResourceArrayRemove.
64 : */
65 : typedef struct ResourceArray
66 : {
67 : Datum *itemsarr; /* buffer for storing values */
68 : Datum invalidval; /* value that is considered invalid */
69 : uint32 capacity; /* allocated length of itemsarr[] */
70 : uint32 nitems; /* how many items are stored in items array */
71 : uint32 maxitems; /* current limit on nitems before enlarging */
72 : uint32 lastidx; /* index of last item returned by GetAny */
73 : } ResourceArray;
74 :
75 : /*
76 : * Initially allocated size of a ResourceArray. Must be power of two since
77 : * we'll use (arraysize - 1) as mask for hashing.
78 : */
79 : #define RESARRAY_INIT_SIZE 16
80 :
81 : /*
82 : * When to switch to hashing vs. simple array logic in a ResourceArray.
83 : */
84 : #define RESARRAY_MAX_ARRAY 64
85 : #define RESARRAY_IS_ARRAY(resarr) ((resarr)->capacity <= RESARRAY_MAX_ARRAY)
86 :
87 : /*
88 : * How many items may be stored in a resource array of given capacity.
89 : * When this number is reached, we must resize.
90 : */
91 : #define RESARRAY_MAX_ITEMS(capacity) \
92 : ((capacity) <= RESARRAY_MAX_ARRAY ? (capacity) : (capacity)/4 * 3)
93 :
94 : /*
95 : * To speed up bulk releasing or reassigning locks from a resource owner to
96 : * its parent, each resource owner has a small cache of locks it owns. The
97 : * lock manager has the same information in its local lock hash table, and
98 : * we fall back on that if cache overflows, but traversing the hash table
99 : * is slower when there are a lot of locks belonging to other resource owners.
100 : *
101 : * MAX_RESOWNER_LOCKS is the size of the per-resource owner cache. It's
102 : * chosen based on some testing with pg_dump with a large schema. When the
103 : * tests were done (on 9.2), resource owners in a pg_dump run contained up
104 : * to 9 locks, regardless of the schema size, except for the top resource
105 : * owner which contained much more (overflowing the cache). 15 seems like a
106 : * nice round number that's somewhat higher than what pg_dump needs. Note that
107 : * making this number larger is not free - the bigger the cache, the slower
108 : * it is to release locks (in retail), when a resource owner holds many locks.
109 : */
110 : #define MAX_RESOWNER_LOCKS 15
111 :
112 : /*
113 : * ResourceOwner objects look like this
114 : */
115 : typedef struct ResourceOwnerData
116 : {
117 : ResourceOwner parent; /* NULL if no parent (toplevel owner) */
118 : ResourceOwner firstchild; /* head of linked list of children */
119 : ResourceOwner nextchild; /* next child of same parent */
120 : const char *name; /* name (just for debugging) */
121 :
122 : /* We have built-in support for remembering: */
123 : ResourceArray bufferarr; /* owned buffers */
124 : ResourceArray bufferioarr; /* in-progress buffer IO */
125 : ResourceArray catrefarr; /* catcache references */
126 : ResourceArray catlistrefarr; /* catcache-list pins */
127 : ResourceArray relrefarr; /* relcache references */
128 : ResourceArray planrefarr; /* plancache references */
129 : ResourceArray tupdescarr; /* tupdesc references */
130 : ResourceArray snapshotarr; /* snapshot references */
131 : ResourceArray filearr; /* open temporary files */
132 : ResourceArray dsmarr; /* dynamic shmem segments */
133 : ResourceArray jitarr; /* JIT contexts */
134 : ResourceArray cryptohasharr; /* cryptohash contexts */
135 : ResourceArray hmacarr; /* HMAC contexts */
136 :
137 : /* We can remember up to MAX_RESOWNER_LOCKS references to local locks. */
138 : int nlocks; /* number of owned locks */
139 : LOCALLOCK *locks[MAX_RESOWNER_LOCKS]; /* list of owned locks */
140 : } ResourceOwnerData;
141 :
142 :
143 : /*****************************************************************************
144 : * GLOBAL MEMORY *
145 : *****************************************************************************/
146 :
147 : ResourceOwner CurrentResourceOwner = NULL;
148 : ResourceOwner CurTransactionResourceOwner = NULL;
149 : ResourceOwner TopTransactionResourceOwner = NULL;
150 : ResourceOwner AuxProcessResourceOwner = NULL;
151 :
152 : /*
153 : * List of add-on callbacks for resource releasing
154 : */
155 : typedef struct ResourceReleaseCallbackItem
156 : {
157 : struct ResourceReleaseCallbackItem *next;
158 : ResourceReleaseCallback callback;
159 : void *arg;
160 : } ResourceReleaseCallbackItem;
161 :
162 : static ResourceReleaseCallbackItem *ResourceRelease_callbacks = NULL;
163 :
164 :
165 : /* Internal routines */
166 : static void ResourceArrayInit(ResourceArray *resarr, Datum invalidval);
167 : static void ResourceArrayEnlarge(ResourceArray *resarr);
168 : static void ResourceArrayAdd(ResourceArray *resarr, Datum value);
169 : static bool ResourceArrayRemove(ResourceArray *resarr, Datum value);
170 : static bool ResourceArrayGetAny(ResourceArray *resarr, Datum *value);
171 : static void ResourceArrayFree(ResourceArray *resarr);
172 : static void ResourceOwnerReleaseInternal(ResourceOwner owner,
173 : ResourceReleasePhase phase,
174 : bool isCommit,
175 : bool isTopLevel);
176 : static void ReleaseAuxProcessResourcesCallback(int code, Datum arg);
177 : static void PrintRelCacheLeakWarning(Relation rel);
178 : static void PrintPlanCacheLeakWarning(CachedPlan *plan);
179 : static void PrintTupleDescLeakWarning(TupleDesc tupdesc);
180 : static void PrintSnapshotLeakWarning(Snapshot snapshot);
181 : static void PrintFileLeakWarning(File file);
182 : static void PrintDSMLeakWarning(dsm_segment *seg);
183 : static void PrintCryptoHashLeakWarning(Datum handle);
184 : static void PrintHMACLeakWarning(Datum handle);
185 :
186 :
187 : /*****************************************************************************
188 : * INTERNAL ROUTINES *
189 : *****************************************************************************/
190 :
191 :
192 : /*
193 : * Initialize a ResourceArray
194 : */
195 : static void
196 GIC 13078767 : ResourceArrayInit(ResourceArray *resarr, Datum invalidval)
197 ECB : {
198 : /* Assert it's empty */
199 GIC 13078767 : Assert(resarr->itemsarr == NULL);
200 CBC 13078767 : Assert(resarr->capacity == 0);
201 13078767 : Assert(resarr->nitems == 0);
202 13078767 : Assert(resarr->maxitems == 0);
203 ECB : /* Remember the appropriate "invalid" value */
204 GIC 13078767 : resarr->invalidval = invalidval;
205 ECB : /* We don't allocate any storage until needed */
206 GIC 13078767 : }
207 ECB :
208 : /*
209 : * Make sure there is room for at least one more resource in an array.
210 : *
211 : * This is separate from actually inserting a resource because if we run out
212 : * of memory, it's critical to do so *before* acquiring the resource.
213 : */
214 : static void
215 GIC 208923634 : ResourceArrayEnlarge(ResourceArray *resarr)
216 ECB : {
217 : uint32 i,
218 : oldcap,
219 : newcap;
220 : Datum *olditemsarr;
221 : Datum *newitemsarr;
222 :
223 GIC 208923634 : if (resarr->nitems < resarr->maxitems)
224 CBC 205506208 : return; /* no work needed */
225 ECB :
226 GIC 3417426 : olditemsarr = resarr->itemsarr;
227 CBC 3417426 : oldcap = resarr->capacity;
228 ECB :
229 : /* Double the capacity of the array (capacity must stay a power of 2!) */
230 GIC 3417426 : newcap = (oldcap > 0) ? oldcap * 2 : RESARRAY_INIT_SIZE;
231 CBC 3417426 : newitemsarr = (Datum *) MemoryContextAlloc(TopMemoryContext,
232 ECB : newcap * sizeof(Datum));
233 GIC 59757586 : for (i = 0; i < newcap; i++)
234 CBC 56340160 : newitemsarr[i] = resarr->invalidval;
235 ECB :
236 : /* We assume we can't fail below this point, so OK to scribble on resarr */
237 GIC 3417426 : resarr->itemsarr = newitemsarr;
238 CBC 3417426 : resarr->capacity = newcap;
239 3417426 : resarr->maxitems = RESARRAY_MAX_ITEMS(newcap);
240 3417426 : resarr->nitems = 0;
241 ECB :
242 GIC 3417426 : if (olditemsarr != NULL)
243 ECB : {
244 : /*
245 : * Transfer any pre-existing entries into the new array; they don't
246 : * necessarily go where they were before, so this simple logic is the
247 : * best way. Note that if we were managing the set as a simple array,
248 : * the entries after nitems are garbage, but that shouldn't matter
249 : * because we won't get here unless nitems was equal to oldcap.
250 : */
251 GIC 953306 : for (i = 0; i < oldcap; i++)
252 ECB : {
253 GIC 939680 : if (olditemsarr[i] != resarr->invalidval)
254 CBC 769696 : ResourceArrayAdd(resarr, olditemsarr[i]);
255 ECB : }
256 :
257 : /* And release old array. */
258 GIC 13626 : pfree(olditemsarr);
259 ECB : }
260 :
261 GIC 3417426 : Assert(resarr->nitems < resarr->maxitems);
262 ECB : }
263 :
264 : /*
265 : * Add a resource to ResourceArray
266 : *
267 : * Caller must have previously done ResourceArrayEnlarge()
268 : */
269 : static void
270 GIC 206595945 : ResourceArrayAdd(ResourceArray *resarr, Datum value)
271 ECB : {
272 : uint32 idx;
273 :
274 GIC 206595945 : Assert(value != resarr->invalidval);
275 CBC 206595945 : Assert(resarr->nitems < resarr->maxitems);
276 ECB :
277 GIC 206595945 : if (RESARRAY_IS_ARRAY(resarr))
278 ECB : {
279 : /* Append to linear array. */
280 GIC 205411741 : idx = resarr->nitems;
281 ECB : }
282 : else
283 : {
284 : /* Insert into first free slot at or after hash location. */
285 GIC 1184204 : uint32 mask = resarr->capacity - 1;
286 ECB :
287 GIC 1184204 : idx = DatumGetUInt32(hash_any((void *) &value, sizeof(value))) & mask;
288 ECB : for (;;)
289 : {
290 GIC 392068502 : if (resarr->itemsarr[idx] == resarr->invalidval)
291 CBC 1184204 : break;
292 390884298 : idx = (idx + 1) & mask;
293 ECB : }
294 : }
295 GIC 206595945 : resarr->lastidx = idx;
296 CBC 206595945 : resarr->itemsarr[idx] = value;
297 206595945 : resarr->nitems++;
298 206595945 : }
299 ECB :
300 : /*
301 : * Remove a resource from ResourceArray
302 : *
303 : * Returns true on success, false if resource was not found.
304 : *
305 : * Note: if same resource ID appears more than once, one instance is removed.
306 : */
307 : static bool
308 GIC 205826244 : ResourceArrayRemove(ResourceArray *resarr, Datum value)
309 ECB : {
310 : uint32 i,
311 : idx,
312 GIC 205826244 : lastidx = resarr->lastidx;
313 ECB :
314 GIC 205826244 : Assert(value != resarr->invalidval);
315 ECB :
316 : /* Search through all items, but try lastidx first. */
317 GIC 205826244 : if (RESARRAY_IS_ARRAY(resarr))
318 ECB : {
319 GIC 205151992 : if (lastidx < resarr->nitems &&
320 CBC 205151992 : resarr->itemsarr[lastidx] == value)
321 ECB : {
322 GIC 199281187 : resarr->itemsarr[lastidx] = resarr->itemsarr[resarr->nitems - 1];
323 CBC 199281187 : resarr->nitems--;
324 ECB : /* Update lastidx to make reverse-order removals fast. */
325 GIC 199281187 : resarr->lastidx = resarr->nitems - 1;
326 CBC 199281187 : return true;
327 ECB : }
328 GIC 12783604 : for (i = 0; i < resarr->nitems; i++)
329 ECB : {
330 GIC 12783604 : if (resarr->itemsarr[i] == value)
331 ECB : {
332 GIC 5870805 : resarr->itemsarr[i] = resarr->itemsarr[resarr->nitems - 1];
333 CBC 5870805 : resarr->nitems--;
334 ECB : /* Update lastidx to make reverse-order removals fast. */
335 GIC 5870805 : resarr->lastidx = resarr->nitems - 1;
336 CBC 5870805 : return true;
337 ECB : }
338 : }
339 : }
340 : else
341 : {
342 GIC 674252 : uint32 mask = resarr->capacity - 1;
343 ECB :
344 GIC 674252 : if (lastidx < resarr->capacity &&
345 CBC 674252 : resarr->itemsarr[lastidx] == value)
346 ECB : {
347 GIC 199252 : resarr->itemsarr[lastidx] = resarr->invalidval;
348 CBC 199252 : resarr->nitems--;
349 199252 : return true;
350 ECB : }
351 GIC 475000 : idx = DatumGetUInt32(hash_any((void *) &value, sizeof(value))) & mask;
352 CBC 171789826 : for (i = 0; i < resarr->capacity; i++)
353 ECB : {
354 GIC 171789826 : if (resarr->itemsarr[idx] == value)
355 ECB : {
356 GIC 475000 : resarr->itemsarr[idx] = resarr->invalidval;
357 CBC 475000 : resarr->nitems--;
358 475000 : return true;
359 ECB : }
360 GIC 171314826 : idx = (idx + 1) & mask;
361 ECB : }
362 : }
363 :
364 UIC 0 : return false;
365 EUB : }
366 :
367 : /*
368 : * Get any convenient entry in a ResourceArray.
369 : *
370 : * "Convenient" is defined as "easy for ResourceArrayRemove to remove";
371 : * we help that along by setting lastidx to match. This avoids O(N^2) cost
372 : * when removing all ResourceArray items during ResourceOwner destruction.
373 : *
374 : * Returns true if we found an element, or false if the array is empty.
375 : */
376 : static bool
377 GIC 13180874 : ResourceArrayGetAny(ResourceArray *resarr, Datum *value)
378 ECB : {
379 GIC 13180874 : if (resarr->nitems == 0)
380 CBC 13088006 : return false;
381 ECB :
382 GIC 92868 : if (RESARRAY_IS_ARRAY(resarr))
383 ECB : {
384 : /* Linear array: just return the first element. */
385 GIC 83885 : resarr->lastidx = 0;
386 ECB : }
387 : else
388 : {
389 : /* Hash: search forward from wherever we were last. */
390 GIC 8983 : uint32 mask = resarr->capacity - 1;
391 ECB :
392 : for (;;)
393 : {
394 GIC 22149 : resarr->lastidx &= mask;
395 CBC 22149 : if (resarr->itemsarr[resarr->lastidx] != resarr->invalidval)
396 8983 : break;
397 13166 : resarr->lastidx++;
398 ECB : }
399 : }
400 :
401 GIC 92868 : *value = resarr->itemsarr[resarr->lastidx];
402 CBC 92868 : return true;
403 ECB : }
404 :
405 : /*
406 : * Trash a ResourceArray (we don't care about its state after this)
407 : */
408 : static void
409 GIC 13047411 : ResourceArrayFree(ResourceArray *resarr)
410 ECB : {
411 GIC 13047411 : if (resarr->itemsarr)
412 CBC 3400021 : pfree(resarr->itemsarr);
413 13047411 : }
414 ECB :
415 :
416 : /*****************************************************************************
417 : * EXPORTED ROUTINES *
418 : *****************************************************************************/
419 :
420 :
421 : /*
422 : * ResourceOwnerCreate
423 : * Create an empty ResourceOwner.
424 : *
425 : * All ResourceOwner objects are kept in TopMemoryContext, since they should
426 : * only be freed explicitly.
427 : */
428 : ResourceOwner
429 GIC 1006059 : ResourceOwnerCreate(ResourceOwner parent, const char *name)
430 ECB : {
431 : ResourceOwner owner;
432 :
433 GIC 1006059 : owner = (ResourceOwner) MemoryContextAllocZero(TopMemoryContext,
434 ECB : sizeof(ResourceOwnerData));
435 GIC 1006059 : owner->name = name;
436 ECB :
437 GIC 1006059 : if (parent)
438 ECB : {
439 GIC 516105 : owner->parent = parent;
440 CBC 516105 : owner->nextchild = parent->firstchild;
441 516105 : parent->firstchild = owner;
442 ECB : }
443 :
444 GIC 1006059 : ResourceArrayInit(&(owner->bufferarr), BufferGetDatum(InvalidBuffer));
445 GNC 1006059 : ResourceArrayInit(&(owner->bufferioarr), BufferGetDatum(InvalidBuffer));
446 CBC 1006059 : ResourceArrayInit(&(owner->catrefarr), PointerGetDatum(NULL));
447 1006059 : ResourceArrayInit(&(owner->catlistrefarr), PointerGetDatum(NULL));
448 1006059 : ResourceArrayInit(&(owner->relrefarr), PointerGetDatum(NULL));
449 1006059 : ResourceArrayInit(&(owner->planrefarr), PointerGetDatum(NULL));
450 1006059 : ResourceArrayInit(&(owner->tupdescarr), PointerGetDatum(NULL));
451 1006059 : ResourceArrayInit(&(owner->snapshotarr), PointerGetDatum(NULL));
452 1006059 : ResourceArrayInit(&(owner->filearr), FileGetDatum(-1));
453 1006059 : ResourceArrayInit(&(owner->dsmarr), PointerGetDatum(NULL));
454 1006059 : ResourceArrayInit(&(owner->jitarr), PointerGetDatum(NULL));
455 1006059 : ResourceArrayInit(&(owner->cryptohasharr), PointerGetDatum(NULL));
456 1006059 : ResourceArrayInit(&(owner->hmacarr), PointerGetDatum(NULL));
457 ECB :
458 CBC 1006059 : return owner;
459 : }
460 ECB :
461 : /*
462 : * ResourceOwnerRelease
463 : * Release all resources owned by a ResourceOwner and its descendants,
464 : * but don't delete the owner objects themselves.
465 : *
466 : * Note that this executes just one phase of release, and so typically
467 : * must be called three times. We do it this way because (a) we want to
468 : * do all the recursion separately for each phase, thereby preserving
469 : * the needed order of operations; and (b) xact.c may have other operations
470 : * to do between the phases.
471 : *
472 : * phase: release phase to execute
473 : * isCommit: true for successful completion of a query or transaction,
474 : * false for unsuccessful
475 : * isTopLevel: true if completing a main transaction, else false
476 : *
477 : * isCommit is passed because some modules may expect that their resources
478 : * were all released already if the transaction or portal finished normally.
479 : * If so it is reasonable to give a warning (NOT an error) should any
480 : * unreleased resources be present. When isCommit is false, such warnings
481 : * are generally inappropriate.
482 : *
483 : * isTopLevel is passed when we are releasing TopTransactionResourceOwner
484 : * at completion of a main transaction. This generally means that *all*
485 : * resources will be released, and so we can optimize things a bit.
486 : */
487 : void
488 GIC 2932668 : ResourceOwnerRelease(ResourceOwner owner,
489 : ResourceReleasePhase phase,
490 ECB : bool isCommit,
491 : bool isTopLevel)
492 : {
493 : /* There's not currently any setup needed before recursing */
494 GIC 2932668 : ResourceOwnerReleaseInternal(owner, phase, isCommit, isTopLevel);
495 2932668 : }
496 ECB :
497 : static void
498 GIC 3018624 : ResourceOwnerReleaseInternal(ResourceOwner owner,
499 : ResourceReleasePhase phase,
500 ECB : bool isCommit,
501 : bool isTopLevel)
502 : {
503 : ResourceOwner child;
504 : ResourceOwner save;
505 : ResourceReleaseCallbackItem *item;
506 : ResourceReleaseCallbackItem *next;
507 : Datum foundres;
508 :
509 : /* Recurse to handle descendants */
510 GIC 3104580 : for (child = owner->firstchild; child != NULL; child = child->nextchild)
511 85956 : ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel);
512 :
513 ECB : /*
514 : * Make CurrentResourceOwner point to me, so that ReleaseBuffer etc don't
515 : * get confused.
516 : */
517 GIC 3018624 : save = CurrentResourceOwner;
518 3018624 : CurrentResourceOwner = owner;
519 :
520 CBC 3018624 : if (phase == RESOURCE_RELEASE_BEFORE_LOCKS)
521 ECB : {
522 : /*
523 : * Abort failed buffer IO. AbortBufferIO()->TerminateBufferIO() calls
524 : * ResourceOwnerForgetBufferIOs(), so we just have to iterate till
525 : * there are none.
526 : *
527 : * Needs to be before we release buffer pins.
528 : *
529 : * During a commit, there shouldn't be any in-progress IO.
530 : */
531 GNC 1006221 : while (ResourceArrayGetAny(&(owner->bufferioarr), &foundres))
532 : {
533 13 : Buffer res = DatumGetBuffer(foundres);
534 :
535 13 : if (isCommit)
536 UNC 0 : elog(PANIC, "lost track of buffer IO on buffer %u", res);
537 GNC 13 : AbortBufferIO(res);
538 : }
539 :
540 : /*
541 ECB : * Release buffer pins. Note that ReleaseBuffer will remove the
542 : * buffer entry from our array, so we just have to iterate till there
543 : * are none.
544 : *
545 : * During a commit, there shouldn't be any remaining pins --- that
546 : * would indicate failure to clean up the executor correctly --- so
547 : * issue warnings. In the abort case, just clean up quietly.
548 : */
549 GIC 1009873 : while (ResourceArrayGetAny(&(owner->bufferarr), &foundres))
550 : {
551 3665 : Buffer res = DatumGetBuffer(foundres);
552 ECB :
553 GIC 3665 : if (isCommit)
554 LBC 0 : PrintBufferLeakWarning(res);
555 GIC 3665 : ReleaseBuffer(res);
556 ECB : }
557 EUB :
558 ECB : /* Ditto for relcache references */
559 GIC 1022070 : while (ResourceArrayGetAny(&(owner->relrefarr), &foundres))
560 : {
561 15862 : Relation res = (Relation) DatumGetPointer(foundres);
562 :
563 15862 : if (isCommit)
564 UIC 0 : PrintRelCacheLeakWarning(res);
565 GIC 15862 : RelationClose(res);
566 : }
567 :
568 : /* Ditto for dynamic shared memory segments */
569 1006208 : while (ResourceArrayGetAny(&(owner->dsmarr), &foundres))
570 ECB : {
571 UIC 0 : dsm_segment *res = (dsm_segment *) DatumGetPointer(foundres);
572 ECB :
573 UIC 0 : if (isCommit)
574 LBC 0 : PrintDSMLeakWarning(res);
575 UBC 0 : dsm_detach(res);
576 ECB : }
577 :
578 : /* Ditto for JIT contexts */
579 GIC 1006216 : while (ResourceArrayGetAny(&(owner->jitarr), &foundres))
580 ECB : {
581 GNC 8 : JitContext *context = (JitContext *) DatumGetPointer(foundres);
582 ECB :
583 GIC 8 : jit_release_context(context);
584 ECB : }
585 EUB :
586 ECB : /* Ditto for cryptohash contexts */
587 GIC 1006212 : while (ResourceArrayGetAny(&(owner->cryptohasharr), &foundres))
588 : {
589 : pg_cryptohash_ctx *context =
590 GNC 4 : (pg_cryptohash_ctx *) DatumGetPointer(foundres);
591 :
592 GBC 4 : if (isCommit)
593 UIC 0 : PrintCryptoHashLeakWarning(foundres);
594 GBC 4 : pg_cryptohash_free(context);
595 EUB : }
596 :
597 : /* Ditto for HMAC contexts */
598 GIC 1006208 : while (ResourceArrayGetAny(&(owner->hmacarr), &foundres))
599 : {
600 UNC 0 : pg_hmac_ctx *context = (pg_hmac_ctx *) DatumGetPointer(foundres);
601 :
602 LBC 0 : if (isCommit)
603 UIC 0 : PrintHMACLeakWarning(foundres);
604 LBC 0 : pg_hmac_free(context);
605 : }
606 : }
607 GIC 2012416 : else if (phase == RESOURCE_RELEASE_LOCKS)
608 ECB : {
609 GIC 1006208 : if (isTopLevel)
610 : {
611 ECB : /*
612 : * For a top-level xact we are going to release all locks (or at
613 : * least all non-session locks), so just do a single lmgr call at
614 EUB : * the top of the recursion.
615 ECB : */
616 GIC 518632 : if (owner == TopTransactionResourceOwner)
617 : {
618 486958 : ProcReleaseLocks(isCommit);
619 CBC 486958 : ReleasePredicateLocks(isCommit, false);
620 : }
621 EUB : }
622 : else
623 : {
624 : /*
625 : * Release locks retail. Note that if we are committing a
626 : * subtransaction, we do NOT release its locks yet, but transfer
627 : * them to the parent.
628 ECB : */
629 : LOCALLOCK **locks;
630 : int nlocks;
631 :
632 GIC 487576 : Assert(owner->parent != NULL);
633 :
634 : /*
635 : * Pass the list of locks owned by this resource owner to the lock
636 : * manager, unless it has overflowed.
637 ECB : */
638 GIC 487576 : if (owner->nlocks > MAX_RESOWNER_LOCKS)
639 ECB : {
640 CBC 3495 : locks = NULL;
641 GIC 3495 : nlocks = 0;
642 : }
643 : else
644 : {
645 484081 : locks = owner->locks;
646 484081 : nlocks = owner->nlocks;
647 : }
648 :
649 487576 : if (isCommit)
650 482967 : LockReassignCurrentOwner(locks, nlocks);
651 : else
652 4609 : LockReleaseCurrentOwner(locks, nlocks);
653 ECB : }
654 : }
655 GIC 1006208 : else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
656 : {
657 : /*
658 : * Release catcache references. Note that ReleaseCatCache will remove
659 ECB : * the catref entry from our array, so we just have to iterate till
660 : * there are none.
661 : *
662 : * As with buffer pins, warn if any are left at commit time.
663 : */
664 GIC 1010879 : while (ResourceArrayGetAny(&(owner->catrefarr), &foundres))
665 : {
666 CBC 4671 : HeapTuple res = (HeapTuple) DatumGetPointer(foundres);
667 ECB :
668 GIC 4671 : if (isCommit)
669 UIC 0 : PrintCatCacheLeakWarning(res);
670 CBC 4671 : ReleaseCatCache(res);
671 ECB : }
672 :
673 : /* Ditto for catcache lists */
674 GIC 1006226 : while (ResourceArrayGetAny(&(owner->catlistrefarr), &foundres))
675 : {
676 CBC 18 : CatCList *res = (CatCList *) DatumGetPointer(foundres);
677 :
678 GIC 18 : if (isCommit)
679 UIC 0 : PrintCatCacheListLeakWarning(res);
680 GIC 18 : ReleaseCatCacheList(res);
681 : }
682 :
683 : /* Ditto for plancache references */
684 1011274 : while (ResourceArrayGetAny(&(owner->planrefarr), &foundres))
685 ECB : {
686 GIC 5066 : CachedPlan *res = (CachedPlan *) DatumGetPointer(foundres);
687 ECB :
688 GIC 5066 : if (isCommit)
689 LBC 0 : PrintPlanCacheLeakWarning(res);
690 GBC 5066 : ReleaseCachedPlan(res, owner);
691 ECB : }
692 :
693 : /* Ditto for tupdesc references */
694 GIC 1011717 : while (ResourceArrayGetAny(&(owner->tupdescarr), &foundres))
695 ECB : {
696 GIC 5509 : TupleDesc res = (TupleDesc) DatumGetPointer(foundres);
697 ECB :
698 GIC 5509 : if (isCommit)
699 LBC 0 : PrintTupleDescLeakWarning(res);
700 GBC 5509 : DecrTupleDescRefCount(res);
701 ECB : }
702 :
703 : /* Ditto for snapshot references */
704 GIC 1031379 : while (ResourceArrayGetAny(&(owner->snapshotarr), &foundres))
705 ECB : {
706 GIC 25171 : Snapshot res = (Snapshot) DatumGetPointer(foundres);
707 ECB :
708 GIC 25171 : if (isCommit)
709 LBC 0 : PrintSnapshotLeakWarning(res);
710 GBC 25171 : UnregisterSnapshot(res);
711 ECB : }
712 :
713 : /* Ditto for temporary files */
714 GIC 1006212 : while (ResourceArrayGetAny(&(owner->filearr), &foundres))
715 ECB : {
716 GIC 4 : File res = DatumGetFile(foundres);
717 ECB :
718 GIC 4 : if (isCommit)
719 LBC 0 : PrintFileLeakWarning(res);
720 GBC 4 : FileClose(res);
721 ECB : }
722 : }
723 :
724 : /* Let add-on modules get a chance too */
725 GNC 3020262 : for (item = ResourceRelease_callbacks; item; item = next)
726 : {
727 : /* allow callbacks to unregister themselves when called */
728 1638 : next = item->next;
729 GIC 1638 : item->callback(phase, isCommit, isTopLevel, item->arg);
730 : }
731 ECB :
732 GIC 3018624 : CurrentResourceOwner = save;
733 CBC 3018624 : }
734 EUB :
735 ECB : /*
736 : * ResourceOwnerReleaseAllPlanCacheRefs
737 : * Release the plancache references (only) held by this owner.
738 : *
739 : * We might eventually add similar functions for other resource types,
740 : * but for now, only this is needed.
741 : */
742 : void
743 CBC 7302 : ResourceOwnerReleaseAllPlanCacheRefs(ResourceOwner owner)
744 EUB : {
745 ECB : Datum foundres;
746 :
747 GIC 40179 : while (ResourceArrayGetAny(&(owner->planrefarr), &foundres))
748 : {
749 32877 : CachedPlan *res = (CachedPlan *) DatumGetPointer(foundres);
750 ECB :
751 GIC 32877 : ReleaseCachedPlan(res, owner);
752 : }
753 CBC 7302 : }
754 ECB :
755 : /*
756 : * ResourceOwnerDelete
757 : * Delete an owner object and its descendants.
758 : *
759 : * The caller must have already released all resources in the object tree.
760 : */
761 : void
762 GIC 1003647 : ResourceOwnerDelete(ResourceOwner owner)
763 : {
764 : /* We had better not be deleting CurrentResourceOwner ... */
765 1003647 : Assert(owner != CurrentResourceOwner);
766 :
767 : /* And it better not own any resources, either */
768 CBC 1003647 : Assert(owner->bufferarr.nitems == 0);
769 GNC 1003647 : Assert(owner->bufferioarr.nitems == 0);
770 GIC 1003647 : Assert(owner->catrefarr.nitems == 0);
771 1003647 : Assert(owner->catlistrefarr.nitems == 0);
772 1003647 : Assert(owner->relrefarr.nitems == 0);
773 CBC 1003647 : Assert(owner->planrefarr.nitems == 0);
774 GIC 1003647 : Assert(owner->tupdescarr.nitems == 0);
775 CBC 1003647 : Assert(owner->snapshotarr.nitems == 0);
776 GIC 1003647 : Assert(owner->filearr.nitems == 0);
777 CBC 1003647 : Assert(owner->dsmarr.nitems == 0);
778 GIC 1003647 : Assert(owner->jitarr.nitems == 0);
779 CBC 1003647 : Assert(owner->cryptohasharr.nitems == 0);
780 GIC 1003647 : Assert(owner->hmacarr.nitems == 0);
781 1003647 : Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1);
782 :
783 : /*
784 : * Delete children. The recursive call will delink the child from me, so
785 : * just iterate as long as there is a child.
786 : */
787 1032302 : while (owner->firstchild != NULL)
788 CBC 28655 : ResourceOwnerDelete(owner->firstchild);
789 :
790 : /*
791 ECB : * We delink the owner from its parent before deleting it, so that if
792 : * there's an error we won't have deleted/busted owners still attached to
793 : * the owner tree. Better a leak than a crash.
794 : */
795 CBC 1003647 : ResourceOwnerNewParent(owner, NULL);
796 ECB :
797 : /* And free the object. */
798 CBC 1003647 : ResourceArrayFree(&(owner->bufferarr));
799 GNC 1003647 : ResourceArrayFree(&(owner->bufferioarr));
800 CBC 1003647 : ResourceArrayFree(&(owner->catrefarr));
801 1003647 : ResourceArrayFree(&(owner->catlistrefarr));
802 1003647 : ResourceArrayFree(&(owner->relrefarr));
803 1003647 : ResourceArrayFree(&(owner->planrefarr));
804 1003647 : ResourceArrayFree(&(owner->tupdescarr));
805 1003647 : ResourceArrayFree(&(owner->snapshotarr));
806 1003647 : ResourceArrayFree(&(owner->filearr));
807 1003647 : ResourceArrayFree(&(owner->dsmarr));
808 1003647 : ResourceArrayFree(&(owner->jitarr));
809 GIC 1003647 : ResourceArrayFree(&(owner->cryptohasharr));
810 1003647 : ResourceArrayFree(&(owner->hmacarr));
811 :
812 1003647 : pfree(owner);
813 1003647 : }
814 ECB :
815 : /*
816 : * Fetch parent of a ResourceOwner (returns NULL if top-level owner)
817 : */
818 : ResourceOwner
819 GIC 482967 : ResourceOwnerGetParent(ResourceOwner owner)
820 : {
821 482967 : return owner->parent;
822 ECB : }
823 :
824 : /*
825 : * Reassign a ResourceOwner to have a new parent
826 : */
827 : void
828 CBC 1003682 : ResourceOwnerNewParent(ResourceOwner owner,
829 ECB : ResourceOwner newparent)
830 : {
831 CBC 1003682 : ResourceOwner oldparent = owner->parent;
832 ECB :
833 CBC 1003682 : if (oldparent)
834 ECB : {
835 CBC 516140 : if (owner == oldparent->firstchild)
836 508911 : oldparent->firstchild = owner->nextchild;
837 ECB : else
838 : {
839 : ResourceOwner child;
840 :
841 GIC 8148 : for (child = oldparent->firstchild; child; child = child->nextchild)
842 : {
843 8148 : if (owner == child->nextchild)
844 : {
845 7229 : child->nextchild = owner->nextchild;
846 CBC 7229 : break;
847 : }
848 ECB : }
849 : }
850 : }
851 :
852 GIC 1003682 : if (newparent)
853 : {
854 35 : Assert(owner != newparent);
855 CBC 35 : owner->parent = newparent;
856 GIC 35 : owner->nextchild = newparent->firstchild;
857 35 : newparent->firstchild = owner;
858 ECB : }
859 : else
860 : {
861 GIC 1003647 : owner->parent = NULL;
862 CBC 1003647 : owner->nextchild = NULL;
863 ECB : }
864 GIC 1003682 : }
865 :
866 : /*
867 : * Register or deregister callback functions for resource cleanup
868 ECB : *
869 : * These functions are intended for use by dynamically loaded modules.
870 : * For built-in modules we generally just hardwire the appropriate calls.
871 : *
872 : * Note that the callback occurs post-commit or post-abort, so the callback
873 : * functions can only do noncritical cleanup.
874 : */
875 : void
876 GIC 23 : RegisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
877 : {
878 : ResourceReleaseCallbackItem *item;
879 ECB :
880 : item = (ResourceReleaseCallbackItem *)
881 CBC 23 : MemoryContextAlloc(TopMemoryContext,
882 ECB : sizeof(ResourceReleaseCallbackItem));
883 CBC 23 : item->callback = callback;
884 23 : item->arg = arg;
885 GIC 23 : item->next = ResourceRelease_callbacks;
886 23 : ResourceRelease_callbacks = item;
887 23 : }
888 ECB :
889 : void
890 UIC 0 : UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
891 ECB : {
892 : ResourceReleaseCallbackItem *item;
893 : ResourceReleaseCallbackItem *prev;
894 :
895 UIC 0 : prev = NULL;
896 0 : for (item = ResourceRelease_callbacks; item; prev = item, item = item->next)
897 : {
898 0 : if (item->callback == callback && item->arg == arg)
899 : {
900 0 : if (prev)
901 0 : prev->next = item->next;
902 : else
903 LBC 0 : ResourceRelease_callbacks = item->next;
904 UIC 0 : pfree(item);
905 0 : break;
906 : }
907 : }
908 LBC 0 : }
909 :
910 ECB : /*
911 : * Establish an AuxProcessResourceOwner for the current process.
912 : */
913 : void
914 CBC 2407 : CreateAuxProcessResourceOwner(void)
915 : {
916 GIC 2407 : Assert(AuxProcessResourceOwner == NULL);
917 GBC 2407 : Assert(CurrentResourceOwner == NULL);
918 GIC 2407 : AuxProcessResourceOwner = ResourceOwnerCreate(NULL, "AuxiliaryProcess");
919 2407 : CurrentResourceOwner = AuxProcessResourceOwner;
920 :
921 : /*
922 EUB : * Register a shmem-exit callback for cleanup of aux-process resource
923 : * owner. (This needs to run after, e.g., ShutdownXLOG.)
924 : */
925 GBC 2407 : on_shmem_exit(ReleaseAuxProcessResourcesCallback, 0);
926 GIC 2407 : }
927 EUB :
928 : /*
929 : * Convenience routine to release all resources tracked in
930 : * AuxProcessResourceOwner (but that resowner is not destroyed here).
931 : * Warn about leaked resources if isCommit is true.
932 : */
933 : void
934 GIC 3026 : ReleaseAuxProcessResources(bool isCommit)
935 EUB : {
936 : /*
937 : * At this writing, the only thing that could actually get released is
938 : * buffer pins; but we may as well do the full release protocol.
939 : */
940 GIC 3026 : ResourceOwnerRelease(AuxProcessResourceOwner,
941 ECB : RESOURCE_RELEASE_BEFORE_LOCKS,
942 : isCommit, true);
943 CBC 3026 : ResourceOwnerRelease(AuxProcessResourceOwner,
944 ECB : RESOURCE_RELEASE_LOCKS,
945 : isCommit, true);
946 CBC 3026 : ResourceOwnerRelease(AuxProcessResourceOwner,
947 : RESOURCE_RELEASE_AFTER_LOCKS,
948 : isCommit, true);
949 GIC 3026 : }
950 :
951 : /*
952 ECB : * Shmem-exit callback for the same.
953 : * Warn about leaked resources if process exit code is zero (ie normal).
954 : */
955 : static void
956 GIC 2407 : ReleaseAuxProcessResourcesCallback(int code, Datum arg)
957 : {
958 2407 : bool isCommit = (code == 0);
959 :
960 2407 : ReleaseAuxProcessResources(isCommit);
961 CBC 2407 : }
962 :
963 :
964 : /*
965 : * Make sure there is room for at least one more entry in a ResourceOwner's
966 : * buffer array.
967 ECB : *
968 : * This is separate from actually inserting an entry because if we run out
969 : * of memory, it's critical to do so *before* acquiring the resource.
970 : */
971 : void
972 GIC 84925049 : ResourceOwnerEnlargeBuffers(ResourceOwner owner)
973 ECB : {
974 : /* We used to allow pinning buffers without a resowner, but no more */
975 GIC 84925049 : Assert(owner != NULL);
976 CBC 84925049 : ResourceArrayEnlarge(&(owner->bufferarr));
977 GIC 84925049 : }
978 :
979 : /*
980 : * Remember that a buffer pin is owned by a ResourceOwner
981 : *
982 : * Caller must have previously done ResourceOwnerEnlargeBuffers()
983 ECB : */
984 : void
985 CBC 83570573 : ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
986 : {
987 83570573 : ResourceArrayAdd(&(owner->bufferarr), BufferGetDatum(buffer));
988 83570573 : }
989 :
990 : /*
991 : * Forget that a buffer pin is owned by a ResourceOwner
992 : */
993 : void
994 GIC 83570573 : ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
995 : {
996 83570573 : if (!ResourceArrayRemove(&(owner->bufferarr), BufferGetDatum(buffer)))
997 UIC 0 : elog(ERROR, "buffer %d is not owned by resource owner %s",
998 : buffer, owner->name);
999 CBC 83570573 : }
1000 :
1001 :
1002 : /*
1003 : * Make sure there is room for at least one more entry in a ResourceOwner's
1004 : * buffer array.
1005 : *
1006 : * This is separate from actually inserting an entry because if we run out
1007 : * of memory, it's critical to do so *before* acquiring the resource.
1008 : */
1009 : void
1010 GNC 2601190 : ResourceOwnerEnlargeBufferIOs(ResourceOwner owner)
1011 : {
1012 : /* We used to allow pinning buffers without a resowner, but no more */
1013 2601190 : Assert(owner != NULL);
1014 2601190 : ResourceArrayEnlarge(&(owner->bufferioarr));
1015 2601190 : }
1016 :
1017 : /*
1018 : * Remember that a buffer IO is owned by a ResourceOwner
1019 : *
1020 : * Caller must have previously done ResourceOwnerEnlargeBufferIOs()
1021 : */
1022 : void
1023 2599422 : ResourceOwnerRememberBufferIO(ResourceOwner owner, Buffer buffer)
1024 : {
1025 2599422 : ResourceArrayAdd(&(owner->bufferioarr), BufferGetDatum(buffer));
1026 2599422 : }
1027 :
1028 : /*
1029 : * Forget that a buffer IO is owned by a ResourceOwner
1030 : */
1031 : void
1032 2599422 : ResourceOwnerForgetBufferIO(ResourceOwner owner, Buffer buffer)
1033 : {
1034 2599422 : if (!ResourceArrayRemove(&(owner->bufferioarr), BufferGetDatum(buffer)))
1035 UNC 0 : elog(PANIC, "buffer IO %d is not owned by resource owner %s",
1036 : buffer, owner->name);
1037 GNC 2599422 : }
1038 :
1039 : /*
1040 ECB : * Remember that a Local Lock is owned by a ResourceOwner
1041 : *
1042 : * This is different from the other Remember functions in that the list of
1043 : * locks is only a lossy cache. It can hold up to MAX_RESOWNER_LOCKS entries,
1044 : * and when it overflows, we stop tracking locks. The point of only remembering
1045 : * only up to MAX_RESOWNER_LOCKS entries is that if a lot of locks are held,
1046 : * ResourceOwnerForgetLock doesn't need to scan through a large array to find
1047 : * the entry.
1048 : */
1049 : void
1050 CBC 27048592 : ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock)
1051 : {
1052 27048592 : Assert(locallock != NULL);
1053 ECB :
1054 GIC 27048592 : if (owner->nlocks > MAX_RESOWNER_LOCKS)
1055 2034678 : return; /* we have already overflowed */
1056 :
1057 25013914 : if (owner->nlocks < MAX_RESOWNER_LOCKS)
1058 25005006 : owner->locks[owner->nlocks] = locallock;
1059 ECB : else
1060 : {
1061 : /* overflowed */
1062 EUB : }
1063 GIC 25013914 : owner->nlocks++;
1064 ECB : }
1065 :
1066 : /*
1067 : * Forget that a Local Lock is owned by a ResourceOwner
1068 : */
1069 : void
1070 GIC 27048592 : ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock)
1071 : {
1072 : int i;
1073 :
1074 27048592 : if (owner->nlocks > MAX_RESOWNER_LOCKS)
1075 CBC 2177206 : return; /* we have overflowed */
1076 :
1077 GIC 24871386 : Assert(owner->nlocks > 0);
1078 CBC 28514759 : for (i = owner->nlocks - 1; i >= 0; i--)
1079 ECB : {
1080 CBC 28514759 : if (locallock == owner->locks[i])
1081 : {
1082 GIC 24871386 : owner->locks[i] = owner->locks[owner->nlocks - 1];
1083 24871386 : owner->nlocks--;
1084 24871386 : return;
1085 : }
1086 : }
1087 UIC 0 : elog(ERROR, "lock reference %p is not owned by resource owner %s",
1088 ECB : locallock, owner->name);
1089 : }
1090 :
1091 : /*
1092 : * Make sure there is room for at least one more entry in a ResourceOwner's
1093 : * catcache reference array.
1094 : *
1095 : * This is separate from actually inserting an entry because if we run out
1096 : * of memory, it's critical to do so *before* acquiring the resource.
1097 : */
1098 : void
1099 CBC 48196159 : ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner)
1100 EUB : {
1101 GIC 48196159 : ResourceArrayEnlarge(&(owner->catrefarr));
1102 CBC 48196159 : }
1103 :
1104 : /*
1105 : * Remember that a catcache reference is owned by a ResourceOwner
1106 : *
1107 : * Caller must have previously done ResourceOwnerEnlargeCatCacheRefs()
1108 : */
1109 : void
1110 GIC 48196159 : ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple)
1111 : {
1112 48196159 : ResourceArrayAdd(&(owner->catrefarr), PointerGetDatum(tuple));
1113 48196159 : }
1114 :
1115 ECB : /*
1116 : * Forget that a catcache reference is owned by a ResourceOwner
1117 : */
1118 : void
1119 CBC 48196159 : ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple)
1120 ECB : {
1121 GIC 48196159 : if (!ResourceArrayRemove(&(owner->catrefarr), PointerGetDatum(tuple)))
1122 LBC 0 : elog(ERROR, "catcache reference %p is not owned by resource owner %s",
1123 ECB : tuple, owner->name);
1124 GIC 48196159 : }
1125 :
1126 : /*
1127 : * Make sure there is room for at least one more entry in a ResourceOwner's
1128 ECB : * catcache-list reference array.
1129 : *
1130 : * This is separate from actually inserting an entry because if we run out
1131 : * of memory, it's critical to do so *before* acquiring the resource.
1132 : */
1133 : void
1134 GIC 1600190 : ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner)
1135 ECB : {
1136 GIC 1600190 : ResourceArrayEnlarge(&(owner->catlistrefarr));
1137 1600190 : }
1138 :
1139 ECB : /*
1140 : * Remember that a catcache-list reference is owned by a ResourceOwner
1141 : *
1142 : * Caller must have previously done ResourceOwnerEnlargeCatCacheListRefs()
1143 : */
1144 : void
1145 CBC 1600190 : ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
1146 : {
1147 1600190 : ResourceArrayAdd(&(owner->catlistrefarr), PointerGetDatum(list));
1148 1600190 : }
1149 ECB :
1150 : /*
1151 : * Forget that a catcache-list reference is owned by a ResourceOwner
1152 EUB : */
1153 : void
1154 GIC 1600190 : ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list)
1155 : {
1156 1600190 : if (!ResourceArrayRemove(&(owner->catlistrefarr), PointerGetDatum(list)))
1157 UIC 0 : elog(ERROR, "catcache list reference %p is not owned by resource owner %s",
1158 : list, owner->name);
1159 GIC 1600190 : }
1160 :
1161 : /*
1162 : * Make sure there is room for at least one more entry in a ResourceOwner's
1163 : * relcache reference array.
1164 ECB : *
1165 : * This is separate from actually inserting an entry because if we run out
1166 : * of memory, it's critical to do so *before* acquiring the resource.
1167 : */
1168 : void
1169 GIC 40884389 : ResourceOwnerEnlargeRelationRefs(ResourceOwner owner)
1170 : {
1171 40884389 : ResourceArrayEnlarge(&(owner->relrefarr));
1172 40884389 : }
1173 :
1174 : /*
1175 ECB : * Remember that a relcache reference is owned by a ResourceOwner
1176 : *
1177 : * Caller must have previously done ResourceOwnerEnlargeRelationRefs()
1178 : */
1179 : void
1180 GIC 39145584 : ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel)
1181 : {
1182 39145584 : ResourceArrayAdd(&(owner->relrefarr), PointerGetDatum(rel));
1183 39145584 : }
1184 ECB :
1185 : /*
1186 : * Forget that a relcache reference is owned by a ResourceOwner
1187 EUB : */
1188 : void
1189 CBC 39145584 : ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
1190 : {
1191 GIC 39145584 : if (!ResourceArrayRemove(&(owner->relrefarr), PointerGetDatum(rel)))
1192 UIC 0 : elog(ERROR, "relcache reference %s is not owned by resource owner %s",
1193 : RelationGetRelationName(rel), owner->name);
1194 GIC 39145584 : }
1195 :
1196 : /*
1197 : * Debugging subroutine
1198 : */
1199 ECB : static void
1200 UIC 0 : PrintRelCacheLeakWarning(Relation rel)
1201 ECB : {
1202 LBC 0 : elog(WARNING, "relcache reference leak: relation \"%s\" not closed",
1203 : RelationGetRelationName(rel));
1204 UIC 0 : }
1205 :
1206 : /*
1207 : * Make sure there is room for at least one more entry in a ResourceOwner's
1208 : * plancache reference array.
1209 : *
1210 ECB : * This is separate from actually inserting an entry because if we run out
1211 : * of memory, it's critical to do so *before* acquiring the resource.
1212 : */
1213 : void
1214 GIC 83803 : ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
1215 : {
1216 83803 : ResourceArrayEnlarge(&(owner->planrefarr));
1217 83803 : }
1218 :
1219 ECB : /*
1220 : * Remember that a plancache reference is owned by a ResourceOwner
1221 : *
1222 EUB : * Caller must have previously done ResourceOwnerEnlargePlanCacheRefs()
1223 : */
1224 ECB : void
1225 GIC 83803 : ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
1226 : {
1227 83803 : ResourceArrayAdd(&(owner->planrefarr), PointerGetDatum(plan));
1228 83803 : }
1229 :
1230 : /*
1231 : * Forget that a plancache reference is owned by a ResourceOwner
1232 : */
1233 : void
1234 CBC 83803 : ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
1235 : {
1236 83803 : if (!ResourceArrayRemove(&(owner->planrefarr), PointerGetDatum(plan)))
1237 LBC 0 : elog(ERROR, "plancache reference %p is not owned by resource owner %s",
1238 : plan, owner->name);
1239 GIC 83803 : }
1240 :
1241 : /*
1242 : * Debugging subroutine
1243 : */
1244 : static void
1245 LBC 0 : PrintPlanCacheLeakWarning(CachedPlan *plan)
1246 : {
1247 0 : elog(WARNING, "plancache reference leak: plan %p not closed", plan);
1248 0 : }
1249 :
1250 : /*
1251 : * Make sure there is room for at least one more entry in a ResourceOwner's
1252 : * tupdesc reference array.
1253 : *
1254 ECB : * This is separate from actually inserting an entry because if we run out
1255 : * of memory, it's critical to do so *before* acquiring the resource.
1256 : */
1257 EUB : void
1258 GIC 21264947 : ResourceOwnerEnlargeTupleDescs(ResourceOwner owner)
1259 ECB : {
1260 GIC 21264947 : ResourceArrayEnlarge(&(owner->tupdescarr));
1261 21264947 : }
1262 :
1263 : /*
1264 : * Remember that a tupdesc reference is owned by a ResourceOwner
1265 EUB : *
1266 : * Caller must have previously done ResourceOwnerEnlargeTupleDescs()
1267 : */
1268 : void
1269 GBC 21264947 : ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
1270 : {
1271 GIC 21264947 : ResourceArrayAdd(&(owner->tupdescarr), PointerGetDatum(tupdesc));
1272 21264947 : }
1273 :
1274 : /*
1275 : * Forget that a tupdesc reference is owned by a ResourceOwner
1276 : */
1277 : void
1278 21264947 : ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
1279 ECB : {
1280 GIC 21264947 : if (!ResourceArrayRemove(&(owner->tupdescarr), PointerGetDatum(tupdesc)))
1281 LBC 0 : elog(ERROR, "tupdesc reference %p is not owned by resource owner %s",
1282 ECB : tupdesc, owner->name);
1283 GIC 21264947 : }
1284 :
1285 : /*
1286 : * Debugging subroutine
1287 : */
1288 : static void
1289 UIC 0 : PrintTupleDescLeakWarning(TupleDesc tupdesc)
1290 ECB : {
1291 UIC 0 : elog(WARNING,
1292 ECB : "TupleDesc reference leak: TupleDesc %p (%u,%d) still referenced",
1293 : tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
1294 UIC 0 : }
1295 :
1296 : /*
1297 : * Make sure there is room for at least one more entry in a ResourceOwner's
1298 : * snapshot reference array.
1299 ECB : *
1300 : * This is separate from actually inserting an entry because if we run out
1301 : * of memory, it's critical to do so *before* acquiring the resource.
1302 EUB : */
1303 : void
1304 CBC 8845361 : ResourceOwnerEnlargeSnapshots(ResourceOwner owner)
1305 : {
1306 GIC 8845361 : ResourceArrayEnlarge(&(owner->snapshotarr));
1307 8845361 : }
1308 :
1309 : /*
1310 EUB : * Remember that a snapshot reference is owned by a ResourceOwner
1311 : *
1312 : * Caller must have previously done ResourceOwnerEnlargeSnapshots()
1313 : */
1314 : void
1315 GIC 8845361 : ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot)
1316 : {
1317 8845361 : ResourceArrayAdd(&(owner->snapshotarr), PointerGetDatum(snapshot));
1318 8845361 : }
1319 :
1320 : /*
1321 : * Forget that a snapshot reference is owned by a ResourceOwner
1322 : */
1323 ECB : void
1324 GIC 8845361 : ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot)
1325 ECB : {
1326 CBC 8845361 : if (!ResourceArrayRemove(&(owner->snapshotarr), PointerGetDatum(snapshot)))
1327 UIC 0 : elog(ERROR, "snapshot reference %p is not owned by resource owner %s",
1328 : snapshot, owner->name);
1329 GIC 8845361 : }
1330 :
1331 : /*
1332 : * Debugging subroutine
1333 : */
1334 ECB : static void
1335 UIC 0 : PrintSnapshotLeakWarning(Snapshot snapshot)
1336 ECB : {
1337 LBC 0 : elog(WARNING, "Snapshot reference leak: Snapshot %p still referenced",
1338 : snapshot);
1339 UIC 0 : }
1340 :
1341 :
1342 : /*
1343 ECB : * Make sure there is room for at least one more entry in a ResourceOwner's
1344 : * files reference array.
1345 : *
1346 EUB : * This is separate from actually inserting an entry because if we run out
1347 : * of memory, it's critical to do so *before* acquiring the resource.
1348 ECB : */
1349 : void
1350 GIC 7446 : ResourceOwnerEnlargeFiles(ResourceOwner owner)
1351 : {
1352 7446 : ResourceArrayEnlarge(&(owner->filearr));
1353 7446 : }
1354 EUB :
1355 : /*
1356 : * Remember that a temporary file is owned by a ResourceOwner
1357 : *
1358 : * Caller must have previously done ResourceOwnerEnlargeFiles()
1359 : */
1360 : void
1361 GIC 5110 : ResourceOwnerRememberFile(ResourceOwner owner, File file)
1362 : {
1363 5110 : ResourceArrayAdd(&(owner->filearr), FileGetDatum(file));
1364 5110 : }
1365 :
1366 : /*
1367 : * Forget that a temporary file is owned by a ResourceOwner
1368 : */
1369 ECB : void
1370 GIC 5110 : ResourceOwnerForgetFile(ResourceOwner owner, File file)
1371 ECB : {
1372 CBC 5110 : if (!ResourceArrayRemove(&(owner->filearr), FileGetDatum(file)))
1373 UIC 0 : elog(ERROR, "temporary file %d is not owned by resource owner %s",
1374 : file, owner->name);
1375 GIC 5110 : }
1376 :
1377 : /*
1378 : * Debugging subroutine
1379 : */
1380 ECB : static void
1381 UIC 0 : PrintFileLeakWarning(File file)
1382 ECB : {
1383 LBC 0 : elog(WARNING, "temporary file leak: File %d still referenced",
1384 : file);
1385 UIC 0 : }
1386 :
1387 : /*
1388 : * Make sure there is room for at least one more entry in a ResourceOwner's
1389 ECB : * dynamic shmem segment reference array.
1390 : *
1391 : * This is separate from actually inserting an entry because if we run out
1392 EUB : * of memory, it's critical to do so *before* acquiring the resource.
1393 : */
1394 ECB : void
1395 GIC 14798 : ResourceOwnerEnlargeDSMs(ResourceOwner owner)
1396 : {
1397 14798 : ResourceArrayEnlarge(&(owner->dsmarr));
1398 14798 : }
1399 :
1400 EUB : /*
1401 : * Remember that a dynamic shmem segment is owned by a ResourceOwner
1402 : *
1403 : * Caller must have previously done ResourceOwnerEnlargeDSMs()
1404 : */
1405 : void
1406 GIC 14798 : ResourceOwnerRememberDSM(ResourceOwner owner, dsm_segment *seg)
1407 : {
1408 14798 : ResourceArrayAdd(&(owner->dsmarr), PointerGetDatum(seg));
1409 14798 : }
1410 :
1411 : /*
1412 : * Forget that a dynamic shmem segment is owned by a ResourceOwner
1413 : */
1414 : void
1415 CBC 14798 : ResourceOwnerForgetDSM(ResourceOwner owner, dsm_segment *seg)
1416 : {
1417 14798 : if (!ResourceArrayRemove(&(owner->dsmarr), PointerGetDatum(seg)))
1418 LBC 0 : elog(ERROR, "dynamic shared memory segment %u is not owned by resource owner %s",
1419 : dsm_segment_handle(seg), owner->name);
1420 GIC 14798 : }
1421 :
1422 : /*
1423 : * Debugging subroutine
1424 : */
1425 : static void
1426 LBC 0 : PrintDSMLeakWarning(dsm_segment *seg)
1427 : {
1428 0 : elog(WARNING, "dynamic shared memory leak: segment %u still referenced",
1429 ECB : dsm_segment_handle(seg));
1430 UIC 0 : }
1431 :
1432 : /*
1433 : * Make sure there is room for at least one more entry in a ResourceOwner's
1434 : * JIT context reference array.
1435 ECB : *
1436 : * This is separate from actually inserting an entry because if we run out of
1437 : * memory, it's critical to do so *before* acquiring the resource.
1438 EUB : */
1439 : void
1440 CBC 839 : ResourceOwnerEnlargeJIT(ResourceOwner owner)
1441 : {
1442 GIC 839 : ResourceArrayEnlarge(&(owner->jitarr));
1443 839 : }
1444 :
1445 : /*
1446 EUB : * Remember that a JIT context is owned by a ResourceOwner
1447 : *
1448 : * Caller must have previously done ResourceOwnerEnlargeJIT()
1449 : */
1450 : void
1451 GIC 839 : ResourceOwnerRememberJIT(ResourceOwner owner, Datum handle)
1452 : {
1453 839 : ResourceArrayAdd(&(owner->jitarr), handle);
1454 839 : }
1455 :
1456 : /*
1457 : * Forget that a JIT context is owned by a ResourceOwner
1458 : */
1459 : void
1460 CBC 839 : ResourceOwnerForgetJIT(ResourceOwner owner, Datum handle)
1461 : {
1462 839 : if (!ResourceArrayRemove(&(owner->jitarr), handle))
1463 LBC 0 : elog(ERROR, "JIT context %p is not owned by resource owner %s",
1464 : DatumGetPointer(handle), owner->name);
1465 GIC 839 : }
1466 :
1467 : /*
1468 : * Make sure there is room for at least one more entry in a ResourceOwner's
1469 : * cryptohash context reference array.
1470 : *
1471 ECB : * This is separate from actually inserting an entry because if we run out of
1472 : * memory, it's critical to do so *before* acquiring the resource.
1473 : */
1474 : void
1475 GIC 499247 : ResourceOwnerEnlargeCryptoHash(ResourceOwner owner)
1476 : {
1477 499247 : ResourceArrayEnlarge(&(owner->cryptohasharr));
1478 499247 : }
1479 :
1480 ECB : /*
1481 : * Remember that a cryptohash context is owned by a ResourceOwner
1482 : *
1483 EUB : * Caller must have previously done ResourceOwnerEnlargeCryptoHash()
1484 : */
1485 ECB : void
1486 GIC 499247 : ResourceOwnerRememberCryptoHash(ResourceOwner owner, Datum handle)
1487 : {
1488 499247 : ResourceArrayAdd(&(owner->cryptohasharr), handle);
1489 499247 : }
1490 :
1491 EUB : /*
1492 : * Forget that a cryptohash context is owned by a ResourceOwner
1493 : */
1494 : void
1495 GBC 499242 : ResourceOwnerForgetCryptoHash(ResourceOwner owner, Datum handle)
1496 : {
1497 GIC 499242 : if (!ResourceArrayRemove(&(owner->cryptohasharr), handle))
1498 UIC 0 : elog(ERROR, "cryptohash context %p is not owned by resource owner %s",
1499 : DatumGetPointer(handle), owner->name);
1500 GIC 499242 : }
1501 :
1502 : /*
1503 : * Debugging subroutine
1504 : */
1505 ECB : static void
1506 UIC 0 : PrintCryptoHashLeakWarning(Datum handle)
1507 ECB : {
1508 LBC 0 : elog(WARNING, "cryptohash context reference leak: context %p still referenced",
1509 : DatumGetPointer(handle));
1510 UIC 0 : }
1511 :
1512 : /*
1513 : * Make sure there is room for at least one more entry in a ResourceOwner's
1514 : * hmac context reference array.
1515 : *
1516 ECB : * This is separate from actually inserting an entry because if we run out of
1517 : * memory, it's critical to do so *before* acquiring the resource.
1518 : */
1519 : void
1520 GIC 216 : ResourceOwnerEnlargeHMAC(ResourceOwner owner)
1521 : {
1522 216 : ResourceArrayEnlarge(&(owner->hmacarr));
1523 216 : }
1524 :
1525 ECB : /*
1526 : * Remember that a HMAC context is owned by a ResourceOwner
1527 : *
1528 EUB : * Caller must have previously done ResourceOwnerEnlargeHMAC()
1529 : */
1530 ECB : void
1531 GIC 216 : ResourceOwnerRememberHMAC(ResourceOwner owner, Datum handle)
1532 : {
1533 216 : ResourceArrayAdd(&(owner->hmacarr), handle);
1534 216 : }
1535 :
1536 : /*
1537 : * Forget that a HMAC context is owned by a ResourceOwner
1538 : */
1539 : void
1540 CBC 216 : ResourceOwnerForgetHMAC(ResourceOwner owner, Datum handle)
1541 : {
1542 216 : if (!ResourceArrayRemove(&(owner->hmacarr), handle))
1543 LBC 0 : elog(ERROR, "HMAC context %p is not owned by resource owner %s",
1544 : DatumGetPointer(handle), owner->name);
1545 GIC 216 : }
1546 :
1547 : /*
1548 : * Debugging subroutine
1549 : */
1550 : static void
1551 LBC 0 : PrintHMACLeakWarning(Datum handle)
1552 : {
1553 0 : elog(WARNING, "HMAC context reference leak: context %p still referenced",
1554 ECB : DatumGetPointer(handle));
1555 UIC 0 : }
|