Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * mcxt.c
4 : * POSTGRES memory context management code.
5 : *
6 : * This module handles context management operations that are independent
7 : * of the particular kind of context being operated on. It calls
8 : * context-type-specific operations via the function pointers in a
9 : * context's MemoryContextMethods struct.
10 : *
11 : *
12 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
13 : * Portions Copyright (c) 1994, Regents of the University of California
14 : *
15 : *
16 : * IDENTIFICATION
17 : * src/backend/utils/mmgr/mcxt.c
18 : *
19 : *-------------------------------------------------------------------------
20 : */
21 :
22 : #include "postgres.h"
23 :
24 : #include "mb/pg_wchar.h"
25 : #include "miscadmin.h"
26 : #include "utils/memdebug.h"
27 : #include "utils/memutils.h"
28 : #include "utils/memutils_internal.h"
29 : #include "utils/memutils_memorychunk.h"
30 :
31 :
32 : static void BogusFree(void *pointer);
33 : static void *BogusRealloc(void *pointer, Size size, int flags);
34 : static MemoryContext BogusGetChunkContext(void *pointer);
35 : static Size BogusGetChunkSpace(void *pointer);
36 :
37 : /*****************************************************************************
38 : * GLOBAL MEMORY *
39 : *****************************************************************************/
40 : #define BOGUS_MCTX(id) \
41 : [id].free_p = BogusFree, \
42 : [id].realloc = BogusRealloc, \
43 : [id].get_chunk_context = BogusGetChunkContext, \
44 : [id].get_chunk_space = BogusGetChunkSpace
45 :
46 : static const MemoryContextMethods mcxt_methods[] = {
47 : /* aset.c */
48 : [MCTX_ASET_ID].alloc = AllocSetAlloc,
49 : [MCTX_ASET_ID].free_p = AllocSetFree,
50 : [MCTX_ASET_ID].realloc = AllocSetRealloc,
51 : [MCTX_ASET_ID].reset = AllocSetReset,
52 : [MCTX_ASET_ID].delete_context = AllocSetDelete,
53 : [MCTX_ASET_ID].get_chunk_context = AllocSetGetChunkContext,
54 : [MCTX_ASET_ID].get_chunk_space = AllocSetGetChunkSpace,
55 : [MCTX_ASET_ID].is_empty = AllocSetIsEmpty,
56 : [MCTX_ASET_ID].stats = AllocSetStats,
57 : #ifdef MEMORY_CONTEXT_CHECKING
58 : [MCTX_ASET_ID].check = AllocSetCheck,
59 : #endif
60 :
61 : /* generation.c */
62 : [MCTX_GENERATION_ID].alloc = GenerationAlloc,
63 : [MCTX_GENERATION_ID].free_p = GenerationFree,
64 : [MCTX_GENERATION_ID].realloc = GenerationRealloc,
65 : [MCTX_GENERATION_ID].reset = GenerationReset,
66 : [MCTX_GENERATION_ID].delete_context = GenerationDelete,
67 : [MCTX_GENERATION_ID].get_chunk_context = GenerationGetChunkContext,
68 : [MCTX_GENERATION_ID].get_chunk_space = GenerationGetChunkSpace,
69 : [MCTX_GENERATION_ID].is_empty = GenerationIsEmpty,
70 : [MCTX_GENERATION_ID].stats = GenerationStats,
71 : #ifdef MEMORY_CONTEXT_CHECKING
72 : [MCTX_GENERATION_ID].check = GenerationCheck,
73 : #endif
74 :
75 : /* slab.c */
76 : [MCTX_SLAB_ID].alloc = SlabAlloc,
77 : [MCTX_SLAB_ID].free_p = SlabFree,
78 : [MCTX_SLAB_ID].realloc = SlabRealloc,
79 : [MCTX_SLAB_ID].reset = SlabReset,
80 : [MCTX_SLAB_ID].delete_context = SlabDelete,
81 : [MCTX_SLAB_ID].get_chunk_context = SlabGetChunkContext,
82 : [MCTX_SLAB_ID].get_chunk_space = SlabGetChunkSpace,
83 : [MCTX_SLAB_ID].is_empty = SlabIsEmpty,
84 : [MCTX_SLAB_ID].stats = SlabStats,
85 : #ifdef MEMORY_CONTEXT_CHECKING
86 : [MCTX_SLAB_ID].check = SlabCheck,
87 : #endif
88 :
89 : /* alignedalloc.c */
90 : [MCTX_ALIGNED_REDIRECT_ID].alloc = NULL, /* not required */
91 : [MCTX_ALIGNED_REDIRECT_ID].free_p = AlignedAllocFree,
92 : [MCTX_ALIGNED_REDIRECT_ID].realloc = AlignedAllocRealloc,
93 : [MCTX_ALIGNED_REDIRECT_ID].reset = NULL, /* not required */
94 : [MCTX_ALIGNED_REDIRECT_ID].delete_context = NULL, /* not required */
95 : [MCTX_ALIGNED_REDIRECT_ID].get_chunk_context = AlignedAllocGetChunkContext,
96 : [MCTX_ALIGNED_REDIRECT_ID].get_chunk_space = AlignedAllocGetChunkSpace,
97 : [MCTX_ALIGNED_REDIRECT_ID].is_empty = NULL, /* not required */
98 : [MCTX_ALIGNED_REDIRECT_ID].stats = NULL, /* not required */
99 : #ifdef MEMORY_CONTEXT_CHECKING
100 : [MCTX_ALIGNED_REDIRECT_ID].check = NULL, /* not required */
101 : #endif
102 :
103 : /* bump.c */
104 : [MCTX_BUMP_ID].alloc = BumpAlloc,
105 : [MCTX_BUMP_ID].free_p = BumpFree,
106 : [MCTX_BUMP_ID].realloc = BumpRealloc,
107 : [MCTX_BUMP_ID].reset = BumpReset,
108 : [MCTX_BUMP_ID].delete_context = BumpDelete,
109 : [MCTX_BUMP_ID].get_chunk_context = BumpGetChunkContext,
110 : [MCTX_BUMP_ID].get_chunk_space = BumpGetChunkSpace,
111 : [MCTX_BUMP_ID].is_empty = BumpIsEmpty,
112 : [MCTX_BUMP_ID].stats = BumpStats,
113 : #ifdef MEMORY_CONTEXT_CHECKING
114 : [MCTX_BUMP_ID].check = BumpCheck,
115 : #endif
116 :
117 :
118 : /*
119 : * Reserved and unused IDs should have dummy entries here. This allows us
120 : * to fail cleanly if a bogus pointer is passed to pfree or the like. It
121 : * seems sufficient to provide routines for the methods that might get
122 : * invoked from inspection of a chunk (see MCXT_METHOD calls below).
123 : */
124 : BOGUS_MCTX(MCTX_1_RESERVED_GLIBC_ID),
125 : BOGUS_MCTX(MCTX_2_RESERVED_GLIBC_ID),
126 : BOGUS_MCTX(MCTX_8_UNUSED_ID),
127 : BOGUS_MCTX(MCTX_9_UNUSED_ID),
128 : BOGUS_MCTX(MCTX_10_UNUSED_ID),
129 : BOGUS_MCTX(MCTX_11_UNUSED_ID),
130 : BOGUS_MCTX(MCTX_12_UNUSED_ID),
131 : BOGUS_MCTX(MCTX_13_UNUSED_ID),
132 : BOGUS_MCTX(MCTX_14_UNUSED_ID),
133 : BOGUS_MCTX(MCTX_0_RESERVED_UNUSEDMEM_ID),
134 : BOGUS_MCTX(MCTX_15_RESERVED_WIPEDMEM_ID)
135 : };
136 :
137 : #undef BOGUS_MCTX
138 :
139 : /*
140 : * CurrentMemoryContext
141 : * Default memory context for allocations.
142 : */
143 : MemoryContext CurrentMemoryContext = NULL;
144 :
145 : /*
146 : * Standard top-level contexts. For a description of the purpose of each
147 : * of these contexts, refer to src/backend/utils/mmgr/README
148 : */
149 : MemoryContext TopMemoryContext = NULL;
150 : MemoryContext ErrorContext = NULL;
151 : MemoryContext PostmasterContext = NULL;
152 : MemoryContext CacheMemoryContext = NULL;
153 : MemoryContext MessageContext = NULL;
154 : MemoryContext TopTransactionContext = NULL;
155 : MemoryContext CurTransactionContext = NULL;
156 :
157 : /* This is a transient link to the active portal's memory context: */
158 : MemoryContext PortalContext = NULL;
159 :
160 : static void MemoryContextDeleteOnly(MemoryContext context);
161 : static void MemoryContextCallResetCallbacks(MemoryContext context);
162 : static void MemoryContextStatsInternal(MemoryContext context, int level,
163 : int max_level, int max_children,
164 : MemoryContextCounters *totals,
165 : bool print_to_stderr);
166 : static void MemoryContextStatsPrint(MemoryContext context, void *passthru,
167 : const char *stats_string,
168 : bool print_to_stderr);
169 :
170 : /*
171 : * You should not do memory allocations within a critical section, because
172 : * an out-of-memory error will be escalated to a PANIC. To enforce that
173 : * rule, the allocation functions Assert that.
174 : */
175 : #define AssertNotInCriticalSection(context) \
176 : Assert(CritSectionCount == 0 || (context)->allowInCritSection)
177 :
178 : /*
179 : * Call the given function in the MemoryContextMethods for the memory context
180 : * type that 'pointer' belongs to.
181 : */
182 : #define MCXT_METHOD(pointer, method) \
183 : mcxt_methods[GetMemoryChunkMethodID(pointer)].method
184 :
185 : /*
186 : * GetMemoryChunkMethodID
187 : * Return the MemoryContextMethodID from the uint64 chunk header which
188 : * directly precedes 'pointer'.
189 : */
190 : static inline MemoryContextMethodID
191 561968860 : GetMemoryChunkMethodID(const void *pointer)
192 : {
193 : uint64 header;
194 :
195 : /*
196 : * Try to detect bogus pointers handed to us, poorly though we can.
197 : * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
198 : * allocated chunk.
199 : */
200 : Assert(pointer == (const void *) MAXALIGN(pointer));
201 :
202 : /* Allow access to the uint64 header */
203 : VALGRIND_MAKE_MEM_DEFINED((char *) pointer - sizeof(uint64), sizeof(uint64));
204 :
205 561968860 : header = *((const uint64 *) ((const char *) pointer - sizeof(uint64)));
206 :
207 : /* Disallow access to the uint64 header */
208 : VALGRIND_MAKE_MEM_NOACCESS((char *) pointer - sizeof(uint64), sizeof(uint64));
209 :
210 561968860 : return (MemoryContextMethodID) (header & MEMORY_CONTEXT_METHODID_MASK);
211 : }
212 :
213 : /*
214 : * GetMemoryChunkHeader
215 : * Return the uint64 chunk header which directly precedes 'pointer'.
216 : *
217 : * This is only used after GetMemoryChunkMethodID, so no need for error checks.
218 : */
219 : static inline uint64
220 0 : GetMemoryChunkHeader(const void *pointer)
221 : {
222 : uint64 header;
223 :
224 : /* Allow access to the uint64 header */
225 : VALGRIND_MAKE_MEM_DEFINED((char *) pointer - sizeof(uint64), sizeof(uint64));
226 :
227 0 : header = *((const uint64 *) ((const char *) pointer - sizeof(uint64)));
228 :
229 : /* Disallow access to the uint64 header */
230 : VALGRIND_MAKE_MEM_NOACCESS((char *) pointer - sizeof(uint64), sizeof(uint64));
231 :
232 0 : return header;
233 : }
234 :
235 : /*
236 : * MemoryContextTraverseNext
237 : * Helper function to traverse all descendants of a memory context
238 : * without recursion.
239 : *
240 : * Recursion could lead to out-of-stack errors with deep context hierarchies,
241 : * which would be unpleasant in error cleanup code paths.
242 : *
243 : * To process 'context' and all its descendants, use a loop like this:
244 : *
245 : * <process 'context'>
246 : * for (MemoryContext curr = context->firstchild;
247 : * curr != NULL;
248 : * curr = MemoryContextTraverseNext(curr, context))
249 : * {
250 : * <process 'curr'>
251 : * }
252 : *
253 : * This visits all the contexts in pre-order, that is a node is visited
254 : * before its children.
255 : */
256 : static MemoryContext
257 1245830 : MemoryContextTraverseNext(MemoryContext curr, MemoryContext top)
258 : {
259 : /* After processing a node, traverse to its first child if any */
260 1245830 : if (curr->firstchild != NULL)
261 0 : return curr->firstchild;
262 :
263 : /*
264 : * After processing a childless node, traverse to its next sibling if
265 : * there is one. If there isn't, traverse back up to the parent (which
266 : * has already been visited, and now so have all its descendants). We're
267 : * done if that is "top", otherwise traverse to its next sibling if any,
268 : * otherwise repeat moving up.
269 : */
270 1245830 : while (curr->nextchild == NULL)
271 : {
272 648652 : curr = curr->parent;
273 648652 : if (curr == top)
274 648652 : return NULL;
275 : }
276 597178 : return curr->nextchild;
277 : }
278 :
279 : /*
280 : * Support routines to trap use of invalid memory context method IDs
281 : * (from calling pfree or the like on a bogus pointer). As a possible
282 : * aid in debugging, we report the header word along with the pointer
283 : * address (if we got here, there must be an accessible header word).
284 : */
285 : static void
286 0 : BogusFree(void *pointer)
287 : {
288 0 : elog(ERROR, "pfree called with invalid pointer %p (header 0x%016" PRIx64 ")",
289 : pointer, GetMemoryChunkHeader(pointer));
290 : }
291 :
292 : static void *
293 0 : BogusRealloc(void *pointer, Size size, int flags)
294 : {
295 0 : elog(ERROR, "repalloc called with invalid pointer %p (header 0x%016" PRIx64 ")",
296 : pointer, GetMemoryChunkHeader(pointer));
297 : return NULL; /* keep compiler quiet */
298 : }
299 :
300 : static MemoryContext
301 0 : BogusGetChunkContext(void *pointer)
302 : {
303 0 : elog(ERROR, "GetMemoryChunkContext called with invalid pointer %p (header 0x%016" PRIx64 ")",
304 : pointer, GetMemoryChunkHeader(pointer));
305 : return NULL; /* keep compiler quiet */
306 : }
307 :
308 : static Size
309 0 : BogusGetChunkSpace(void *pointer)
310 : {
311 0 : elog(ERROR, "GetMemoryChunkSpace called with invalid pointer %p (header 0x%016" PRIx64 ")",
312 : pointer, GetMemoryChunkHeader(pointer));
313 : return 0; /* keep compiler quiet */
314 : }
315 :
316 :
317 : /*****************************************************************************
318 : * EXPORTED ROUTINES *
319 : *****************************************************************************/
320 :
321 :
322 : /*
323 : * MemoryContextInit
324 : * Start up the memory-context subsystem.
325 : *
326 : * This must be called before creating contexts or allocating memory in
327 : * contexts. TopMemoryContext and ErrorContext are initialized here;
328 : * other contexts must be created afterwards.
329 : *
330 : * In normal multi-backend operation, this is called once during
331 : * postmaster startup, and not at all by individual backend startup
332 : * (since the backends inherit an already-initialized context subsystem
333 : * by virtue of being forked off the postmaster). But in an EXEC_BACKEND
334 : * build, each process must do this for itself.
335 : *
336 : * In a standalone backend this must be called during backend startup.
337 : */
338 : void
339 3660 : MemoryContextInit(void)
340 : {
341 : Assert(TopMemoryContext == NULL);
342 :
343 : /*
344 : * First, initialize TopMemoryContext, which is the parent of all others.
345 : */
346 3660 : TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
347 : "TopMemoryContext",
348 : ALLOCSET_DEFAULT_SIZES);
349 :
350 : /*
351 : * Not having any other place to point CurrentMemoryContext, make it point
352 : * to TopMemoryContext. Caller should change this soon!
353 : */
354 3660 : CurrentMemoryContext = TopMemoryContext;
355 :
356 : /*
357 : * Initialize ErrorContext as an AllocSetContext with slow growth rate ---
358 : * we don't really expect much to be allocated in it. More to the point,
359 : * require it to contain at least 8K at all times. This is the only case
360 : * where retained memory in a context is *essential* --- we want to be
361 : * sure ErrorContext still has some memory even if we've run out
362 : * elsewhere! Also, allow allocations in ErrorContext within a critical
363 : * section. Otherwise a PANIC will cause an assertion failure in the error
364 : * reporting code, before printing out the real cause of the failure.
365 : *
366 : * This should be the last step in this function, as elog.c assumes memory
367 : * management works once ErrorContext is non-null.
368 : */
369 3660 : ErrorContext = AllocSetContextCreate(TopMemoryContext,
370 : "ErrorContext",
371 : 8 * 1024,
372 : 8 * 1024,
373 : 8 * 1024);
374 3660 : MemoryContextAllowInCriticalSection(ErrorContext, true);
375 3660 : }
376 :
377 : /*
378 : * MemoryContextReset
379 : * Release all space allocated within a context and delete all its
380 : * descendant contexts (but not the named context itself).
381 : */
382 : void
383 331652974 : MemoryContextReset(MemoryContext context)
384 : {
385 : Assert(MemoryContextIsValid(context));
386 :
387 : /* save a function call in common case where there are no children */
388 331652974 : if (context->firstchild != NULL)
389 603080 : MemoryContextDeleteChildren(context);
390 :
391 : /* save a function call if no pallocs since startup or last reset */
392 331652974 : if (!context->isReset)
393 49834194 : MemoryContextResetOnly(context);
394 331652974 : }
395 :
396 : /*
397 : * MemoryContextResetOnly
398 : * Release all space allocated within a context.
399 : * Nothing is done to the context's descendant contexts.
400 : */
401 : void
402 55659974 : MemoryContextResetOnly(MemoryContext context)
403 : {
404 : Assert(MemoryContextIsValid(context));
405 :
406 : /* Nothing to do if no pallocs since startup or last reset */
407 55659974 : if (!context->isReset)
408 : {
409 55658794 : MemoryContextCallResetCallbacks(context);
410 :
411 : /*
412 : * If context->ident points into the context's memory, it will become
413 : * a dangling pointer. We could prevent that by setting it to NULL
414 : * here, but that would break valid coding patterns that keep the
415 : * ident elsewhere, e.g. in a parent context. So for now we assume
416 : * the programmer got it right.
417 : */
418 :
419 55658794 : context->methods->reset(context);
420 55658794 : context->isReset = true;
421 : VALGRIND_DESTROY_MEMPOOL(context);
422 : VALGRIND_CREATE_MEMPOOL(context, 0, false);
423 : }
424 55659974 : }
425 :
426 : /*
427 : * MemoryContextResetChildren
428 : * Release all space allocated within a context's descendants,
429 : * but don't delete the contexts themselves. The named context
430 : * itself is not touched.
431 : */
432 : void
433 0 : MemoryContextResetChildren(MemoryContext context)
434 : {
435 : Assert(MemoryContextIsValid(context));
436 :
437 0 : for (MemoryContext curr = context->firstchild;
438 0 : curr != NULL;
439 0 : curr = MemoryContextTraverseNext(curr, context))
440 : {
441 0 : MemoryContextResetOnly(curr);
442 : }
443 0 : }
444 :
445 : /*
446 : * MemoryContextDelete
447 : * Delete a context and its descendants, and release all space
448 : * allocated therein.
449 : *
450 : * The type-specific delete routine removes all storage for the context,
451 : * but we have to deal with descendant nodes here.
452 : */
453 : void
454 9509266 : MemoryContextDelete(MemoryContext context)
455 : {
456 : MemoryContext curr;
457 :
458 : Assert(MemoryContextIsValid(context));
459 :
460 : /*
461 : * Delete subcontexts from the bottom up.
462 : *
463 : * Note: Do not use recursion here. A "stack depth limit exceeded" error
464 : * would be unpleasant if we're already in the process of cleaning up from
465 : * transaction abort. We also cannot use MemoryContextTraverseNext() here
466 : * because we modify the tree as we go.
467 : */
468 9509266 : curr = context;
469 : for (;;)
470 1834038 : {
471 : MemoryContext parent;
472 :
473 : /* Descend down until we find a leaf context with no children */
474 13177342 : while (curr->firstchild != NULL)
475 1834038 : curr = curr->firstchild;
476 :
477 : /*
478 : * We're now at a leaf with no children. Free it and continue from the
479 : * parent. Or if this was the original node, we're all done.
480 : */
481 11343304 : parent = curr->parent;
482 11343304 : MemoryContextDeleteOnly(curr);
483 :
484 11343304 : if (curr == context)
485 9509266 : break;
486 1834038 : curr = parent;
487 : }
488 9509266 : }
489 :
490 : /*
491 : * Subroutine of MemoryContextDelete,
492 : * to delete a context that has no children.
493 : * We must also delink the context from its parent, if it has one.
494 : */
495 : static void
496 11343304 : MemoryContextDeleteOnly(MemoryContext context)
497 : {
498 : Assert(MemoryContextIsValid(context));
499 : /* We had better not be deleting TopMemoryContext ... */
500 : Assert(context != TopMemoryContext);
501 : /* And not CurrentMemoryContext, either */
502 : Assert(context != CurrentMemoryContext);
503 : /* All the children should've been deleted already */
504 : Assert(context->firstchild == NULL);
505 :
506 : /*
507 : * It's not entirely clear whether 'tis better to do this before or after
508 : * delinking the context; but an error in a callback will likely result in
509 : * leaking the whole context (if it's not a root context) if we do it
510 : * after, so let's do it before.
511 : */
512 11343304 : MemoryContextCallResetCallbacks(context);
513 :
514 : /*
515 : * We delink the context from its parent before deleting it, so that if
516 : * there's an error we won't have deleted/busted contexts still attached
517 : * to the context tree. Better a leak than a crash.
518 : */
519 11343304 : MemoryContextSetParent(context, NULL);
520 :
521 : /*
522 : * Also reset the context's ident pointer, in case it points into the
523 : * context. This would only matter if someone tries to get stats on the
524 : * (already unlinked) context, which is unlikely, but let's be safe.
525 : */
526 11343304 : context->ident = NULL;
527 :
528 11343304 : context->methods->delete_context(context);
529 :
530 : VALGRIND_DESTROY_MEMPOOL(context);
531 11343304 : }
532 :
533 : /*
534 : * MemoryContextDeleteChildren
535 : * Delete all the descendants of the named context and release all
536 : * space allocated therein. The named context itself is not touched.
537 : */
538 : void
539 1044784 : MemoryContextDeleteChildren(MemoryContext context)
540 : {
541 : Assert(MemoryContextIsValid(context));
542 :
543 : /*
544 : * MemoryContextDelete will delink the child from me, so just iterate as
545 : * long as there is a child.
546 : */
547 1719872 : while (context->firstchild != NULL)
548 675088 : MemoryContextDelete(context->firstchild);
549 1044784 : }
550 :
551 : /*
552 : * MemoryContextRegisterResetCallback
553 : * Register a function to be called before next context reset/delete.
554 : * Such callbacks will be called in reverse order of registration.
555 : *
556 : * The caller is responsible for allocating a MemoryContextCallback struct
557 : * to hold the info about this callback request, and for filling in the
558 : * "func" and "arg" fields in the struct to show what function to call with
559 : * what argument. Typically the callback struct should be allocated within
560 : * the specified context, since that means it will automatically be freed
561 : * when no longer needed.
562 : *
563 : * There is no API for deregistering a callback once registered. If you
564 : * want it to not do anything anymore, adjust the state pointed to by its
565 : * "arg" to indicate that.
566 : */
567 : void
568 82088 : MemoryContextRegisterResetCallback(MemoryContext context,
569 : MemoryContextCallback *cb)
570 : {
571 : Assert(MemoryContextIsValid(context));
572 :
573 : /* Push onto head so this will be called before older registrants. */
574 82088 : cb->next = context->reset_cbs;
575 82088 : context->reset_cbs = cb;
576 : /* Mark the context as non-reset (it probably is already). */
577 82088 : context->isReset = false;
578 82088 : }
579 :
580 : /*
581 : * MemoryContextCallResetCallbacks
582 : * Internal function to call all registered callbacks for context.
583 : */
584 : static void
585 67002098 : MemoryContextCallResetCallbacks(MemoryContext context)
586 : {
587 : MemoryContextCallback *cb;
588 :
589 : /*
590 : * We pop each callback from the list before calling. That way, if an
591 : * error occurs inside the callback, we won't try to call it a second time
592 : * in the likely event that we reset or delete the context later.
593 : */
594 67084158 : while ((cb = context->reset_cbs) != NULL)
595 : {
596 82060 : context->reset_cbs = cb->next;
597 82060 : cb->func(cb->arg);
598 : }
599 67002098 : }
600 :
601 : /*
602 : * MemoryContextSetIdentifier
603 : * Set the identifier string for a memory context.
604 : *
605 : * An identifier can be provided to help distinguish among different contexts
606 : * of the same kind in memory context stats dumps. The identifier string
607 : * must live at least as long as the context it is for; typically it is
608 : * allocated inside that context, so that it automatically goes away on
609 : * context deletion. Pass id = NULL to forget any old identifier.
610 : */
611 : void
612 4659086 : MemoryContextSetIdentifier(MemoryContext context, const char *id)
613 : {
614 : Assert(MemoryContextIsValid(context));
615 4659086 : context->ident = id;
616 4659086 : }
617 :
618 : /*
619 : * MemoryContextSetParent
620 : * Change a context to belong to a new parent (or no parent).
621 : *
622 : * We provide this as an API function because it is sometimes useful to
623 : * change a context's lifespan after creation. For example, a context
624 : * might be created underneath a transient context, filled with data,
625 : * and then reparented underneath CacheMemoryContext to make it long-lived.
626 : * In this way no special effort is needed to get rid of the context in case
627 : * a failure occurs before its contents are completely set up.
628 : *
629 : * Callers often assume that this function cannot fail, so don't put any
630 : * elog(ERROR) calls in it.
631 : *
632 : * A possible caller error is to reparent a context under itself, creating
633 : * a loop in the context graph. We assert here that context != new_parent,
634 : * but checking for multi-level loops seems more trouble than it's worth.
635 : */
636 : void
637 11634482 : MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
638 : {
639 : Assert(MemoryContextIsValid(context));
640 : Assert(context != new_parent);
641 :
642 : /* Fast path if it's got correct parent already */
643 11634482 : if (new_parent == context->parent)
644 9402 : return;
645 :
646 : /* Delink from existing parent, if any */
647 11625080 : if (context->parent)
648 : {
649 11625080 : MemoryContext parent = context->parent;
650 :
651 11625080 : if (context->prevchild != NULL)
652 1141226 : context->prevchild->nextchild = context->nextchild;
653 : else
654 : {
655 : Assert(parent->firstchild == context);
656 10483854 : parent->firstchild = context->nextchild;
657 : }
658 :
659 11625080 : if (context->nextchild != NULL)
660 4854948 : context->nextchild->prevchild = context->prevchild;
661 : }
662 :
663 : /* And relink */
664 11625080 : if (new_parent)
665 : {
666 : Assert(MemoryContextIsValid(new_parent));
667 281776 : context->parent = new_parent;
668 281776 : context->prevchild = NULL;
669 281776 : context->nextchild = new_parent->firstchild;
670 281776 : if (new_parent->firstchild != NULL)
671 257502 : new_parent->firstchild->prevchild = context;
672 281776 : new_parent->firstchild = context;
673 : }
674 : else
675 : {
676 11343304 : context->parent = NULL;
677 11343304 : context->prevchild = NULL;
678 11343304 : context->nextchild = NULL;
679 : }
680 : }
681 :
682 : /*
683 : * MemoryContextAllowInCriticalSection
684 : * Allow/disallow allocations in this memory context within a critical
685 : * section.
686 : *
687 : * Normally, memory allocations are not allowed within a critical section,
688 : * because a failure would lead to PANIC. There are a few exceptions to
689 : * that, like allocations related to debugging code that is not supposed to
690 : * be enabled in production. This function can be used to exempt specific
691 : * memory contexts from the assertion in palloc().
692 : */
693 : void
694 4882 : MemoryContextAllowInCriticalSection(MemoryContext context, bool allow)
695 : {
696 : Assert(MemoryContextIsValid(context));
697 :
698 4882 : context->allowInCritSection = allow;
699 4882 : }
700 :
701 : /*
702 : * GetMemoryChunkContext
703 : * Given a currently-allocated chunk, determine the MemoryContext that
704 : * the chunk belongs to.
705 : */
706 : MemoryContext
707 3635368 : GetMemoryChunkContext(void *pointer)
708 : {
709 3635368 : return MCXT_METHOD(pointer, get_chunk_context) (pointer);
710 : }
711 :
712 : /*
713 : * GetMemoryChunkSpace
714 : * Given a currently-allocated chunk, determine the total space
715 : * it occupies (including all memory-allocation overhead).
716 : *
717 : * This is useful for measuring the total space occupied by a set of
718 : * allocated chunks.
719 : */
720 : Size
721 40452894 : GetMemoryChunkSpace(void *pointer)
722 : {
723 40452894 : return MCXT_METHOD(pointer, get_chunk_space) (pointer);
724 : }
725 :
726 : /*
727 : * MemoryContextGetParent
728 : * Get the parent context (if any) of the specified context
729 : */
730 : MemoryContext
731 17516 : MemoryContextGetParent(MemoryContext context)
732 : {
733 : Assert(MemoryContextIsValid(context));
734 :
735 17516 : return context->parent;
736 : }
737 :
738 : /*
739 : * MemoryContextIsEmpty
740 : * Is a memory context empty of any allocated space?
741 : */
742 : bool
743 10712 : MemoryContextIsEmpty(MemoryContext context)
744 : {
745 : Assert(MemoryContextIsValid(context));
746 :
747 : /*
748 : * For now, we consider a memory context nonempty if it has any children;
749 : * perhaps this should be changed later.
750 : */
751 10712 : if (context->firstchild != NULL)
752 2 : return false;
753 : /* Otherwise use the type-specific inquiry */
754 10710 : return context->methods->is_empty(context);
755 : }
756 :
757 : /*
758 : * Find the memory allocated to blocks for this memory context. If recurse is
759 : * true, also include children.
760 : */
761 : Size
762 1802472 : MemoryContextMemAllocated(MemoryContext context, bool recurse)
763 : {
764 1802472 : Size total = context->mem_allocated;
765 :
766 : Assert(MemoryContextIsValid(context));
767 :
768 1802472 : if (recurse)
769 : {
770 1802472 : for (MemoryContext curr = context->firstchild;
771 3048302 : curr != NULL;
772 1245830 : curr = MemoryContextTraverseNext(curr, context))
773 : {
774 1245830 : total += curr->mem_allocated;
775 : }
776 : }
777 :
778 1802472 : return total;
779 : }
780 :
781 : /*
782 : * Return the memory consumption statistics about the given context and its
783 : * children.
784 : */
785 : void
786 30 : MemoryContextMemConsumed(MemoryContext context,
787 : MemoryContextCounters *consumed)
788 : {
789 : Assert(MemoryContextIsValid(context));
790 :
791 30 : memset(consumed, 0, sizeof(*consumed));
792 :
793 : /* Examine the context itself */
794 30 : context->methods->stats(context, NULL, NULL, consumed, false);
795 :
796 : /* Examine children, using iteration not recursion */
797 30 : for (MemoryContext curr = context->firstchild;
798 30 : curr != NULL;
799 0 : curr = MemoryContextTraverseNext(curr, context))
800 : {
801 0 : curr->methods->stats(curr, NULL, NULL, consumed, false);
802 : }
803 30 : }
804 :
805 : /*
806 : * MemoryContextStats
807 : * Print statistics about the named context and all its descendants.
808 : *
809 : * This is just a debugging utility, so it's not very fancy. However, we do
810 : * make some effort to summarize when the output would otherwise be very long.
811 : * The statistics are sent to stderr.
812 : */
813 : void
814 0 : MemoryContextStats(MemoryContext context)
815 : {
816 : /* Hard-wired limits are usually good enough */
817 0 : MemoryContextStatsDetail(context, 100, 100, true);
818 0 : }
819 :
820 : /*
821 : * MemoryContextStatsDetail
822 : *
823 : * Entry point for use if you want to vary the number of child contexts shown.
824 : *
825 : * If print_to_stderr is true, print statistics about the memory contexts
826 : * with fprintf(stderr), otherwise use ereport().
827 : */
828 : void
829 18 : MemoryContextStatsDetail(MemoryContext context,
830 : int max_level, int max_children,
831 : bool print_to_stderr)
832 : {
833 : MemoryContextCounters grand_totals;
834 :
835 18 : memset(&grand_totals, 0, sizeof(grand_totals));
836 :
837 18 : MemoryContextStatsInternal(context, 1, max_level, max_children,
838 : &grand_totals, print_to_stderr);
839 :
840 18 : if (print_to_stderr)
841 0 : fprintf(stderr,
842 : "Grand total: %zu bytes in %zu blocks; %zu free (%zu chunks); %zu used\n",
843 : grand_totals.totalspace, grand_totals.nblocks,
844 : grand_totals.freespace, grand_totals.freechunks,
845 0 : grand_totals.totalspace - grand_totals.freespace);
846 : else
847 : {
848 : /*
849 : * Use LOG_SERVER_ONLY to prevent the memory contexts from being sent
850 : * to the connected client.
851 : *
852 : * We don't buffer the information about all memory contexts in a
853 : * backend into StringInfo and log it as one message. That would
854 : * require the buffer to be enlarged, risking an OOM as there could be
855 : * a large number of memory contexts in a backend. Instead, we log
856 : * one message per memory context.
857 : */
858 18 : ereport(LOG_SERVER_ONLY,
859 : (errhidestmt(true),
860 : errhidecontext(true),
861 : errmsg_internal("Grand total: %zu bytes in %zu blocks; %zu free (%zu chunks); %zu used",
862 : grand_totals.totalspace, grand_totals.nblocks,
863 : grand_totals.freespace, grand_totals.freechunks,
864 : grand_totals.totalspace - grand_totals.freespace)));
865 : }
866 18 : }
867 :
868 : /*
869 : * MemoryContextStatsInternal
870 : * One recursion level for MemoryContextStats
871 : *
872 : * Print stats for this context if possible, but in any case accumulate counts
873 : * into *totals (if not NULL).
874 : */
875 : static void
876 1620 : MemoryContextStatsInternal(MemoryContext context, int level,
877 : int max_level, int max_children,
878 : MemoryContextCounters *totals,
879 : bool print_to_stderr)
880 : {
881 : MemoryContext child;
882 : int ichild;
883 :
884 : Assert(MemoryContextIsValid(context));
885 :
886 : /* Examine the context itself */
887 1620 : context->methods->stats(context,
888 : MemoryContextStatsPrint,
889 : &level,
890 : totals, print_to_stderr);
891 :
892 : /*
893 : * Examine children.
894 : *
895 : * If we are past the recursion depth limit or already running low on
896 : * stack, do not print them explicitly but just summarize them. Similarly,
897 : * if there are more than max_children of them, we do not print the rest
898 : * explicitly, but just summarize them.
899 : */
900 1620 : child = context->firstchild;
901 1620 : ichild = 0;
902 1620 : if (level <= max_level && !stack_is_too_deep())
903 : {
904 3222 : for (; child != NULL && ichild < max_children;
905 1602 : child = child->nextchild, ichild++)
906 : {
907 1602 : MemoryContextStatsInternal(child, level + 1,
908 : max_level, max_children,
909 : totals,
910 : print_to_stderr);
911 : }
912 : }
913 :
914 1620 : if (child != NULL)
915 : {
916 : /* Summarize the rest of the children, avoiding recursion. */
917 : MemoryContextCounters local_totals;
918 :
919 0 : memset(&local_totals, 0, sizeof(local_totals));
920 :
921 0 : ichild = 0;
922 0 : while (child != NULL)
923 : {
924 0 : child->methods->stats(child, NULL, NULL, &local_totals, false);
925 0 : ichild++;
926 0 : child = MemoryContextTraverseNext(child, context);
927 : }
928 :
929 0 : if (print_to_stderr)
930 : {
931 0 : for (int i = 0; i < level; i++)
932 0 : fprintf(stderr, " ");
933 0 : fprintf(stderr,
934 : "%d more child contexts containing %zu total in %zu blocks; %zu free (%zu chunks); %zu used\n",
935 : ichild,
936 : local_totals.totalspace,
937 : local_totals.nblocks,
938 : local_totals.freespace,
939 : local_totals.freechunks,
940 0 : local_totals.totalspace - local_totals.freespace);
941 : }
942 : else
943 0 : ereport(LOG_SERVER_ONLY,
944 : (errhidestmt(true),
945 : errhidecontext(true),
946 : errmsg_internal("level: %d; %d more child contexts containing %zu total in %zu blocks; %zu free (%zu chunks); %zu used",
947 : level,
948 : ichild,
949 : local_totals.totalspace,
950 : local_totals.nblocks,
951 : local_totals.freespace,
952 : local_totals.freechunks,
953 : local_totals.totalspace - local_totals.freespace)));
954 :
955 0 : if (totals)
956 : {
957 0 : totals->nblocks += local_totals.nblocks;
958 0 : totals->freechunks += local_totals.freechunks;
959 0 : totals->totalspace += local_totals.totalspace;
960 0 : totals->freespace += local_totals.freespace;
961 : }
962 : }
963 1620 : }
964 :
965 : /*
966 : * MemoryContextStatsPrint
967 : * Print callback used by MemoryContextStatsInternal
968 : *
969 : * For now, the passthru pointer just points to "int level"; later we might
970 : * make that more complicated.
971 : */
972 : static void
973 1620 : MemoryContextStatsPrint(MemoryContext context, void *passthru,
974 : const char *stats_string,
975 : bool print_to_stderr)
976 : {
977 1620 : int level = *(int *) passthru;
978 1620 : const char *name = context->name;
979 1620 : const char *ident = context->ident;
980 : char truncated_ident[110];
981 : int i;
982 :
983 : /*
984 : * It seems preferable to label dynahash contexts with just the hash table
985 : * name. Those are already unique enough, so the "dynahash" part isn't
986 : * very helpful, and this way is more consistent with pre-v11 practice.
987 : */
988 1620 : if (ident && strcmp(name, "dynahash") == 0)
989 : {
990 210 : name = ident;
991 210 : ident = NULL;
992 : }
993 :
994 1620 : truncated_ident[0] = '\0';
995 :
996 1620 : if (ident)
997 : {
998 : /*
999 : * Some contexts may have very long identifiers (e.g., SQL queries).
1000 : * Arbitrarily truncate at 100 bytes, but be careful not to break
1001 : * multibyte characters. Also, replace ASCII control characters, such
1002 : * as newlines, with spaces.
1003 : */
1004 1140 : int idlen = strlen(ident);
1005 1140 : bool truncated = false;
1006 :
1007 1140 : strcpy(truncated_ident, ": ");
1008 1140 : i = strlen(truncated_ident);
1009 :
1010 1140 : if (idlen > 100)
1011 : {
1012 0 : idlen = pg_mbcliplen(ident, idlen, 100);
1013 0 : truncated = true;
1014 : }
1015 :
1016 31866 : while (idlen-- > 0)
1017 : {
1018 30726 : unsigned char c = *ident++;
1019 :
1020 30726 : if (c < ' ')
1021 0 : c = ' ';
1022 30726 : truncated_ident[i++] = c;
1023 : }
1024 1140 : truncated_ident[i] = '\0';
1025 :
1026 1140 : if (truncated)
1027 0 : strcat(truncated_ident, "...");
1028 : }
1029 :
1030 1620 : if (print_to_stderr)
1031 : {
1032 0 : for (i = 1; i < level; i++)
1033 0 : fprintf(stderr, " ");
1034 0 : fprintf(stderr, "%s: %s%s\n", name, stats_string, truncated_ident);
1035 : }
1036 : else
1037 1620 : ereport(LOG_SERVER_ONLY,
1038 : (errhidestmt(true),
1039 : errhidecontext(true),
1040 : errmsg_internal("level: %d; %s: %s%s",
1041 : level, name, stats_string, truncated_ident)));
1042 1620 : }
1043 :
1044 : /*
1045 : * MemoryContextCheck
1046 : * Check all chunks in the named context and its children.
1047 : *
1048 : * This is just a debugging utility, so it's not fancy.
1049 : */
1050 : #ifdef MEMORY_CONTEXT_CHECKING
1051 : void
1052 : MemoryContextCheck(MemoryContext context)
1053 : {
1054 : Assert(MemoryContextIsValid(context));
1055 : context->methods->check(context);
1056 :
1057 : for (MemoryContext curr = context->firstchild;
1058 : curr != NULL;
1059 : curr = MemoryContextTraverseNext(curr, context))
1060 : {
1061 : Assert(MemoryContextIsValid(curr));
1062 : curr->methods->check(curr);
1063 : }
1064 : }
1065 : #endif
1066 :
1067 : /*
1068 : * MemoryContextCreate
1069 : * Context-type-independent part of context creation.
1070 : *
1071 : * This is only intended to be called by context-type-specific
1072 : * context creation routines, not by the unwashed masses.
1073 : *
1074 : * The memory context creation procedure goes like this:
1075 : * 1. Context-type-specific routine makes some initial space allocation,
1076 : * including enough space for the context header. If it fails,
1077 : * it can ereport() with no damage done.
1078 : * 2. Context-type-specific routine sets up all type-specific fields of
1079 : * the header (those beyond MemoryContextData proper), as well as any
1080 : * other management fields it needs to have a fully valid context.
1081 : * Usually, failure in this step is impossible, but if it's possible
1082 : * the initial space allocation should be freed before ereport'ing.
1083 : * 3. Context-type-specific routine calls MemoryContextCreate() to fill in
1084 : * the generic header fields and link the context into the context tree.
1085 : * 4. We return to the context-type-specific routine, which finishes
1086 : * up type-specific initialization. This routine can now do things
1087 : * that might fail (like allocate more memory), so long as it's
1088 : * sure the node is left in a state that delete will handle.
1089 : *
1090 : * node: the as-yet-uninitialized common part of the context header node.
1091 : * tag: NodeTag code identifying the memory context type.
1092 : * method_id: MemoryContextMethodID of the context-type being created.
1093 : * parent: parent context, or NULL if this will be a top-level context.
1094 : * name: name of context (must be statically allocated).
1095 : *
1096 : * Context routines generally assume that MemoryContextCreate can't fail,
1097 : * so this can contain Assert but not elog/ereport.
1098 : */
1099 : void
1100 14883108 : MemoryContextCreate(MemoryContext node,
1101 : NodeTag tag,
1102 : MemoryContextMethodID method_id,
1103 : MemoryContext parent,
1104 : const char *name)
1105 : {
1106 : /* Creating new memory contexts is not allowed in a critical section */
1107 : Assert(CritSectionCount == 0);
1108 :
1109 : /* Validate parent, to help prevent crazy context linkages */
1110 : Assert(parent == NULL || MemoryContextIsValid(parent));
1111 : Assert(node != parent);
1112 :
1113 : /* Initialize all standard fields of memory context header */
1114 14883108 : node->type = tag;
1115 14883108 : node->isReset = true;
1116 14883108 : node->methods = &mcxt_methods[method_id];
1117 14883108 : node->parent = parent;
1118 14883108 : node->firstchild = NULL;
1119 14883108 : node->mem_allocated = 0;
1120 14883108 : node->prevchild = NULL;
1121 14883108 : node->name = name;
1122 14883108 : node->ident = NULL;
1123 14883108 : node->reset_cbs = NULL;
1124 :
1125 : /* OK to link node into context tree */
1126 14883108 : if (parent)
1127 : {
1128 14879350 : node->nextchild = parent->firstchild;
1129 14879350 : if (parent->firstchild != NULL)
1130 8232490 : parent->firstchild->prevchild = node;
1131 14879350 : parent->firstchild = node;
1132 : /* inherit allowInCritSection flag from parent */
1133 14879350 : node->allowInCritSection = parent->allowInCritSection;
1134 : }
1135 : else
1136 : {
1137 3758 : node->nextchild = NULL;
1138 3758 : node->allowInCritSection = false;
1139 : }
1140 :
1141 : VALGRIND_CREATE_MEMPOOL(node, 0, false);
1142 14883108 : }
1143 :
1144 : /*
1145 : * MemoryContextAllocationFailure
1146 : * For use by MemoryContextMethods implementations to handle when malloc
1147 : * returns NULL. The behavior is specific to whether MCXT_ALLOC_NO_OOM
1148 : * is in 'flags'.
1149 : */
1150 : void *
1151 0 : MemoryContextAllocationFailure(MemoryContext context, Size size, int flags)
1152 : {
1153 0 : if ((flags & MCXT_ALLOC_NO_OOM) == 0)
1154 : {
1155 0 : if (TopMemoryContext)
1156 0 : MemoryContextStats(TopMemoryContext);
1157 0 : ereport(ERROR,
1158 : (errcode(ERRCODE_OUT_OF_MEMORY),
1159 : errmsg("out of memory"),
1160 : errdetail("Failed on request of size %zu in memory context \"%s\".",
1161 : size, context->name)));
1162 : }
1163 0 : return NULL;
1164 : }
1165 :
1166 : /*
1167 : * MemoryContextSizeFailure
1168 : * For use by MemoryContextMethods implementations to handle invalid
1169 : * memory allocation request sizes.
1170 : */
1171 : void
1172 0 : MemoryContextSizeFailure(MemoryContext context, Size size, int flags)
1173 : {
1174 0 : elog(ERROR, "invalid memory alloc request size %zu", size);
1175 : }
1176 :
1177 : /*
1178 : * MemoryContextAlloc
1179 : * Allocate space within the specified context.
1180 : *
1181 : * This could be turned into a macro, but we'd have to import
1182 : * nodes/memnodes.h into postgres.h which seems a bad idea.
1183 : */
1184 : void *
1185 187126948 : MemoryContextAlloc(MemoryContext context, Size size)
1186 : {
1187 : void *ret;
1188 :
1189 : Assert(MemoryContextIsValid(context));
1190 : AssertNotInCriticalSection(context);
1191 :
1192 187126948 : context->isReset = false;
1193 :
1194 : /*
1195 : * For efficiency reasons, we purposefully offload the handling of
1196 : * allocation failures to the MemoryContextMethods implementation as this
1197 : * allows these checks to be performed only when an actual malloc needs to
1198 : * be done to request more memory from the OS. Additionally, not having
1199 : * to execute any instructions after this call allows the compiler to use
1200 : * the sibling call optimization. If you're considering adding code after
1201 : * this call, consider making it the responsibility of the 'alloc'
1202 : * function instead.
1203 : */
1204 187126948 : ret = context->methods->alloc(context, size, 0);
1205 :
1206 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1207 :
1208 187126948 : return ret;
1209 : }
1210 :
1211 : /*
1212 : * MemoryContextAllocZero
1213 : * Like MemoryContextAlloc, but clears allocated memory
1214 : *
1215 : * We could just call MemoryContextAlloc then clear the memory, but this
1216 : * is a very common combination, so we provide the combined operation.
1217 : */
1218 : void *
1219 44739744 : MemoryContextAllocZero(MemoryContext context, Size size)
1220 : {
1221 : void *ret;
1222 :
1223 : Assert(MemoryContextIsValid(context));
1224 : AssertNotInCriticalSection(context);
1225 :
1226 44739744 : context->isReset = false;
1227 :
1228 44739744 : ret = context->methods->alloc(context, size, 0);
1229 :
1230 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1231 :
1232 553870392 : MemSetAligned(ret, 0, size);
1233 :
1234 44739744 : return ret;
1235 : }
1236 :
1237 : /*
1238 : * MemoryContextAllocExtended
1239 : * Allocate space within the specified context using the given flags.
1240 : */
1241 : void *
1242 7361820 : MemoryContextAllocExtended(MemoryContext context, Size size, int flags)
1243 : {
1244 : void *ret;
1245 :
1246 : Assert(MemoryContextIsValid(context));
1247 : AssertNotInCriticalSection(context);
1248 :
1249 7361820 : if (!((flags & MCXT_ALLOC_HUGE) != 0 ? AllocHugeSizeIsValid(size) :
1250 : AllocSizeIsValid(size)))
1251 0 : elog(ERROR, "invalid memory alloc request size %zu", size);
1252 :
1253 7361820 : context->isReset = false;
1254 :
1255 7361820 : ret = context->methods->alloc(context, size, flags);
1256 7361820 : if (unlikely(ret == NULL))
1257 0 : return NULL;
1258 :
1259 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1260 :
1261 7361820 : if ((flags & MCXT_ALLOC_ZERO) != 0)
1262 210268880 : MemSetAligned(ret, 0, size);
1263 :
1264 7361820 : return ret;
1265 : }
1266 :
1267 : /*
1268 : * HandleLogMemoryContextInterrupt
1269 : * Handle receipt of an interrupt indicating logging of memory
1270 : * contexts.
1271 : *
1272 : * All the actual work is deferred to ProcessLogMemoryContextInterrupt(),
1273 : * because we cannot safely emit a log message inside the signal handler.
1274 : */
1275 : void
1276 18 : HandleLogMemoryContextInterrupt(void)
1277 : {
1278 18 : InterruptPending = true;
1279 18 : LogMemoryContextPending = true;
1280 : /* latch will be set by procsignal_sigusr1_handler */
1281 18 : }
1282 :
1283 : /*
1284 : * ProcessLogMemoryContextInterrupt
1285 : * Perform logging of memory contexts of this backend process.
1286 : *
1287 : * Any backend that participates in ProcSignal signaling must arrange
1288 : * to call this function if we see LogMemoryContextPending set.
1289 : * It is called from CHECK_FOR_INTERRUPTS(), which is enough because
1290 : * the target process for logging of memory contexts is a backend.
1291 : */
1292 : void
1293 18 : ProcessLogMemoryContextInterrupt(void)
1294 : {
1295 18 : LogMemoryContextPending = false;
1296 :
1297 : /*
1298 : * Use LOG_SERVER_ONLY to prevent this message from being sent to the
1299 : * connected client.
1300 : */
1301 18 : ereport(LOG_SERVER_ONLY,
1302 : (errhidestmt(true),
1303 : errhidecontext(true),
1304 : errmsg("logging memory contexts of PID %d", MyProcPid)));
1305 :
1306 : /*
1307 : * When a backend process is consuming huge memory, logging all its memory
1308 : * contexts might overrun available disk space. To prevent this, we limit
1309 : * the depth of the hierarchy, as well as the number of child contexts to
1310 : * log per parent to 100.
1311 : *
1312 : * As with MemoryContextStats(), we suppose that practical cases where the
1313 : * dump gets long will typically be huge numbers of siblings under the
1314 : * same parent context; while the additional debugging value from seeing
1315 : * details about individual siblings beyond 100 will not be large.
1316 : */
1317 18 : MemoryContextStatsDetail(TopMemoryContext, 100, 100, false);
1318 18 : }
1319 :
1320 : void *
1321 669900314 : palloc(Size size)
1322 : {
1323 : /* duplicates MemoryContextAlloc to avoid increased overhead */
1324 : void *ret;
1325 669900314 : MemoryContext context = CurrentMemoryContext;
1326 :
1327 : Assert(MemoryContextIsValid(context));
1328 : AssertNotInCriticalSection(context);
1329 :
1330 669900314 : context->isReset = false;
1331 :
1332 : /*
1333 : * For efficiency reasons, we purposefully offload the handling of
1334 : * allocation failures to the MemoryContextMethods implementation as this
1335 : * allows these checks to be performed only when an actual malloc needs to
1336 : * be done to request more memory from the OS. Additionally, not having
1337 : * to execute any instructions after this call allows the compiler to use
1338 : * the sibling call optimization. If you're considering adding code after
1339 : * this call, consider making it the responsibility of the 'alloc'
1340 : * function instead.
1341 : */
1342 669900314 : ret = context->methods->alloc(context, size, 0);
1343 : /* We expect OOM to be handled by the alloc function */
1344 : Assert(ret != NULL);
1345 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1346 :
1347 669900314 : return ret;
1348 : }
1349 :
1350 : void *
1351 478217886 : palloc0(Size size)
1352 : {
1353 : /* duplicates MemoryContextAllocZero to avoid increased overhead */
1354 : void *ret;
1355 478217886 : MemoryContext context = CurrentMemoryContext;
1356 :
1357 : Assert(MemoryContextIsValid(context));
1358 : AssertNotInCriticalSection(context);
1359 :
1360 478217886 : context->isReset = false;
1361 :
1362 478217886 : ret = context->methods->alloc(context, size, 0);
1363 : /* We expect OOM to be handled by the alloc function */
1364 : Assert(ret != NULL);
1365 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1366 :
1367 4397626234 : MemSetAligned(ret, 0, size);
1368 :
1369 478217886 : return ret;
1370 : }
1371 :
1372 : void *
1373 22989354 : palloc_extended(Size size, int flags)
1374 : {
1375 : /* duplicates MemoryContextAllocExtended to avoid increased overhead */
1376 : void *ret;
1377 22989354 : MemoryContext context = CurrentMemoryContext;
1378 :
1379 : Assert(MemoryContextIsValid(context));
1380 : AssertNotInCriticalSection(context);
1381 :
1382 22989354 : context->isReset = false;
1383 :
1384 22989354 : ret = context->methods->alloc(context, size, flags);
1385 22989354 : if (unlikely(ret == NULL))
1386 : {
1387 : /* NULL can be returned only when using MCXT_ALLOC_NO_OOM */
1388 : Assert(flags & MCXT_ALLOC_NO_OOM);
1389 0 : return NULL;
1390 : }
1391 :
1392 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1393 :
1394 22989354 : if ((flags & MCXT_ALLOC_ZERO) != 0)
1395 5258 : MemSetAligned(ret, 0, size);
1396 :
1397 22989354 : return ret;
1398 : }
1399 :
1400 : /*
1401 : * MemoryContextAllocAligned
1402 : * Allocate 'size' bytes of memory in 'context' aligned to 'alignto'
1403 : * bytes.
1404 : *
1405 : * Currently, we align addresses by requesting additional bytes from the
1406 : * MemoryContext's standard allocator function and then aligning the returned
1407 : * address by the required alignment. This means that the given MemoryContext
1408 : * must support providing us with a chunk of memory that's larger than 'size'.
1409 : * For allocators such as Slab, that's not going to work, as slab only allows
1410 : * chunks of the size that's specified when the context is created.
1411 : *
1412 : * 'alignto' must be a power of 2.
1413 : * 'flags' may be 0 or set the same as MemoryContextAllocExtended().
1414 : */
1415 : void *
1416 3209082 : MemoryContextAllocAligned(MemoryContext context,
1417 : Size size, Size alignto, int flags)
1418 : {
1419 : MemoryChunk *alignedchunk;
1420 : Size alloc_size;
1421 : void *unaligned;
1422 : void *aligned;
1423 :
1424 : /* wouldn't make much sense to waste that much space */
1425 : Assert(alignto < (128 * 1024 * 1024));
1426 :
1427 : /* ensure alignto is a power of 2 */
1428 : Assert((alignto & (alignto - 1)) == 0);
1429 :
1430 : /*
1431 : * If the alignment requirements are less than what we already guarantee
1432 : * then just use the standard allocation function.
1433 : */
1434 3209082 : if (unlikely(alignto <= MAXIMUM_ALIGNOF))
1435 0 : return MemoryContextAllocExtended(context, size, flags);
1436 :
1437 : /*
1438 : * We implement aligned pointers by simply allocating enough memory for
1439 : * the requested size plus the alignment and an additional "redirection"
1440 : * MemoryChunk. This additional MemoryChunk is required for operations
1441 : * such as pfree when used on the pointer returned by this function. We
1442 : * use this redirection MemoryChunk in order to find the pointer to the
1443 : * memory that was returned by the MemoryContextAllocExtended call below.
1444 : * We do that by "borrowing" the block offset field and instead of using
1445 : * that to find the offset into the owning block, we use it to find the
1446 : * original allocated address.
1447 : *
1448 : * Here we must allocate enough extra memory so that we can still align
1449 : * the pointer returned by MemoryContextAllocExtended and also have enough
1450 : * space for the redirection MemoryChunk. Since allocations will already
1451 : * be at least aligned by MAXIMUM_ALIGNOF, we can subtract that amount
1452 : * from the allocation size to save a little memory.
1453 : */
1454 3209082 : alloc_size = size + PallocAlignedExtraBytes(alignto);
1455 :
1456 : #ifdef MEMORY_CONTEXT_CHECKING
1457 : /* ensure there's space for a sentinel byte */
1458 : alloc_size += 1;
1459 : #endif
1460 :
1461 : /* perform the actual allocation */
1462 3209082 : unaligned = MemoryContextAllocExtended(context, alloc_size, flags);
1463 :
1464 : /* set the aligned pointer */
1465 3209082 : aligned = (void *) TYPEALIGN(alignto, (char *) unaligned +
1466 : sizeof(MemoryChunk));
1467 :
1468 3209082 : alignedchunk = PointerGetMemoryChunk(aligned);
1469 :
1470 : /*
1471 : * We set the redirect MemoryChunk so that the block offset calculation is
1472 : * used to point back to the 'unaligned' allocated chunk. This allows us
1473 : * to use MemoryChunkGetBlock() to find the unaligned chunk when we need
1474 : * to perform operations such as pfree() and repalloc().
1475 : *
1476 : * We store 'alignto' in the MemoryChunk's 'value' so that we know what
1477 : * the alignment was set to should we ever be asked to realloc this
1478 : * pointer.
1479 : */
1480 3209082 : MemoryChunkSetHdrMask(alignedchunk, unaligned, alignto,
1481 : MCTX_ALIGNED_REDIRECT_ID);
1482 :
1483 : /* double check we produced a correctly aligned pointer */
1484 : Assert((void *) TYPEALIGN(alignto, aligned) == aligned);
1485 :
1486 : #ifdef MEMORY_CONTEXT_CHECKING
1487 : alignedchunk->requested_size = size;
1488 : /* set mark to catch clobber of "unused" space */
1489 : set_sentinel(aligned, size);
1490 : #endif
1491 :
1492 : /* Mark the bytes before the redirection header as noaccess */
1493 : VALGRIND_MAKE_MEM_NOACCESS(unaligned,
1494 : (char *) alignedchunk - (char *) unaligned);
1495 :
1496 : /* Disallow access to the redirection chunk header. */
1497 : VALGRIND_MAKE_MEM_NOACCESS(alignedchunk, sizeof(MemoryChunk));
1498 :
1499 3209082 : return aligned;
1500 : }
1501 :
1502 : /*
1503 : * palloc_aligned
1504 : * Allocate 'size' bytes returning a pointer that's aligned to the
1505 : * 'alignto' boundary.
1506 : *
1507 : * Currently, we align addresses by requesting additional bytes from the
1508 : * MemoryContext's standard allocator function and then aligning the returned
1509 : * address by the required alignment. This means that the given MemoryContext
1510 : * must support providing us with a chunk of memory that's larger than 'size'.
1511 : * For allocators such as Slab, that's not going to work, as slab only allows
1512 : * chunks of the size that's specified when the context is created.
1513 : *
1514 : * 'alignto' must be a power of 2.
1515 : * 'flags' may be 0 or set the same as MemoryContextAllocExtended().
1516 : */
1517 : void *
1518 3082394 : palloc_aligned(Size size, Size alignto, int flags)
1519 : {
1520 3082394 : return MemoryContextAllocAligned(CurrentMemoryContext, size, alignto, flags);
1521 : }
1522 :
1523 : /*
1524 : * pfree
1525 : * Release an allocated chunk.
1526 : */
1527 : void
1528 508785644 : pfree(void *pointer)
1529 : {
1530 : #ifdef USE_VALGRIND
1531 : MemoryContextMethodID method = GetMemoryChunkMethodID(pointer);
1532 : MemoryContext context = GetMemoryChunkContext(pointer);
1533 : #endif
1534 :
1535 508785644 : MCXT_METHOD(pointer, free_p) (pointer);
1536 :
1537 : #ifdef USE_VALGRIND
1538 : if (method != MCTX_ALIGNED_REDIRECT_ID)
1539 : VALGRIND_MEMPOOL_FREE(context, pointer);
1540 : #endif
1541 508785644 : }
1542 :
1543 : /*
1544 : * repalloc
1545 : * Adjust the size of a previously allocated chunk.
1546 : */
1547 : void *
1548 8990324 : repalloc(void *pointer, Size size)
1549 : {
1550 : #ifdef USE_VALGRIND
1551 : MemoryContextMethodID method = GetMemoryChunkMethodID(pointer);
1552 : #endif
1553 : #if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND)
1554 : MemoryContext context = GetMemoryChunkContext(pointer);
1555 : #endif
1556 : void *ret;
1557 :
1558 : AssertNotInCriticalSection(context);
1559 :
1560 : /* isReset must be false already */
1561 : Assert(!context->isReset);
1562 :
1563 : /*
1564 : * For efficiency reasons, we purposefully offload the handling of
1565 : * allocation failures to the MemoryContextMethods implementation as this
1566 : * allows these checks to be performed only when an actual malloc needs to
1567 : * be done to request more memory from the OS. Additionally, not having
1568 : * to execute any instructions after this call allows the compiler to use
1569 : * the sibling call optimization. If you're considering adding code after
1570 : * this call, consider making it the responsibility of the 'realloc'
1571 : * function instead.
1572 : */
1573 8990324 : ret = MCXT_METHOD(pointer, realloc) (pointer, size, 0);
1574 :
1575 : #ifdef USE_VALGRIND
1576 : if (method != MCTX_ALIGNED_REDIRECT_ID)
1577 : VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size);
1578 : #endif
1579 :
1580 8990324 : return ret;
1581 : }
1582 :
1583 : /*
1584 : * repalloc_extended
1585 : * Adjust the size of a previously allocated chunk,
1586 : * with HUGE and NO_OOM options.
1587 : */
1588 : void *
1589 104630 : repalloc_extended(void *pointer, Size size, int flags)
1590 : {
1591 : #if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND)
1592 : MemoryContext context = GetMemoryChunkContext(pointer);
1593 : #endif
1594 : void *ret;
1595 :
1596 : AssertNotInCriticalSection(context);
1597 :
1598 : /* isReset must be false already */
1599 : Assert(!context->isReset);
1600 :
1601 : /*
1602 : * For efficiency reasons, we purposefully offload the handling of
1603 : * allocation failures to the MemoryContextMethods implementation as this
1604 : * allows these checks to be performed only when an actual malloc needs to
1605 : * be done to request more memory from the OS. Additionally, not having
1606 : * to execute any instructions after this call allows the compiler to use
1607 : * the sibling call optimization. If you're considering adding code after
1608 : * this call, consider making it the responsibility of the 'realloc'
1609 : * function instead.
1610 : */
1611 104630 : ret = MCXT_METHOD(pointer, realloc) (pointer, size, flags);
1612 104630 : if (unlikely(ret == NULL))
1613 0 : return NULL;
1614 :
1615 : VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size);
1616 :
1617 104630 : return ret;
1618 : }
1619 :
1620 : /*
1621 : * repalloc0
1622 : * Adjust the size of a previously allocated chunk and zero out the added
1623 : * space.
1624 : */
1625 : void *
1626 49524 : repalloc0(void *pointer, Size oldsize, Size size)
1627 : {
1628 : void *ret;
1629 :
1630 : /* catch wrong argument order */
1631 49524 : if (unlikely(oldsize > size))
1632 0 : elog(ERROR, "invalid repalloc0 call: oldsize %zu, new size %zu",
1633 : oldsize, size);
1634 :
1635 49524 : ret = repalloc(pointer, size);
1636 49524 : memset((char *) ret + oldsize, 0, (size - oldsize));
1637 49524 : return ret;
1638 : }
1639 :
1640 : /*
1641 : * MemoryContextAllocHuge
1642 : * Allocate (possibly-expansive) space within the specified context.
1643 : *
1644 : * See considerations in comment at MaxAllocHugeSize.
1645 : */
1646 : void *
1647 3080 : MemoryContextAllocHuge(MemoryContext context, Size size)
1648 : {
1649 : void *ret;
1650 :
1651 : Assert(MemoryContextIsValid(context));
1652 : AssertNotInCriticalSection(context);
1653 :
1654 3080 : context->isReset = false;
1655 :
1656 : /*
1657 : * For efficiency reasons, we purposefully offload the handling of
1658 : * allocation failures to the MemoryContextMethods implementation as this
1659 : * allows these checks to be performed only when an actual malloc needs to
1660 : * be done to request more memory from the OS. Additionally, not having
1661 : * to execute any instructions after this call allows the compiler to use
1662 : * the sibling call optimization. If you're considering adding code after
1663 : * this call, consider making it the responsibility of the 'alloc'
1664 : * function instead.
1665 : */
1666 3080 : ret = context->methods->alloc(context, size, MCXT_ALLOC_HUGE);
1667 :
1668 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1669 :
1670 3080 : return ret;
1671 : }
1672 :
1673 : /*
1674 : * repalloc_huge
1675 : * Adjust the size of a previously allocated chunk, permitting a large
1676 : * value. The previous allocation need not have been "huge".
1677 : */
1678 : void *
1679 103756 : repalloc_huge(void *pointer, Size size)
1680 : {
1681 : /* this one seems not worth its own implementation */
1682 103756 : return repalloc_extended(pointer, size, MCXT_ALLOC_HUGE);
1683 : }
1684 :
1685 : /*
1686 : * MemoryContextStrdup
1687 : * Like strdup(), but allocate from the specified context
1688 : */
1689 : char *
1690 90293104 : MemoryContextStrdup(MemoryContext context, const char *string)
1691 : {
1692 : char *nstr;
1693 90293104 : Size len = strlen(string) + 1;
1694 :
1695 90293104 : nstr = (char *) MemoryContextAlloc(context, len);
1696 :
1697 90293104 : memcpy(nstr, string, len);
1698 :
1699 90293104 : return nstr;
1700 : }
1701 :
1702 : char *
1703 86663250 : pstrdup(const char *in)
1704 : {
1705 86663250 : return MemoryContextStrdup(CurrentMemoryContext, in);
1706 : }
1707 :
1708 : /*
1709 : * pnstrdup
1710 : * Like pstrdup(), but append null byte to a
1711 : * not-necessarily-null-terminated input string.
1712 : */
1713 : char *
1714 1239358 : pnstrdup(const char *in, Size len)
1715 : {
1716 : char *out;
1717 :
1718 1239358 : len = strnlen(in, len);
1719 :
1720 1239358 : out = palloc(len + 1);
1721 1239358 : memcpy(out, in, len);
1722 1239358 : out[len] = '\0';
1723 :
1724 1239358 : return out;
1725 : }
1726 :
1727 : /*
1728 : * Make copy of string with all trailing newline characters removed.
1729 : */
1730 : char *
1731 424 : pchomp(const char *in)
1732 : {
1733 : size_t n;
1734 :
1735 424 : n = strlen(in);
1736 848 : while (n > 0 && in[n - 1] == '\n')
1737 424 : n--;
1738 424 : return pnstrdup(in, n);
1739 : }
|