Age Owner 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
2630 tgl 196 GIC 13078767 : ResourceArrayInit(ResourceArray *resarr, Datum invalidval)
2630 tgl 197 ECB : {
198 : /* Assert it's empty */
2630 tgl 199 GIC 13078767 : Assert(resarr->itemsarr == NULL);
2630 tgl 200 CBC 13078767 : Assert(resarr->capacity == 0);
201 13078767 : Assert(resarr->nitems == 0);
202 13078767 : Assert(resarr->maxitems == 0);
2630 tgl 203 ECB : /* Remember the appropriate "invalid" value */
2630 tgl 204 GIC 13078767 : resarr->invalidval = invalidval;
2630 tgl 205 ECB : /* We don't allocate any storage until needed */
2630 tgl 206 GIC 13078767 : }
2630 tgl 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
2630 tgl 215 GIC 208923634 : ResourceArrayEnlarge(ResourceArray *resarr)
2630 tgl 216 ECB : {
217 : uint32 i,
218 : oldcap,
219 : newcap;
220 : Datum *olditemsarr;
221 : Datum *newitemsarr;
222 :
2630 tgl 223 GIC 208923634 : if (resarr->nitems < resarr->maxitems)
2630 tgl 224 CBC 205506208 : return; /* no work needed */
2630 tgl 225 ECB :
2630 tgl 226 GIC 3417426 : olditemsarr = resarr->itemsarr;
2630 tgl 227 CBC 3417426 : oldcap = resarr->capacity;
2630 tgl 228 ECB :
229 : /* Double the capacity of the array (capacity must stay a power of 2!) */
2630 tgl 230 GIC 3417426 : newcap = (oldcap > 0) ? oldcap * 2 : RESARRAY_INIT_SIZE;
2630 tgl 231 CBC 3417426 : newitemsarr = (Datum *) MemoryContextAlloc(TopMemoryContext,
2630 tgl 232 ECB : newcap * sizeof(Datum));
2630 tgl 233 GIC 59757586 : for (i = 0; i < newcap; i++)
2630 tgl 234 CBC 56340160 : newitemsarr[i] = resarr->invalidval;
2630 tgl 235 ECB :
236 : /* We assume we can't fail below this point, so OK to scribble on resarr */
2630 tgl 237 GIC 3417426 : resarr->itemsarr = newitemsarr;
2630 tgl 238 CBC 3417426 : resarr->capacity = newcap;
239 3417426 : resarr->maxitems = RESARRAY_MAX_ITEMS(newcap);
240 3417426 : resarr->nitems = 0;
2630 tgl 241 ECB :
2630 tgl 242 GIC 3417426 : if (olditemsarr != NULL)
2630 tgl 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 : */
2630 tgl 251 GIC 953306 : for (i = 0; i < oldcap; i++)
2630 tgl 252 ECB : {
2630 tgl 253 GIC 939680 : if (olditemsarr[i] != resarr->invalidval)
2630 tgl 254 CBC 769696 : ResourceArrayAdd(resarr, olditemsarr[i]);
2630 tgl 255 ECB : }
256 :
257 : /* And release old array. */
2630 tgl 258 GIC 13626 : pfree(olditemsarr);
2630 tgl 259 ECB : }
260 :
2630 tgl 261 GIC 3417426 : Assert(resarr->nitems < resarr->maxitems);
2630 tgl 262 ECB : }
263 :
264 : /*
265 : * Add a resource to ResourceArray
266 : *
267 : * Caller must have previously done ResourceArrayEnlarge()
268 : */
269 : static void
2630 tgl 270 GIC 206595945 : ResourceArrayAdd(ResourceArray *resarr, Datum value)
2630 tgl 271 ECB : {
272 : uint32 idx;
273 :
2630 tgl 274 GIC 206595945 : Assert(value != resarr->invalidval);
2630 tgl 275 CBC 206595945 : Assert(resarr->nitems < resarr->maxitems);
2630 tgl 276 ECB :
2630 tgl 277 GIC 206595945 : if (RESARRAY_IS_ARRAY(resarr))
2630 tgl 278 ECB : {
279 : /* Append to linear array. */
2630 tgl 280 GIC 205411741 : idx = resarr->nitems;
2630 tgl 281 ECB : }
282 : else
283 : {
284 : /* Insert into first free slot at or after hash location. */
2630 tgl 285 GIC 1184204 : uint32 mask = resarr->capacity - 1;
2630 tgl 286 ECB :
2630 tgl 287 GIC 1184204 : idx = DatumGetUInt32(hash_any((void *) &value, sizeof(value))) & mask;
2630 tgl 288 ECB : for (;;)
289 : {
2630 tgl 290 GIC 392068502 : if (resarr->itemsarr[idx] == resarr->invalidval)
2630 tgl 291 CBC 1184204 : break;
292 390884298 : idx = (idx + 1) & mask;
2630 tgl 293 ECB : }
294 : }
2630 tgl 295 GIC 206595945 : resarr->lastidx = idx;
2630 tgl 296 CBC 206595945 : resarr->itemsarr[idx] = value;
297 206595945 : resarr->nitems++;
298 206595945 : }
2630 tgl 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
2630 tgl 308 GIC 205826244 : ResourceArrayRemove(ResourceArray *resarr, Datum value)
2630 tgl 309 ECB : {
310 : uint32 i,
311 : idx,
2630 tgl 312 GIC 205826244 : lastidx = resarr->lastidx;
2630 tgl 313 ECB :
2630 tgl 314 GIC 205826244 : Assert(value != resarr->invalidval);
2630 tgl 315 ECB :
316 : /* Search through all items, but try lastidx first. */
2630 tgl 317 GIC 205826244 : if (RESARRAY_IS_ARRAY(resarr))
2630 tgl 318 ECB : {
2630 tgl 319 GIC 205151992 : if (lastidx < resarr->nitems &&
2630 tgl 320 CBC 205151992 : resarr->itemsarr[lastidx] == value)
2630 tgl 321 ECB : {
2630 tgl 322 GIC 199281187 : resarr->itemsarr[lastidx] = resarr->itemsarr[resarr->nitems - 1];
2630 tgl 323 CBC 199281187 : resarr->nitems--;
2630 tgl 324 ECB : /* Update lastidx to make reverse-order removals fast. */
2630 tgl 325 GIC 199281187 : resarr->lastidx = resarr->nitems - 1;
2630 tgl 326 CBC 199281187 : return true;
2630 tgl 327 ECB : }
2630 tgl 328 GIC 12783604 : for (i = 0; i < resarr->nitems; i++)
2630 tgl 329 ECB : {
2630 tgl 330 GIC 12783604 : if (resarr->itemsarr[i] == value)
2630 tgl 331 ECB : {
2630 tgl 332 GIC 5870805 : resarr->itemsarr[i] = resarr->itemsarr[resarr->nitems - 1];
2630 tgl 333 CBC 5870805 : resarr->nitems--;
2630 tgl 334 ECB : /* Update lastidx to make reverse-order removals fast. */
2630 tgl 335 GIC 5870805 : resarr->lastidx = resarr->nitems - 1;
2630 tgl 336 CBC 5870805 : return true;
2630 tgl 337 ECB : }
338 : }
339 : }
340 : else
341 : {
2630 tgl 342 GIC 674252 : uint32 mask = resarr->capacity - 1;
2630 tgl 343 ECB :
2630 tgl 344 GIC 674252 : if (lastidx < resarr->capacity &&
2630 tgl 345 CBC 674252 : resarr->itemsarr[lastidx] == value)
2630 tgl 346 ECB : {
2630 tgl 347 GIC 199252 : resarr->itemsarr[lastidx] = resarr->invalidval;
2630 tgl 348 CBC 199252 : resarr->nitems--;
349 199252 : return true;
2630 tgl 350 ECB : }
2630 tgl 351 GIC 475000 : idx = DatumGetUInt32(hash_any((void *) &value, sizeof(value))) & mask;
2630 tgl 352 CBC 171789826 : for (i = 0; i < resarr->capacity; i++)
2630 tgl 353 ECB : {
2630 tgl 354 GIC 171789826 : if (resarr->itemsarr[idx] == value)
2630 tgl 355 ECB : {
2630 tgl 356 GIC 475000 : resarr->itemsarr[idx] = resarr->invalidval;
2630 tgl 357 CBC 475000 : resarr->nitems--;
358 475000 : return true;
2630 tgl 359 ECB : }
2630 tgl 360 GIC 171314826 : idx = (idx + 1) & mask;
2630 tgl 361 ECB : }
362 : }
363 :
2630 tgl 364 UIC 0 : return false;
2630 tgl 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
2630 tgl 377 GIC 13180874 : ResourceArrayGetAny(ResourceArray *resarr, Datum *value)
2630 tgl 378 ECB : {
2630 tgl 379 GIC 13180874 : if (resarr->nitems == 0)
2630 tgl 380 CBC 13088006 : return false;
2630 tgl 381 ECB :
2630 tgl 382 GIC 92868 : if (RESARRAY_IS_ARRAY(resarr))
2630 tgl 383 ECB : {
384 : /* Linear array: just return the first element. */
2630 tgl 385 GIC 83885 : resarr->lastidx = 0;
2630 tgl 386 ECB : }
387 : else
388 : {
389 : /* Hash: search forward from wherever we were last. */
2630 tgl 390 GIC 8983 : uint32 mask = resarr->capacity - 1;
2630 tgl 391 ECB :
392 : for (;;)
393 : {
2630 tgl 394 GIC 22149 : resarr->lastidx &= mask;
2630 tgl 395 CBC 22149 : if (resarr->itemsarr[resarr->lastidx] != resarr->invalidval)
396 8983 : break;
397 13166 : resarr->lastidx++;
2630 tgl 398 ECB : }
399 : }
400 :
2630 tgl 401 GIC 92868 : *value = resarr->itemsarr[resarr->lastidx];
2630 tgl 402 CBC 92868 : return true;
2630 tgl 403 ECB : }
404 :
405 : /*
406 : * Trash a ResourceArray (we don't care about its state after this)
407 : */
408 : static void
2630 tgl 409 GIC 13047411 : ResourceArrayFree(ResourceArray *resarr)
2630 tgl 410 ECB : {
2630 tgl 411 GIC 13047411 : if (resarr->itemsarr)
2630 tgl 412 CBC 3400021 : pfree(resarr->itemsarr);
413 13047411 : }
2630 tgl 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
6840 tgl 429 GIC 1006059 : ResourceOwnerCreate(ResourceOwner parent, const char *name)
6840 tgl 430 ECB : {
431 : ResourceOwner owner;
432 :
6840 tgl 433 GIC 1006059 : owner = (ResourceOwner) MemoryContextAllocZero(TopMemoryContext,
6385 bruce 434 ECB : sizeof(ResourceOwnerData));
6840 tgl 435 GIC 1006059 : owner->name = name;
6840 tgl 436 ECB :
6840 tgl 437 GIC 1006059 : if (parent)
6840 tgl 438 ECB : {
6840 tgl 439 GIC 516105 : owner->parent = parent;
6840 tgl 440 CBC 516105 : owner->nextchild = parent->firstchild;
441 516105 : parent->firstchild = owner;
6840 tgl 442 ECB : }
443 :
2630 tgl 444 GIC 1006059 : ResourceArrayInit(&(owner->bufferarr), BufferGetDatum(InvalidBuffer));
4 andres 445 GNC 1006059 : ResourceArrayInit(&(owner->bufferioarr), BufferGetDatum(InvalidBuffer));
2630 tgl 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));
1845 andres 454 1006059 : ResourceArrayInit(&(owner->jitarr), PointerGetDatum(NULL));
856 michael 455 1006059 : ResourceArrayInit(&(owner->cryptohasharr), PointerGetDatum(NULL));
736 456 1006059 : ResourceArrayInit(&(owner->hmacarr), PointerGetDatum(NULL));
2630 tgl 457 ECB :
6840 tgl 458 CBC 1006059 : return owner;
459 : }
6840 tgl 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
6840 tgl 488 GIC 2932668 : ResourceOwnerRelease(ResourceOwner owner,
489 : ResourceReleasePhase phase,
6840 tgl 490 ECB : bool isCommit,
491 : bool isTopLevel)
492 : {
493 : /* There's not currently any setup needed before recursing */
2006 tgl 494 GIC 2932668 : ResourceOwnerReleaseInternal(owner, phase, isCommit, isTopLevel);
6826 495 2932668 : }
6826 tgl 496 ECB :
497 : static void
6826 tgl 498 GIC 3018624 : ResourceOwnerReleaseInternal(ResourceOwner owner,
499 : ResourceReleasePhase phase,
6826 tgl 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 */
6840 tgl 510 GIC 3104580 : for (child = owner->firstchild; child != NULL; child = child->nextchild)
6826 511 85956 : ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel);
512 :
6840 tgl 513 ECB : /*
6385 bruce 514 : * Make CurrentResourceOwner point to me, so that ReleaseBuffer etc don't
515 : * get confused.
516 : */
6840 tgl 517 GIC 3018624 : save = CurrentResourceOwner;
518 3018624 : CurrentResourceOwner = owner;
519 :
6840 tgl 520 CBC 3018624 : if (phase == RESOURCE_RELEASE_BEFORE_LOCKS)
6840 tgl 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 : */
4 andres 531 GNC 1006221 : while (ResourceArrayGetAny(&(owner->bufferioarr), &foundres))
532 : {
533 13 : Buffer res = DatumGetBuffer(foundres);
534 :
535 13 : if (isCommit)
4 andres 536 UNC 0 : elog(PANIC, "lost track of buffer IO on buffer %u", res);
4 andres 537 GNC 13 : AbortBufferIO(res);
538 : }
539 :
540 : /*
6385 bruce 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 : */
2630 tgl 549 GIC 1009873 : while (ResourceArrayGetAny(&(owner->bufferarr), &foundres))
550 : {
551 3665 : Buffer res = DatumGetBuffer(foundres);
2630 tgl 552 ECB :
6749 tgl 553 GIC 3665 : if (isCommit)
2630 tgl 554 LBC 0 : PrintBufferLeakWarning(res);
2630 tgl 555 GIC 3665 : ReleaseBuffer(res);
6840 tgl 556 ECB : }
6749 tgl 557 EUB :
2630 tgl 558 ECB : /* Ditto for relcache references */
2630 tgl 559 GIC 1022070 : while (ResourceArrayGetAny(&(owner->relrefarr), &foundres))
560 : {
561 15862 : Relation res = (Relation) DatumGetPointer(foundres);
562 :
6453 563 15862 : if (isCommit)
2630 tgl 564 UIC 0 : PrintRelCacheLeakWarning(res);
2630 tgl 565 GIC 15862 : RelationClose(res);
566 : }
567 :
568 : /* Ditto for dynamic shared memory segments */
569 1006208 : while (ResourceArrayGetAny(&(owner->dsmarr), &foundres))
3469 rhaas 570 ECB : {
2630 tgl 571 UIC 0 : dsm_segment *res = (dsm_segment *) DatumGetPointer(foundres);
2630 tgl 572 ECB :
3469 rhaas 573 UIC 0 : if (isCommit)
2630 tgl 574 LBC 0 : PrintDSMLeakWarning(res);
2630 tgl 575 UBC 0 : dsm_detach(res);
3469 rhaas 576 ECB : }
577 :
578 : /* Ditto for JIT contexts */
1845 andres 579 GIC 1006216 : while (ResourceArrayGetAny(&(owner->jitarr), &foundres))
1845 andres 580 ECB : {
224 peter 581 GNC 8 : JitContext *context = (JitContext *) DatumGetPointer(foundres);
1845 andres 582 ECB :
1845 andres 583 GIC 8 : jit_release_context(context);
1845 andres 584 ECB : }
856 michael 585 EUB :
856 michael 586 ECB : /* Ditto for cryptohash contexts */
856 michael 587 GIC 1006212 : while (ResourceArrayGetAny(&(owner->cryptohasharr), &foundres))
588 : {
589 : pg_cryptohash_ctx *context =
224 peter 590 GNC 4 : (pg_cryptohash_ctx *) DatumGetPointer(foundres);
591 :
856 michael 592 GBC 4 : if (isCommit)
856 michael 593 UIC 0 : PrintCryptoHashLeakWarning(foundres);
856 michael 594 GBC 4 : pg_cryptohash_free(context);
856 michael 595 EUB : }
736 596 :
597 : /* Ditto for HMAC contexts */
736 michael 598 GIC 1006208 : while (ResourceArrayGetAny(&(owner->hmacarr), &foundres))
599 : {
224 peter 600 UNC 0 : pg_hmac_ctx *context = (pg_hmac_ctx *) DatumGetPointer(foundres);
601 :
736 michael 602 LBC 0 : if (isCommit)
736 michael 603 UIC 0 : PrintHMACLeakWarning(foundres);
736 michael 604 LBC 0 : pg_hmac_free(context);
605 : }
606 : }
6840 tgl 607 GIC 2012416 : else if (phase == RESOURCE_RELEASE_LOCKS)
6840 tgl 608 ECB : {
6840 tgl 609 GIC 1006208 : if (isTopLevel)
610 : {
6840 tgl 611 ECB : /*
612 : * For a top-level xact we are going to release all locks (or at
6385 bruce 613 : * least all non-session locks), so just do a single lmgr call at
6385 bruce 614 EUB : * the top of the recursion.
6840 tgl 615 ECB : */
6840 tgl 616 GIC 518632 : if (owner == TopTransactionResourceOwner)
617 : {
618 486958 : ProcReleaseLocks(isCommit);
1486 tmunro 619 CBC 486958 : ReleasePredicateLocks(isCommit, false);
620 : }
6840 tgl 621 EUB : }
622 : else
623 : {
624 : /*
6799 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.
6840 tgl 628 ECB : */
629 : LOCALLOCK **locks;
3944 heikki.linnakangas 630 : int nlocks;
631 :
6801 tgl 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.
3944 heikki.linnakangas 637 ECB : */
3944 heikki.linnakangas 638 GIC 487576 : if (owner->nlocks > MAX_RESOWNER_LOCKS)
3944 heikki.linnakangas 639 ECB : {
3944 heikki.linnakangas 640 CBC 3495 : locks = NULL;
3944 heikki.linnakangas 641 GIC 3495 : nlocks = 0;
642 : }
643 : else
644 : {
645 484081 : locks = owner->locks;
646 484081 : nlocks = owner->nlocks;
647 : }
648 :
6799 tgl 649 487576 : if (isCommit)
3944 heikki.linnakangas 650 482967 : LockReassignCurrentOwner(locks, nlocks);
651 : else
652 4609 : LockReleaseCurrentOwner(locks, nlocks);
6840 tgl 653 ECB : }
654 : }
6840 tgl 655 GIC 1006208 : else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
656 : {
657 : /*
658 : * Release catcache references. Note that ReleaseCatCache will remove
2630 tgl 659 ECB : * the catref entry from our array, so we just have to iterate till
660 : * there are none.
6453 661 : *
2630 662 : * As with buffer pins, warn if any are left at commit time.
663 : */
2630 tgl 664 GIC 1010879 : while (ResourceArrayGetAny(&(owner->catrefarr), &foundres))
665 : {
2630 tgl 666 CBC 4671 : HeapTuple res = (HeapTuple) DatumGetPointer(foundres);
2630 tgl 667 ECB :
6453 tgl 668 GIC 4671 : if (isCommit)
2630 tgl 669 UIC 0 : PrintCatCacheLeakWarning(res);
2630 tgl 670 CBC 4671 : ReleaseCatCache(res);
6840 tgl 671 ECB : }
672 :
6141 673 : /* Ditto for catcache lists */
2630 tgl 674 GIC 1006226 : while (ResourceArrayGetAny(&(owner->catlistrefarr), &foundres))
675 : {
2630 tgl 676 CBC 18 : CatCList *res = (CatCList *) DatumGetPointer(foundres);
677 :
6453 tgl 678 GIC 18 : if (isCommit)
2630 tgl 679 UIC 0 : PrintCatCacheListLeakWarning(res);
2630 tgl 680 GIC 18 : ReleaseCatCacheList(res);
681 : }
682 :
683 : /* Ditto for plancache references */
684 1011274 : while (ResourceArrayGetAny(&(owner->planrefarr), &foundres))
5871 tgl 685 ECB : {
2630 tgl 686 GIC 5066 : CachedPlan *res = (CachedPlan *) DatumGetPointer(foundres);
2630 tgl 687 ECB :
5871 tgl 688 GIC 5066 : if (isCommit)
2630 tgl 689 LBC 0 : PrintPlanCacheLeakWarning(res);
804 tgl 690 GBC 5066 : ReleaseCachedPlan(res, owner);
5871 tgl 691 ECB : }
692 :
693 : /* Ditto for tupdesc references */
2630 tgl 694 GIC 1011717 : while (ResourceArrayGetAny(&(owner->tupdescarr), &foundres))
6141 tgl 695 ECB : {
2630 tgl 696 GIC 5509 : TupleDesc res = (TupleDesc) DatumGetPointer(foundres);
2630 tgl 697 ECB :
6141 tgl 698 GIC 5509 : if (isCommit)
2630 tgl 699 LBC 0 : PrintTupleDescLeakWarning(res);
2630 tgl 700 GBC 5509 : DecrTupleDescRefCount(res);
6141 tgl 701 ECB : }
702 :
703 : /* Ditto for snapshot references */
2630 tgl 704 GIC 1031379 : while (ResourceArrayGetAny(&(owner->snapshotarr), &foundres))
5248 alvherre 705 ECB : {
2630 tgl 706 GIC 25171 : Snapshot res = (Snapshot) DatumGetPointer(foundres);
2630 tgl 707 ECB :
5248 alvherre 708 GIC 25171 : if (isCommit)
2630 tgl 709 LBC 0 : PrintSnapshotLeakWarning(res);
2630 tgl 710 GBC 25171 : UnregisterSnapshot(res);
5248 alvherre 711 ECB : }
712 :
713 : /* Ditto for temporary files */
2630 tgl 714 GIC 1006212 : while (ResourceArrayGetAny(&(owner->filearr), &foundres))
4875 heikki.linnakangas 715 ECB : {
2630 tgl 716 GIC 4 : File res = DatumGetFile(foundres);
2630 tgl 717 ECB :
4875 heikki.linnakangas 718 GIC 4 : if (isCommit)
2630 tgl 719 LBC 0 : PrintFileLeakWarning(res);
2630 tgl 720 GBC 4 : FileClose(res);
4875 heikki.linnakangas 721 ECB : }
722 : }
723 :
724 : /* Let add-on modules get a chance too */
193 tgl 725 GNC 3020262 : for (item = ResourceRelease_callbacks; item; item = next)
726 : {
727 : /* allow callbacks to unregister themselves when called */
728 1638 : next = item->next;
2040 peter_e 729 GIC 1638 : item->callback(phase, isCommit, isTopLevel, item->arg);
730 : }
6840 tgl 731 ECB :
6840 tgl 732 GIC 3018624 : CurrentResourceOwner = save;
6840 tgl 733 CBC 3018624 : }
6840 tgl 734 EUB :
1109 tgl 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
1109 tgl 743 CBC 7302 : ResourceOwnerReleaseAllPlanCacheRefs(ResourceOwner owner)
1109 tgl 744 EUB : {
1109 tgl 745 ECB : Datum foundres;
746 :
1109 tgl 747 GIC 40179 : while (ResourceArrayGetAny(&(owner->planrefarr), &foundres))
748 : {
749 32877 : CachedPlan *res = (CachedPlan *) DatumGetPointer(foundres);
1109 tgl 750 ECB :
804 tgl 751 GIC 32877 : ReleaseCachedPlan(res, owner);
752 : }
1109 tgl 753 CBC 7302 : }
1109 tgl 754 ECB :
755 : /*
756 : * ResourceOwnerDelete
6840 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
6840 tgl 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 */
2630 tgl 768 CBC 1003647 : Assert(owner->bufferarr.nitems == 0);
4 andres 769 GNC 1003647 : Assert(owner->bufferioarr.nitems == 0);
2630 tgl 770 GIC 1003647 : Assert(owner->catrefarr.nitems == 0);
771 1003647 : Assert(owner->catlistrefarr.nitems == 0);
772 1003647 : Assert(owner->relrefarr.nitems == 0);
2630 tgl 773 CBC 1003647 : Assert(owner->planrefarr.nitems == 0);
2630 tgl 774 GIC 1003647 : Assert(owner->tupdescarr.nitems == 0);
2630 tgl 775 CBC 1003647 : Assert(owner->snapshotarr.nitems == 0);
2630 tgl 776 GIC 1003647 : Assert(owner->filearr.nitems == 0);
2630 tgl 777 CBC 1003647 : Assert(owner->dsmarr.nitems == 0);
1845 andres 778 GIC 1003647 : Assert(owner->jitarr.nitems == 0);
856 michael 779 CBC 1003647 : Assert(owner->cryptohasharr.nitems == 0);
736 michael 780 GIC 1003647 : Assert(owner->hmacarr.nitems == 0);
3944 heikki.linnakangas 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 : */
6840 tgl 787 1032302 : while (owner->firstchild != NULL)
6840 tgl 788 CBC 28655 : ResourceOwnerDelete(owner->firstchild);
789 :
790 : /*
6797 bruce 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.
6840 tgl 794 : */
6840 tgl 795 CBC 1003647 : ResourceOwnerNewParent(owner, NULL);
6840 tgl 796 ECB :
797 : /* And free the object. */
2630 tgl 798 CBC 1003647 : ResourceArrayFree(&(owner->bufferarr));
4 andres 799 GNC 1003647 : ResourceArrayFree(&(owner->bufferioarr));
2630 tgl 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));
1845 andres 808 1003647 : ResourceArrayFree(&(owner->jitarr));
856 michael 809 GIC 1003647 : ResourceArrayFree(&(owner->cryptohasharr));
736 810 1003647 : ResourceArrayFree(&(owner->hmacarr));
811 :
6840 tgl 812 1003647 : pfree(owner);
813 1003647 : }
6840 tgl 814 ECB :
6799 815 : /*
816 : * Fetch parent of a ResourceOwner (returns NULL if top-level owner)
817 : */
818 : ResourceOwner
6799 tgl 819 GIC 482967 : ResourceOwnerGetParent(ResourceOwner owner)
820 : {
821 482967 : return owner->parent;
6799 tgl 822 ECB : }
823 :
824 : /*
6840 825 : * Reassign a ResourceOwner to have a new parent
826 : */
827 : void
6840 tgl 828 CBC 1003682 : ResourceOwnerNewParent(ResourceOwner owner,
6840 tgl 829 ECB : ResourceOwner newparent)
830 : {
6840 tgl 831 CBC 1003682 : ResourceOwner oldparent = owner->parent;
6840 tgl 832 ECB :
6840 tgl 833 CBC 1003682 : if (oldparent)
6840 tgl 834 ECB : {
6840 tgl 835 CBC 516140 : if (owner == oldparent->firstchild)
836 508911 : oldparent->firstchild = owner->nextchild;
6840 tgl 837 ECB : else
838 : {
839 : ResourceOwner child;
840 :
6840 tgl 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;
6840 tgl 846 CBC 7229 : break;
847 : }
6840 tgl 848 ECB : }
849 : }
850 : }
851 :
6840 tgl 852 GIC 1003682 : if (newparent)
853 : {
854 35 : Assert(owner != newparent);
6840 tgl 855 CBC 35 : owner->parent = newparent;
6840 tgl 856 GIC 35 : owner->nextchild = newparent->firstchild;
857 35 : newparent->firstchild = owner;
6840 tgl 858 ECB : }
859 : else
860 : {
6840 tgl 861 GIC 1003647 : owner->parent = NULL;
6840 tgl 862 CBC 1003647 : owner->nextchild = NULL;
6840 tgl 863 ECB : }
6840 tgl 864 GIC 1003682 : }
865 :
866 : /*
867 : * Register or deregister callback functions for resource cleanup
6840 tgl 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
6840 tgl 876 GIC 23 : RegisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
877 : {
878 : ResourceReleaseCallbackItem *item;
6840 tgl 879 ECB :
880 : item = (ResourceReleaseCallbackItem *)
6840 tgl 881 CBC 23 : MemoryContextAlloc(TopMemoryContext,
6840 tgl 882 ECB : sizeof(ResourceReleaseCallbackItem));
6840 tgl 883 CBC 23 : item->callback = callback;
884 23 : item->arg = arg;
6840 tgl 885 GIC 23 : item->next = ResourceRelease_callbacks;
886 23 : ResourceRelease_callbacks = item;
887 23 : }
6840 tgl 888 ECB :
889 : void
6840 tgl 890 UIC 0 : UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
6840 tgl 891 ECB : {
892 : ResourceReleaseCallbackItem *item;
893 : ResourceReleaseCallbackItem *prev;
894 :
6840 tgl 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
6840 tgl 903 LBC 0 : ResourceRelease_callbacks = item->next;
6840 tgl 904 UIC 0 : pfree(item);
905 0 : break;
906 : }
907 : }
6840 tgl 908 LBC 0 : }
909 :
1726 tgl 910 ECB : /*
911 : * Establish an AuxProcessResourceOwner for the current process.
912 : */
913 : void
1726 tgl 914 CBC 2407 : CreateAuxProcessResourceOwner(void)
915 : {
1726 tgl 916 GIC 2407 : Assert(AuxProcessResourceOwner == NULL);
1726 tgl 917 GBC 2407 : Assert(CurrentResourceOwner == NULL);
1726 tgl 918 GIC 2407 : AuxProcessResourceOwner = ResourceOwnerCreate(NULL, "AuxiliaryProcess");
919 2407 : CurrentResourceOwner = AuxProcessResourceOwner;
920 :
921 : /*
1726 tgl 922 EUB : * Register a shmem-exit callback for cleanup of aux-process resource
923 : * owner. (This needs to run after, e.g., ShutdownXLOG.)
924 : */
1726 tgl 925 GBC 2407 : on_shmem_exit(ReleaseAuxProcessResourcesCallback, 0);
1726 tgl 926 GIC 2407 : }
1726 tgl 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
1726 tgl 934 GIC 3026 : ReleaseAuxProcessResources(bool isCommit)
1726 tgl 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 : */
1726 tgl 940 GIC 3026 : ResourceOwnerRelease(AuxProcessResourceOwner,
1726 tgl 941 ECB : RESOURCE_RELEASE_BEFORE_LOCKS,
942 : isCommit, true);
1726 tgl 943 CBC 3026 : ResourceOwnerRelease(AuxProcessResourceOwner,
1726 tgl 944 ECB : RESOURCE_RELEASE_LOCKS,
945 : isCommit, true);
1726 tgl 946 CBC 3026 : ResourceOwnerRelease(AuxProcessResourceOwner,
947 : RESOURCE_RELEASE_AFTER_LOCKS,
948 : isCommit, true);
1726 tgl 949 GIC 3026 : }
950 :
951 : /*
1726 tgl 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
1726 tgl 956 GIC 2407 : ReleaseAuxProcessResourcesCallback(int code, Datum arg)
957 : {
958 2407 : bool isCommit = (code == 0);
959 :
960 2407 : ReleaseAuxProcessResources(isCommit);
1726 tgl 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.
6840 tgl 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
6840 tgl 972 GIC 84925049 : ResourceOwnerEnlargeBuffers(ResourceOwner owner)
6840 tgl 973 ECB : {
974 : /* We used to allow pinning buffers without a resowner, but no more */
1726 tgl 975 GIC 84925049 : Assert(owner != NULL);
2630 tgl 976 CBC 84925049 : ResourceArrayEnlarge(&(owner->bufferarr));
6840 tgl 977 GIC 84925049 : }
978 :
979 : /*
980 : * Remember that a buffer pin is owned by a ResourceOwner
981 : *
982 : * Caller must have previously done ResourceOwnerEnlargeBuffers()
6840 tgl 983 ECB : */
984 : void
6840 tgl 985 CBC 83570573 : ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
986 : {
2630 987 83570573 : ResourceArrayAdd(&(owner->bufferarr), BufferGetDatum(buffer));
6840 988 83570573 : }
989 :
990 : /*
991 : * Forget that a buffer pin is owned by a ResourceOwner
992 : */
993 : void
6840 tgl 994 GIC 83570573 : ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
995 : {
2630 996 83570573 : if (!ResourceArrayRemove(&(owner->bufferarr), BufferGetDatum(buffer)))
6840 tgl 997 UIC 0 : elog(ERROR, "buffer %d is not owned by resource owner %s",
998 : buffer, owner->name);
6840 tgl 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
4 andres 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)))
4 andres 1035 UNC 0 : elog(PANIC, "buffer IO %d is not owned by resource owner %s",
1036 : buffer, owner->name);
4 andres 1037 GNC 2599422 : }
1038 :
1039 : /*
3944 heikki.linnakangas 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
3602 bruce 1050 CBC 27048592 : ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock)
1051 : {
2630 tgl 1052 27048592 : Assert(locallock != NULL);
2630 tgl 1053 ECB :
3944 heikki.linnakangas 1054 GIC 27048592 : if (owner->nlocks > MAX_RESOWNER_LOCKS)
3602 bruce 1055 2034678 : return; /* we have already overflowed */
1056 :
3944 heikki.linnakangas 1057 25013914 : if (owner->nlocks < MAX_RESOWNER_LOCKS)
1058 25005006 : owner->locks[owner->nlocks] = locallock;
3944 heikki.linnakangas 1059 ECB : else
1060 : {
1061 : /* overflowed */
3944 heikki.linnakangas 1062 EUB : }
3944 heikki.linnakangas 1063 GIC 25013914 : owner->nlocks++;
3944 heikki.linnakangas 1064 ECB : }
1065 :
1066 : /*
1067 : * Forget that a Local Lock is owned by a ResourceOwner
1068 : */
1069 : void
3944 heikki.linnakangas 1070 GIC 27048592 : ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock)
1071 : {
1072 : int i;
1073 :
1074 27048592 : if (owner->nlocks > MAX_RESOWNER_LOCKS)
3602 bruce 1075 CBC 2177206 : return; /* we have overflowed */
1076 :
3944 heikki.linnakangas 1077 GIC 24871386 : Assert(owner->nlocks > 0);
3944 heikki.linnakangas 1078 CBC 28514759 : for (i = owner->nlocks - 1; i >= 0; i--)
3944 heikki.linnakangas 1079 ECB : {
3944 heikki.linnakangas 1080 CBC 28514759 : if (locallock == owner->locks[i])
1081 : {
3944 heikki.linnakangas 1082 GIC 24871386 : owner->locks[i] = owner->locks[owner->nlocks - 1];
1083 24871386 : owner->nlocks--;
1084 24871386 : return;
1085 : }
1086 : }
3944 heikki.linnakangas 1087 UIC 0 : elog(ERROR, "lock reference %p is not owned by resource owner %s",
3944 heikki.linnakangas 1088 ECB : locallock, owner->name);
1089 : }
1090 :
6840 tgl 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
6840 tgl 1099 CBC 48196159 : ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner)
6840 tgl 1100 EUB : {
2630 tgl 1101 GIC 48196159 : ResourceArrayEnlarge(&(owner->catrefarr));
6840 tgl 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
6840 tgl 1110 GIC 48196159 : ResourceOwnerRememberCatCacheRef(ResourceOwner owner, HeapTuple tuple)
1111 : {
2630 1112 48196159 : ResourceArrayAdd(&(owner->catrefarr), PointerGetDatum(tuple));
6840 1113 48196159 : }
1114 :
6840 tgl 1115 ECB : /*
1116 : * Forget that a catcache reference is owned by a ResourceOwner
1117 : */
1118 : void
6840 tgl 1119 CBC 48196159 : ResourceOwnerForgetCatCacheRef(ResourceOwner owner, HeapTuple tuple)
6840 tgl 1120 ECB : {
2630 tgl 1121 GIC 48196159 : if (!ResourceArrayRemove(&(owner->catrefarr), PointerGetDatum(tuple)))
2630 tgl 1122 LBC 0 : elog(ERROR, "catcache reference %p is not owned by resource owner %s",
2630 tgl 1123 ECB : tuple, owner->name);
6840 tgl 1124 GIC 48196159 : }
1125 :
1126 : /*
1127 : * Make sure there is room for at least one more entry in a ResourceOwner's
6840 tgl 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
6840 tgl 1134 GIC 1600190 : ResourceOwnerEnlargeCatCacheListRefs(ResourceOwner owner)
6840 tgl 1135 ECB : {
2630 tgl 1136 GIC 1600190 : ResourceArrayEnlarge(&(owner->catlistrefarr));
6840 1137 1600190 : }
1138 :
6840 tgl 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
6840 tgl 1145 CBC 1600190 : ResourceOwnerRememberCatCacheListRef(ResourceOwner owner, CatCList *list)
1146 : {
2630 1147 1600190 : ResourceArrayAdd(&(owner->catlistrefarr), PointerGetDatum(list));
6840 1148 1600190 : }
6840 tgl 1149 ECB :
1150 : /*
1151 : * Forget that a catcache-list reference is owned by a ResourceOwner
6840 tgl 1152 EUB : */
1153 : void
6840 tgl 1154 GIC 1600190 : ResourceOwnerForgetCatCacheListRef(ResourceOwner owner, CatCList *list)
1155 : {
2630 1156 1600190 : if (!ResourceArrayRemove(&(owner->catlistrefarr), PointerGetDatum(list)))
2630 tgl 1157 UIC 0 : elog(ERROR, "catcache list reference %p is not owned by resource owner %s",
1158 : list, owner->name);
6840 tgl 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.
6840 tgl 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
6840 tgl 1169 GIC 40884389 : ResourceOwnerEnlargeRelationRefs(ResourceOwner owner)
1170 : {
2630 1171 40884389 : ResourceArrayEnlarge(&(owner->relrefarr));
6840 1172 40884389 : }
1173 :
1174 : /*
6840 tgl 1175 ECB : * Remember that a relcache reference is owned by a ResourceOwner
1176 : *
1177 : * Caller must have previously done ResourceOwnerEnlargeRelationRefs()
1178 : */
1179 : void
6840 tgl 1180 GIC 39145584 : ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel)
1181 : {
2630 1182 39145584 : ResourceArrayAdd(&(owner->relrefarr), PointerGetDatum(rel));
6840 1183 39145584 : }
6840 tgl 1184 ECB :
1185 : /*
1186 : * Forget that a relcache reference is owned by a ResourceOwner
6840 tgl 1187 EUB : */
1188 : void
6840 tgl 1189 CBC 39145584 : ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
1190 : {
2630 tgl 1191 GIC 39145584 : if (!ResourceArrayRemove(&(owner->relrefarr), PointerGetDatum(rel)))
2630 tgl 1192 UIC 0 : elog(ERROR, "relcache reference %s is not owned by resource owner %s",
1193 : RelationGetRelationName(rel), owner->name);
6840 tgl 1194 GIC 39145584 : }
1195 :
1196 : /*
1197 : * Debugging subroutine
1198 : */
6589 tgl 1199 ECB : static void
6589 tgl 1200 UIC 0 : PrintRelCacheLeakWarning(Relation rel)
6589 tgl 1201 ECB : {
6589 tgl 1202 LBC 0 : elog(WARNING, "relcache reference leak: relation \"%s\" not closed",
1203 : RelationGetRelationName(rel));
6589 tgl 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 : *
5871 tgl 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
5871 tgl 1214 GIC 83803 : ResourceOwnerEnlargePlanCacheRefs(ResourceOwner owner)
1215 : {
2630 1216 83803 : ResourceArrayEnlarge(&(owner->planrefarr));
5871 1217 83803 : }
1218 :
5871 tgl 1219 ECB : /*
1220 : * Remember that a plancache reference is owned by a ResourceOwner
1221 : *
5871 tgl 1222 EUB : * Caller must have previously done ResourceOwnerEnlargePlanCacheRefs()
1223 : */
5871 tgl 1224 ECB : void
5624 bruce 1225 GIC 83803 : ResourceOwnerRememberPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
1226 : {
2630 tgl 1227 83803 : ResourceArrayAdd(&(owner->planrefarr), PointerGetDatum(plan));
5871 1228 83803 : }
1229 :
1230 : /*
1231 : * Forget that a plancache reference is owned by a ResourceOwner
1232 : */
1233 : void
5624 bruce 1234 CBC 83803 : ResourceOwnerForgetPlanCacheRef(ResourceOwner owner, CachedPlan *plan)
1235 : {
2630 tgl 1236 83803 : if (!ResourceArrayRemove(&(owner->planrefarr), PointerGetDatum(plan)))
2630 tgl 1237 LBC 0 : elog(ERROR, "plancache reference %p is not owned by resource owner %s",
1238 : plan, owner->name);
5871 tgl 1239 GIC 83803 : }
1240 :
1241 : /*
1242 : * Debugging subroutine
1243 : */
1244 : static void
5624 bruce 1245 LBC 0 : PrintPlanCacheLeakWarning(CachedPlan *plan)
1246 : {
5871 tgl 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 : *
6141 tgl 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 : */
6141 tgl 1257 EUB : void
6141 tgl 1258 GIC 21264947 : ResourceOwnerEnlargeTupleDescs(ResourceOwner owner)
6141 tgl 1259 ECB : {
2630 tgl 1260 GIC 21264947 : ResourceArrayEnlarge(&(owner->tupdescarr));
6141 1261 21264947 : }
1262 :
1263 : /*
1264 : * Remember that a tupdesc reference is owned by a ResourceOwner
6141 tgl 1265 EUB : *
1266 : * Caller must have previously done ResourceOwnerEnlargeTupleDescs()
1267 : */
1268 : void
6141 tgl 1269 GBC 21264947 : ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
1270 : {
2630 tgl 1271 GIC 21264947 : ResourceArrayAdd(&(owner->tupdescarr), PointerGetDatum(tupdesc));
6141 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)
6141 tgl 1279 ECB : {
2630 tgl 1280 GIC 21264947 : if (!ResourceArrayRemove(&(owner->tupdescarr), PointerGetDatum(tupdesc)))
2630 tgl 1281 LBC 0 : elog(ERROR, "tupdesc reference %p is not owned by resource owner %s",
2630 tgl 1282 ECB : tupdesc, owner->name);
6141 tgl 1283 GIC 21264947 : }
1284 :
1285 : /*
1286 : * Debugging subroutine
1287 : */
1288 : static void
6141 tgl 1289 UIC 0 : PrintTupleDescLeakWarning(TupleDesc tupdesc)
6141 tgl 1290 ECB : {
6141 tgl 1291 UIC 0 : elog(WARNING,
6141 tgl 1292 ECB : "TupleDesc reference leak: TupleDesc %p (%u,%d) still referenced",
1293 : tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
6141 tgl 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.
5248 alvherre 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.
5248 alvherre 1302 EUB : */
1303 : void
5248 alvherre 1304 CBC 8845361 : ResourceOwnerEnlargeSnapshots(ResourceOwner owner)
1305 : {
2630 tgl 1306 GIC 8845361 : ResourceArrayEnlarge(&(owner->snapshotarr));
5248 alvherre 1307 8845361 : }
1308 :
1309 : /*
5248 alvherre 1310 EUB : * Remember that a snapshot reference is owned by a ResourceOwner
1311 : *
1312 : * Caller must have previously done ResourceOwnerEnlargeSnapshots()
1313 : */
1314 : void
5248 alvherre 1315 GIC 8845361 : ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snapshot)
1316 : {
2630 tgl 1317 8845361 : ResourceArrayAdd(&(owner->snapshotarr), PointerGetDatum(snapshot));
5248 alvherre 1318 8845361 : }
1319 :
1320 : /*
1321 : * Forget that a snapshot reference is owned by a ResourceOwner
1322 : */
5248 alvherre 1323 ECB : void
5248 alvherre 1324 GIC 8845361 : ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snapshot)
5248 alvherre 1325 ECB : {
2630 tgl 1326 CBC 8845361 : if (!ResourceArrayRemove(&(owner->snapshotarr), PointerGetDatum(snapshot)))
2630 tgl 1327 UIC 0 : elog(ERROR, "snapshot reference %p is not owned by resource owner %s",
1328 : snapshot, owner->name);
5248 alvherre 1329 GIC 8845361 : }
1330 :
1331 : /*
1332 : * Debugging subroutine
1333 : */
5248 alvherre 1334 ECB : static void
5248 alvherre 1335 UIC 0 : PrintSnapshotLeakWarning(Snapshot snapshot)
5248 alvherre 1336 ECB : {
2630 tgl 1337 LBC 0 : elog(WARNING, "Snapshot reference leak: Snapshot %p still referenced",
1338 : snapshot);
5248 alvherre 1339 UIC 0 : }
1340 :
1341 :
1342 : /*
4875 heikki.linnakangas 1343 ECB : * Make sure there is room for at least one more entry in a ResourceOwner's
1344 : * files reference array.
1345 : *
4875 heikki.linnakangas 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.
4875 heikki.linnakangas 1348 ECB : */
1349 : void
4875 heikki.linnakangas 1350 GIC 7446 : ResourceOwnerEnlargeFiles(ResourceOwner owner)
1351 : {
2630 tgl 1352 7446 : ResourceArrayEnlarge(&(owner->filearr));
4875 heikki.linnakangas 1353 7446 : }
4875 heikki.linnakangas 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
4875 heikki.linnakangas 1361 GIC 5110 : ResourceOwnerRememberFile(ResourceOwner owner, File file)
1362 : {
2630 tgl 1363 5110 : ResourceArrayAdd(&(owner->filearr), FileGetDatum(file));
4875 heikki.linnakangas 1364 5110 : }
1365 :
1366 : /*
1367 : * Forget that a temporary file is owned by a ResourceOwner
1368 : */
4875 heikki.linnakangas 1369 ECB : void
4875 heikki.linnakangas 1370 GIC 5110 : ResourceOwnerForgetFile(ResourceOwner owner, File file)
4875 heikki.linnakangas 1371 ECB : {
2630 tgl 1372 CBC 5110 : if (!ResourceArrayRemove(&(owner->filearr), FileGetDatum(file)))
2630 tgl 1373 UIC 0 : elog(ERROR, "temporary file %d is not owned by resource owner %s",
1374 : file, owner->name);
4875 heikki.linnakangas 1375 GIC 5110 : }
1376 :
1377 : /*
1378 : * Debugging subroutine
1379 : */
4875 heikki.linnakangas 1380 ECB : static void
4875 heikki.linnakangas 1381 UIC 0 : PrintFileLeakWarning(File file)
4875 heikki.linnakangas 1382 ECB : {
2630 tgl 1383 LBC 0 : elog(WARNING, "temporary file leak: File %d still referenced",
1384 : file);
4875 heikki.linnakangas 1385 UIC 0 : }
1386 :
1387 : /*
1388 : * Make sure there is room for at least one more entry in a ResourceOwner's
3469 rhaas 1389 ECB : * dynamic shmem segment reference array.
1390 : *
1391 : * This is separate from actually inserting an entry because if we run out
3469 rhaas 1392 EUB : * of memory, it's critical to do so *before* acquiring the resource.
1393 : */
3469 rhaas 1394 ECB : void
3469 rhaas 1395 GIC 14798 : ResourceOwnerEnlargeDSMs(ResourceOwner owner)
1396 : {
2630 tgl 1397 14798 : ResourceArrayEnlarge(&(owner->dsmarr));
3469 rhaas 1398 14798 : }
1399 :
3469 rhaas 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
3469 rhaas 1406 GIC 14798 : ResourceOwnerRememberDSM(ResourceOwner owner, dsm_segment *seg)
1407 : {
2630 tgl 1408 14798 : ResourceArrayAdd(&(owner->dsmarr), PointerGetDatum(seg));
3469 rhaas 1409 14798 : }
1410 :
1411 : /*
1412 : * Forget that a dynamic shmem segment is owned by a ResourceOwner
1413 : */
1414 : void
3469 rhaas 1415 CBC 14798 : ResourceOwnerForgetDSM(ResourceOwner owner, dsm_segment *seg)
1416 : {
2630 tgl 1417 14798 : if (!ResourceArrayRemove(&(owner->dsmarr), PointerGetDatum(seg)))
2630 tgl 1418 LBC 0 : elog(ERROR, "dynamic shared memory segment %u is not owned by resource owner %s",
1419 : dsm_segment_handle(seg), owner->name);
3469 rhaas 1420 GIC 14798 : }
1421 :
1422 : /*
1423 : * Debugging subroutine
1424 : */
1425 : static void
3469 rhaas 1426 LBC 0 : PrintDSMLeakWarning(dsm_segment *seg)
1427 : {
2630 tgl 1428 0 : elog(WARNING, "dynamic shared memory leak: segment %u still referenced",
3469 rhaas 1429 ECB : dsm_segment_handle(seg));
3469 rhaas 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.
1845 andres 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.
1845 andres 1438 EUB : */
1439 : void
1845 andres 1440 CBC 839 : ResourceOwnerEnlargeJIT(ResourceOwner owner)
1441 : {
1845 andres 1442 GIC 839 : ResourceArrayEnlarge(&(owner->jitarr));
1443 839 : }
1444 :
1445 : /*
1845 andres 1446 EUB : * Remember that a JIT context is owned by a ResourceOwner
1447 : *
1448 : * Caller must have previously done ResourceOwnerEnlargeJIT()
1449 : */
1450 : void
1845 andres 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
1845 andres 1460 CBC 839 : ResourceOwnerForgetJIT(ResourceOwner owner, Datum handle)
1461 : {
1462 839 : if (!ResourceArrayRemove(&(owner->jitarr), handle))
1845 andres 1463 LBC 0 : elog(ERROR, "JIT context %p is not owned by resource owner %s",
1464 : DatumGetPointer(handle), owner->name);
1845 andres 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 : *
856 michael 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
856 michael 1475 GIC 499247 : ResourceOwnerEnlargeCryptoHash(ResourceOwner owner)
1476 : {
1477 499247 : ResourceArrayEnlarge(&(owner->cryptohasharr));
1478 499247 : }
1479 :
856 michael 1480 ECB : /*
1481 : * Remember that a cryptohash context is owned by a ResourceOwner
1482 : *
856 michael 1483 EUB : * Caller must have previously done ResourceOwnerEnlargeCryptoHash()
1484 : */
856 michael 1485 ECB : void
856 michael 1486 GIC 499247 : ResourceOwnerRememberCryptoHash(ResourceOwner owner, Datum handle)
1487 : {
1488 499247 : ResourceArrayAdd(&(owner->cryptohasharr), handle);
1489 499247 : }
1490 :
856 michael 1491 EUB : /*
1492 : * Forget that a cryptohash context is owned by a ResourceOwner
1493 : */
1494 : void
856 michael 1495 GBC 499242 : ResourceOwnerForgetCryptoHash(ResourceOwner owner, Datum handle)
1496 : {
856 michael 1497 GIC 499242 : if (!ResourceArrayRemove(&(owner->cryptohasharr), handle))
856 michael 1498 UIC 0 : elog(ERROR, "cryptohash context %p is not owned by resource owner %s",
1499 : DatumGetPointer(handle), owner->name);
856 michael 1500 GIC 499242 : }
1501 :
1502 : /*
1503 : * Debugging subroutine
1504 : */
856 michael 1505 ECB : static void
856 michael 1506 UIC 0 : PrintCryptoHashLeakWarning(Datum handle)
856 michael 1507 ECB : {
856 michael 1508 LBC 0 : elog(WARNING, "cryptohash context reference leak: context %p still referenced",
1509 : DatumGetPointer(handle));
856 michael 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 : *
736 michael 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
736 michael 1520 GIC 216 : ResourceOwnerEnlargeHMAC(ResourceOwner owner)
1521 : {
1522 216 : ResourceArrayEnlarge(&(owner->hmacarr));
1523 216 : }
1524 :
736 michael 1525 ECB : /*
1526 : * Remember that a HMAC context is owned by a ResourceOwner
1527 : *
736 michael 1528 EUB : * Caller must have previously done ResourceOwnerEnlargeHMAC()
1529 : */
736 michael 1530 ECB : void
736 michael 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
736 michael 1540 CBC 216 : ResourceOwnerForgetHMAC(ResourceOwner owner, Datum handle)
1541 : {
1542 216 : if (!ResourceArrayRemove(&(owner->hmacarr), handle))
736 michael 1543 LBC 0 : elog(ERROR, "HMAC context %p is not owned by resource owner %s",
1544 : DatumGetPointer(handle), owner->name);
736 michael 1545 GIC 216 : }
1546 :
1547 : /*
1548 : * Debugging subroutine
1549 : */
1550 : static void
736 michael 1551 LBC 0 : PrintHMACLeakWarning(Datum handle)
1552 : {
1553 0 : elog(WARNING, "HMAC context reference leak: context %p still referenced",
736 michael 1554 ECB : DatumGetPointer(handle));
736 michael 1555 UIC 0 : }
|