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