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 : : *
12 : : * Portions Copyright (c) 1996-2024, 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
556 tgl@sss.pgh.pa.us 191 :CBC 232091590 : 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 [ - + ]: 232091590 : 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 : 232091590 : 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 : 232091590 : 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
556 tgl@sss.pgh.pa.us 220 :UBC 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 : :
365 drowley@postgresql.o 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
37 akorotkov@postgresql 257 :GNC 54795230 : MemoryContextTraverseNext(MemoryContext curr, MemoryContext top)
258 : : {
259 : : /* After processing a node, traverse to its first child if any */
260 [ + + ]: 54795230 : if (curr->firstchild != NULL)
261 : 4551538 : 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 [ + + ]: 54795230 : while (curr->nextchild == NULL)
271 : : {
272 : 5401510 : curr = curr->parent;
273 [ + + ]: 5401510 : if (curr == top)
274 : 849972 : return NULL;
275 : : }
276 : 49393720 : 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
556 tgl@sss.pgh.pa.us 286 :UBC 0 : BogusFree(void *pointer)
287 : : {
288 [ # # ]: 0 : elog(ERROR, "pfree called with invalid pointer %p (header 0x%016llx)",
289 : : pointer, (unsigned long long) GetMemoryChunkHeader(pointer));
290 : : }
291 : :
292 : : static void *
47 drowley@postgresql.o 293 :UNC 0 : BogusRealloc(void *pointer, Size size, int flags)
294 : : {
556 tgl@sss.pgh.pa.us 295 [ # # ]:UBC 0 : elog(ERROR, "repalloc called with invalid pointer %p (header 0x%016llx)",
296 : : pointer, (unsigned long long) 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%016llx)",
304 : : pointer, (unsigned long long) 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%016llx)",
312 : : pointer, (unsigned long long) 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
8691 tgl@sss.pgh.pa.us 339 :CBC 1562 : MemoryContextInit(void)
340 : : {
534 peter@eisentraut.org 341 [ - + ]: 1562 : Assert(TopMemoryContext == NULL);
342 : :
343 : : /*
344 : : * First, initialize TopMemoryContext, which is the parent of all others.
345 : : */
8691 tgl@sss.pgh.pa.us 346 : 1562 : 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 : 1562 : 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 : : */
2011 369 : 1562 : ErrorContext = AllocSetContextCreate(TopMemoryContext,
370 : : "ErrorContext",
371 : : 8 * 1024,
372 : : 8 * 1024,
373 : : 8 * 1024);
3576 heikki.linnakangas@i 374 : 1562 : MemoryContextAllowInCriticalSection(ErrorContext, true);
10141 scrappy@hub.org 375 : 1562 : }
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
8691 tgl@sss.pgh.pa.us 383 : 142447485 : MemoryContextReset(MemoryContext context)
384 : : {
534 peter@eisentraut.org 385 [ + - + + : 142447485 : Assert(MemoryContextIsValid(context));
+ - + - -
+ ]
386 : :
387 : : /* save a function call in common case where there are no children */
6910 tgl@sss.pgh.pa.us 388 [ + + ]: 142447485 : if (context->firstchild != NULL)
3334 389 : 137299 : MemoryContextDeleteChildren(context);
390 : :
391 : : /* save a function call if no pallocs since startup or last reset */
392 [ + + ]: 142447485 : if (!context->isReset)
393 : 18004798 : MemoryContextResetOnly(context);
394 : 142447485 : }
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 : 21084338 : MemoryContextResetOnly(MemoryContext context)
403 : : {
534 peter@eisentraut.org 404 [ + - + + : 21084338 : Assert(MemoryContextIsValid(context));
+ - + - -
+ ]
405 : :
406 : : /* Nothing to do if no pallocs since startup or last reset */
4712 heikki.linnakangas@i 407 [ + + ]: 21084338 : if (!context->isReset)
408 : : {
3334 tgl@sss.pgh.pa.us 409 : 21083827 : 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 : :
2411 peter_e@gmx.net 419 : 21083827 : context->methods->reset(context);
4712 heikki.linnakangas@i 420 : 21083827 : context->isReset = true;
421 : : VALGRIND_DESTROY_MEMPOOL(context);
422 : : VALGRIND_CREATE_MEMPOOL(context, 0, false);
423 : : }
10141 scrappy@hub.org 424 : 21084338 : }
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
8691 tgl@sss.pgh.pa.us 433 :UBC 0 : MemoryContextResetChildren(MemoryContext context)
434 : : {
534 peter@eisentraut.org 435 [ # # # # : 0 : Assert(MemoryContextIsValid(context));
# # # # #
# ]
436 : :
37 akorotkov@postgresql 437 :UNC 0 : for (MemoryContext curr = context->firstchild;
438 [ # # ]: 0 : curr != NULL;
439 : 0 : curr = MemoryContextTraverseNext(curr, context))
440 : : {
441 : 0 : MemoryContextResetOnly(curr);
442 : : }
10141 scrappy@hub.org 443 :UBC 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
8691 tgl@sss.pgh.pa.us 454 :CBC 4448007 : MemoryContextDelete(MemoryContext context)
455 : : {
456 : : MemoryContext curr;
457 : :
37 akorotkov@postgresql 458 [ + - + + :GNC 4448007 : 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 : 4448007 : curr = context;
469 : : for (;;)
470 : 967831 : {
471 : : MemoryContext parent;
472 : :
473 : : /* Descend down until we find a leaf context with no children */
474 [ + + ]: 6383669 : while (curr->firstchild != NULL)
475 : 967831 : 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 : 5415838 : parent = curr->parent;
482 : 5415838 : MemoryContextDeleteOnly(curr);
483 : :
484 [ + + ]: 5415838 : if (curr == context)
485 : 4448007 : break;
486 : 967831 : curr = parent;
487 : : }
488 : 4448007 : }
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 : 5415838 : MemoryContextDeleteOnly(MemoryContext context)
497 : : {
534 peter@eisentraut.org 498 [ + - + + :CBC 5415838 : Assert(MemoryContextIsValid(context));
+ + + + -
+ ]
499 : : /* We had better not be deleting TopMemoryContext ... */
8691 tgl@sss.pgh.pa.us 500 [ - + ]: 5415838 : Assert(context != TopMemoryContext);
501 : : /* And not CurrentMemoryContext, either */
502 [ - + ]: 5415838 : Assert(context != CurrentMemoryContext);
503 : : /* All the children should've been deleted already */
37 akorotkov@postgresql 504 [ - + ]:GNC 5415838 : 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 : : */
3334 tgl@sss.pgh.pa.us 512 :CBC 5415838 : 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 : : */
4599 519 : 5415838 : 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 : : */
2210 526 : 5415838 : context->ident = NULL;
527 : :
2411 peter_e@gmx.net 528 : 5415838 : context->methods->delete_context(context);
529 : :
530 : : VALGRIND_DESTROY_MEMPOOL(context);
10141 scrappy@hub.org 531 : 5415838 : }
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
8691 tgl@sss.pgh.pa.us 539 : 326091 : MemoryContextDeleteChildren(MemoryContext context)
540 : : {
534 peter@eisentraut.org 541 [ + - + + : 326091 : 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 : : */
8691 tgl@sss.pgh.pa.us 547 [ + + ]: 490507 : while (context->firstchild != NULL)
548 : 164416 : MemoryContextDelete(context->firstchild);
10141 scrappy@hub.org 549 : 326091 : }
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
3334 tgl@sss.pgh.pa.us 568 : 21202 : MemoryContextRegisterResetCallback(MemoryContext context,
569 : : MemoryContextCallback *cb)
570 : : {
534 peter@eisentraut.org 571 [ + - - + : 21202 : Assert(MemoryContextIsValid(context));
- - - - -
- ]
572 : :
573 : : /* Push onto head so this will be called before older registrants. */
3334 tgl@sss.pgh.pa.us 574 : 21202 : cb->next = context->reset_cbs;
575 : 21202 : context->reset_cbs = cb;
576 : : /* Mark the context as non-reset (it probably is already). */
577 : 21202 : context->isReset = false;
578 : 21202 : }
579 : :
580 : : /*
581 : : * MemoryContextCallResetCallbacks
582 : : * Internal function to call all registered callbacks for context.
583 : : */
584 : : static void
585 : 26499665 : 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 [ + + ]: 26520853 : while ((cb = context->reset_cbs) != NULL)
595 : : {
596 : 21188 : context->reset_cbs = cb->next;
2411 peter_e@gmx.net 597 : 21188 : cb->func(cb->arg);
598 : : }
3334 tgl@sss.pgh.pa.us 599 : 26499665 : }
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
2210 612 : 1964661 : MemoryContextSetIdentifier(MemoryContext context, const char *id)
613 : : {
534 peter@eisentraut.org 614 [ + - - + : 1964661 : Assert(MemoryContextIsValid(context));
- - - - -
- ]
2210 tgl@sss.pgh.pa.us 615 : 1964661 : context->ident = id;
616 : 1964661 : }
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
4599 637 : 5543914 : MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
638 : : {
534 peter@eisentraut.org 639 [ + - + + : 5543914 : Assert(MemoryContextIsValid(context));
+ + + + -
+ ]
640 [ - + ]: 5543914 : Assert(context != new_parent);
641 : :
642 : : /* Fast path if it's got correct parent already */
3258 tgl@sss.pgh.pa.us 643 [ + + ]: 5543914 : if (new_parent == context->parent)
644 : 4694 : return;
645 : :
646 : : /* Delink from existing parent, if any */
4599 647 [ + - ]: 5539220 : if (context->parent)
648 : : {
649 : 5539220 : MemoryContext parent = context->parent;
650 : :
3050 kgrittn@postgresql.o 651 [ + + ]: 5539220 : if (context->prevchild != NULL)
652 : 436251 : context->prevchild->nextchild = context->nextchild;
653 : : else
654 : : {
655 [ - + ]: 5102969 : Assert(parent->firstchild == context);
656 : 5102969 : parent->firstchild = context->nextchild;
657 : : }
658 : :
659 [ + + ]: 5539220 : if (context->nextchild != NULL)
660 : 2521940 : context->nextchild->prevchild = context->prevchild;
661 : : }
662 : :
663 : : /* And relink */
4599 tgl@sss.pgh.pa.us 664 [ + + ]: 5539220 : if (new_parent)
665 : : {
534 peter@eisentraut.org 666 [ + - - + : 123382 : Assert(MemoryContextIsValid(new_parent));
- - - - -
- ]
4599 tgl@sss.pgh.pa.us 667 : 123382 : context->parent = new_parent;
3050 kgrittn@postgresql.o 668 : 123382 : context->prevchild = NULL;
4599 tgl@sss.pgh.pa.us 669 : 123382 : context->nextchild = new_parent->firstchild;
3050 kgrittn@postgresql.o 670 [ + + ]: 123382 : if (new_parent->firstchild != NULL)
671 : 112895 : new_parent->firstchild->prevchild = context;
4599 tgl@sss.pgh.pa.us 672 : 123382 : new_parent->firstchild = context;
673 : : }
674 : : else
675 : : {
676 : 5415838 : context->parent = NULL;
3050 kgrittn@postgresql.o 677 : 5415838 : context->prevchild = NULL;
4599 tgl@sss.pgh.pa.us 678 : 5415838 : 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
3576 heikki.linnakangas@i 694 : 2385 : MemoryContextAllowInCriticalSection(MemoryContext context, bool allow)
695 : : {
534 peter@eisentraut.org 696 [ + - - + : 2385 : Assert(MemoryContextIsValid(context));
- - - - -
- ]
697 : :
3576 heikki.linnakangas@i 698 : 2385 : context->allowInCritSection = allow;
699 : 2385 : }
700 : :
701 : : /*
702 : : * GetMemoryChunkContext
703 : : * Given a currently-allocated chunk, determine the MemoryContext that
704 : : * the chunk belongs to.
705 : : */
706 : : MemoryContext
594 drowley@postgresql.o 707 : 3735616 : GetMemoryChunkContext(void *pointer)
708 : : {
709 : 3735616 : 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
7916 tgl@sss.pgh.pa.us 721 : 22067047 : GetMemoryChunkSpace(void *pointer)
722 : : {
594 drowley@postgresql.o 723 : 22067047 : 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
4594 tgl@sss.pgh.pa.us 731 : 8657 : MemoryContextGetParent(MemoryContext context)
732 : : {
534 peter@eisentraut.org 733 [ + - - + : 8657 : Assert(MemoryContextIsValid(context));
- - - - -
- ]
734 : :
4594 tgl@sss.pgh.pa.us 735 : 8657 : return context->parent;
736 : : }
737 : :
738 : : /*
739 : : * MemoryContextIsEmpty
740 : : * Is a memory context empty of any allocated space?
741 : : */
742 : : bool
7150 743 : 5374 : MemoryContextIsEmpty(MemoryContext context)
744 : : {
534 peter@eisentraut.org 745 [ + - - + : 5374 : 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 : : */
7150 tgl@sss.pgh.pa.us 751 [ + + ]: 5374 : if (context->firstchild != NULL)
752 : 1 : return false;
753 : : /* Otherwise use the type-specific inquiry */
2411 peter_e@gmx.net 754 : 5373 : 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
1657 tomas.vondra@postgre 762 : 798599 : MemoryContextMemAllocated(MemoryContext context, bool recurse)
763 : : {
1431 tgl@sss.pgh.pa.us 764 : 798599 : Size total = context->mem_allocated;
765 : :
534 peter@eisentraut.org 766 [ + - + + : 798599 : Assert(MemoryContextIsValid(context));
+ - + - -
+ ]
767 : :
1657 tomas.vondra@postgre 768 [ + - ]: 798599 : if (recurse)
769 : : {
37 akorotkov@postgresql 770 :GNC 798599 : for (MemoryContext curr = context->firstchild;
771 [ + + ]: 3236242 : curr != NULL;
772 : 2437643 : curr = MemoryContextTraverseNext(curr, context))
773 : : {
774 : 2437643 : total += curr->mem_allocated;
775 : : }
776 : : }
777 : :
1657 tomas.vondra@postgre 778 :CBC 798599 : return total;
779 : : }
780 : :
781 : : /*
782 : : * Return the memory consumption statistics about the given context and its
783 : : * children.
784 : : */
785 : : void
76 alvherre@alvh.no-ip. 786 :GNC 15 : MemoryContextMemConsumed(MemoryContext context,
787 : : MemoryContextCounters *consumed)
788 : : {
37 akorotkov@postgresql 789 [ + - - + : 15 : Assert(MemoryContextIsValid(context));
- - - - -
- ]
790 : :
76 alvherre@alvh.no-ip. 791 : 15 : memset(consumed, 0, sizeof(*consumed));
792 : :
793 : : /* Examine the context itself */
37 akorotkov@postgresql 794 : 15 : context->methods->stats(context, NULL, NULL, consumed, false);
795 : :
796 : : /* Examine children, using iteration not recursion */
797 : 15 : for (MemoryContext curr = context->firstchild;
798 [ - + ]: 15 : curr != NULL;
37 akorotkov@postgresql 799 :UNC 0 : curr = MemoryContextTraverseNext(curr, context))
800 : : {
801 : 0 : curr->methods->stats(curr, NULL, NULL, consumed, false);
802 : : }
76 alvherre@alvh.no-ip. 803 :GNC 15 : }
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
8691 tgl@sss.pgh.pa.us 814 :UBC 0 : MemoryContextStats(MemoryContext context)
815 : : {
816 : : /* Hard-wired limits are usually good enough */
37 akorotkov@postgresql 817 :UNC 0 : MemoryContextStatsDetail(context, 100, 100, true);
6095 neilc@samurai.com 818 :UBC 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
37 akorotkov@postgresql 829 :GNC 9 : MemoryContextStatsDetail(MemoryContext context,
830 : : int max_level, int max_children,
831 : : bool print_to_stderr)
832 : : {
833 : : MemoryContextCounters grand_totals;
834 : :
3155 tgl@sss.pgh.pa.us 835 :CBC 9 : memset(&grand_totals, 0, sizeof(grand_totals));
836 : :
37 akorotkov@postgresql 837 :GNC 9 : MemoryContextStatsInternal(context, 0, max_level, max_children,
838 : : &grand_totals, print_to_stderr);
839 : :
1104 fujii@postgresql.org 840 [ - + ]:CBC 9 : if (print_to_stderr)
1104 fujii@postgresql.org 841 :UBC 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 : : */
1104 fujii@postgresql.org 858 [ + - ]:CBC 9 : 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 : : }
3155 tgl@sss.pgh.pa.us 866 : 9 : }
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 : 774 : 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 : :
534 peter@eisentraut.org 884 [ + - - + : 774 : Assert(MemoryContextIsValid(context));
- - - - -
- ]
885 : :
886 : : /* Examine the context itself */
2210 tgl@sss.pgh.pa.us 887 [ + - ]: 774 : context->methods->stats(context,
888 : : MemoryContextStatsPrint,
889 : : (void *) &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 : : */
37 akorotkov@postgresql 900 :GNC 774 : child = context->firstchild;
901 : 774 : ichild = 0;
902 [ + - + - ]: 774 : if (level < max_level && !stack_is_too_deep())
903 : : {
904 [ + + + - ]: 1539 : for (; child != NULL && ichild < max_children;
905 : 765 : child = child->nextchild, ichild++)
906 : : {
3155 tgl@sss.pgh.pa.us 907 :CBC 765 : MemoryContextStatsInternal(child, level + 1,
908 : : max_level, max_children,
909 : : totals,
910 : : print_to_stderr);
911 : : }
912 : : }
913 : :
37 akorotkov@postgresql 914 [ - + ]:GNC 774 : if (child != NULL)
915 : : {
916 : : /* Summarize the rest of the children, avoiding recursion. */
917 : : MemoryContextCounters local_totals;
918 : :
37 akorotkov@postgresql 919 :UNC 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 : :
3155 tgl@sss.pgh.pa.us 955 [ # # ]:UBC 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 : : }
10141 scrappy@hub.org 963 :CBC 774 : }
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
2210 tgl@sss.pgh.pa.us 973 : 774 : MemoryContextStatsPrint(MemoryContext context, void *passthru,
974 : : const char *stats_string,
975 : : bool print_to_stderr)
976 : : {
977 : 774 : int level = *(int *) passthru;
978 : 774 : const char *name = context->name;
979 : 774 : 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 [ + + + + ]: 774 : if (ident && strcmp(name, "dynahash") == 0)
989 : : {
990 : 90 : name = ident;
991 : 90 : ident = NULL;
992 : : }
993 : :
1104 fujii@postgresql.org 994 : 774 : truncated_ident[0] = '\0';
995 : :
2210 tgl@sss.pgh.pa.us 996 [ + + ]: 774 : 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 : 549 : int idlen = strlen(ident);
1005 : 549 : bool truncated = false;
1006 : :
1104 fujii@postgresql.org 1007 : 549 : strcpy(truncated_ident, ": ");
1008 : 549 : i = strlen(truncated_ident);
1009 : :
2210 tgl@sss.pgh.pa.us 1010 [ - + ]: 549 : if (idlen > 100)
1011 : : {
2210 tgl@sss.pgh.pa.us 1012 :UBC 0 : idlen = pg_mbcliplen(ident, idlen, 100);
1013 : 0 : truncated = true;
1014 : : }
1015 : :
2210 tgl@sss.pgh.pa.us 1016 [ + + ]:CBC 15171 : while (idlen-- > 0)
1017 : : {
1018 : 14622 : unsigned char c = *ident++;
1019 : :
1020 [ - + ]: 14622 : if (c < ' ')
2210 tgl@sss.pgh.pa.us 1021 :UBC 0 : c = ' ';
1104 fujii@postgresql.org 1022 :CBC 14622 : truncated_ident[i++] = c;
1023 : : }
1024 : 549 : truncated_ident[i] = '\0';
1025 : :
2210 tgl@sss.pgh.pa.us 1026 [ - + ]: 549 : if (truncated)
1104 fujii@postgresql.org 1027 :UBC 0 : strcat(truncated_ident, "...");
1028 : : }
1029 : :
1104 fujii@postgresql.org 1030 [ - + ]:CBC 774 : if (print_to_stderr)
1031 : : {
1104 fujii@postgresql.org 1032 [ # # ]:UBC 0 : for (i = 0; i < level; i++)
1033 : 0 : fprintf(stderr, " ");
1034 : 0 : fprintf(stderr, "%s: %s%s\n", name, stats_string, truncated_ident);
1035 : : }
1036 : : else
1104 fujii@postgresql.org 1037 [ + - ]:CBC 774 : 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)));
2210 tgl@sss.pgh.pa.us 1042 : 774 : }
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
8678 bruce@momjian.us 1052 : 279451 : MemoryContextCheck(MemoryContext context)
1053 : : {
534 peter@eisentraut.org 1054 [ + - - + : 279451 : Assert(MemoryContextIsValid(context));
- - - - -
- ]
2411 peter_e@gmx.net 1055 : 279451 : context->methods->check(context);
1056 : :
37 akorotkov@postgresql 1057 :GNC 279451 : for (MemoryContext curr = context->firstchild;
1058 [ + + ]: 52637038 : curr != NULL;
1059 : 52357587 : curr = MemoryContextTraverseNext(curr, context))
1060 : : {
1061 [ + - + + : 52357587 : Assert(MemoryContextIsValid(curr));
+ + + - -
+ ]
1062 : 52357587 : curr->methods->check(curr);
1063 : : }
8678 bruce@momjian.us 1064 :CBC 279451 : }
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
2314 tgl@sss.pgh.pa.us 1100 : 6896671 : 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 */
3663 heikki.linnakangas@i 1107 [ - + ]: 6896671 : Assert(CritSectionCount == 0);
1108 : :
1109 : : /* Initialize all standard fields of memory context header */
8691 tgl@sss.pgh.pa.us 1110 : 6896671 : node->type = tag;
2314 1111 : 6896671 : node->isReset = true;
594 drowley@postgresql.o 1112 : 6896671 : node->methods = &mcxt_methods[method_id];
2314 tgl@sss.pgh.pa.us 1113 : 6896671 : node->parent = parent;
8691 1114 : 6896671 : node->firstchild = NULL;
1487 jdavis@postgresql.or 1115 : 6896671 : node->mem_allocated = 0;
3050 kgrittn@postgresql.o 1116 : 6896671 : node->prevchild = NULL;
2210 tgl@sss.pgh.pa.us 1117 : 6896671 : node->name = name;
1118 : 6896671 : node->ident = NULL;
2314 1119 : 6896671 : node->reset_cbs = NULL;
1120 : :
1121 : : /* OK to link node into context tree */
8691 1122 [ + + ]: 6896671 : if (parent)
1123 : : {
1124 : 6895070 : node->nextchild = parent->firstchild;
3050 kgrittn@postgresql.o 1125 [ + + ]: 6895070 : if (parent->firstchild != NULL)
1126 : 3931573 : parent->firstchild->prevchild = node;
8691 tgl@sss.pgh.pa.us 1127 : 6895070 : parent->firstchild = node;
1128 : : /* inherit allowInCritSection flag from parent */
3576 heikki.linnakangas@i 1129 : 6895070 : node->allowInCritSection = parent->allowInCritSection;
1130 : : }
1131 : : else
1132 : : {
2314 tgl@sss.pgh.pa.us 1133 : 1601 : node->nextchild = NULL;
1134 : 1601 : node->allowInCritSection = false;
1135 : : }
1136 : :
1137 : : VALGRIND_CREATE_MEMPOOL(node, 0, false);
10141 scrappy@hub.org 1138 : 6896671 : }
1139 : :
1140 : : /*
1141 : : * MemoryContextAllocationFailure
1142 : : * For use by MemoryContextMethods implementations to handle when malloc
1143 : : * returns NULL. The behavior is specific to whether MCXT_ALLOC_NO_OOM
1144 : : * is in 'flags'.
1145 : : */
1146 : : void *
47 drowley@postgresql.o 1147 :UNC 0 : MemoryContextAllocationFailure(MemoryContext context, Size size, int flags)
1148 : : {
1149 [ # # ]: 0 : if ((flags & MCXT_ALLOC_NO_OOM) == 0)
1150 : : {
1151 : 0 : MemoryContextStats(TopMemoryContext);
1152 [ # # ]: 0 : ereport(ERROR,
1153 : : (errcode(ERRCODE_OUT_OF_MEMORY),
1154 : : errmsg("out of memory"),
1155 : : errdetail("Failed on request of size %zu in memory context \"%s\".",
1156 : : size, context->name)));
1157 : : }
1158 : 0 : return NULL;
1159 : : }
1160 : :
1161 : : /*
1162 : : * MemoryContextSizeFailure
1163 : : * For use by MemoryContextMethods implementations to handle invalid
1164 : : * memory allocation request sizes.
1165 : : */
1166 : : void
1167 : 0 : MemoryContextSizeFailure(MemoryContext context, Size size, int flags)
1168 : : {
1169 [ # # ]: 0 : elog(ERROR, "invalid memory alloc request size %zu", size);
1170 : : }
1171 : :
1172 : : /*
1173 : : * MemoryContextAlloc
1174 : : * Allocate space within the specified context.
1175 : : *
1176 : : * This could be turned into a macro, but we'd have to import
1177 : : * nodes/memnodes.h into postgres.h which seems a bad idea.
1178 : : */
1179 : : void *
8691 tgl@sss.pgh.pa.us 1180 :CBC 63013863 : MemoryContextAlloc(MemoryContext context, Size size)
1181 : : {
1182 : : void *ret;
1183 : :
534 peter@eisentraut.org 1184 [ + - + + : 63013863 : Assert(MemoryContextIsValid(context));
+ + + + -
+ ]
3663 heikki.linnakangas@i 1185 [ + + - + ]: 63013863 : AssertNotInCriticalSection(context);
1186 : :
4712 1187 : 63013863 : context->isReset = false;
1188 : :
1189 : : /*
1190 : : * For efficiency reasons, we purposefully offload the handling of
1191 : : * allocation failures to the MemoryContextMethods implementation as this
1192 : : * allows these checks to be performed only when an actual malloc needs to
1193 : : * be done to request more memory from the OS. Additionally, not having
1194 : : * to execute any instructions after this call allows the compiler to use
1195 : : * the sibling call optimization. If you're considering adding code after
1196 : : * this call, consider making it the responsibility of the 'alloc'
1197 : : * function instead.
1198 : : */
47 drowley@postgresql.o 1199 :GNC 63013863 : ret = context->methods->alloc(context, size, 0);
1200 : :
1201 : : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1202 : :
3945 noah@leadboat.com 1203 :CBC 63013862 : return ret;
1204 : : }
1205 : :
1206 : : /*
1207 : : * MemoryContextAllocZero
1208 : : * Like MemoryContextAlloc, but clears allocated memory
1209 : : *
1210 : : * We could just call MemoryContextAlloc then clear the memory, but this
1211 : : * is a very common combination, so we provide the combined operation.
1212 : : */
1213 : : void *
7790 tgl@sss.pgh.pa.us 1214 : 19937261 : MemoryContextAllocZero(MemoryContext context, Size size)
1215 : : {
1216 : : void *ret;
1217 : :
534 peter@eisentraut.org 1218 [ + - + + : 19937261 : Assert(MemoryContextIsValid(context));
+ - + - -
+ ]
3663 heikki.linnakangas@i 1219 [ - + - - ]: 19937261 : AssertNotInCriticalSection(context);
1220 : :
4709 tgl@sss.pgh.pa.us 1221 : 19937261 : context->isReset = false;
1222 : :
47 drowley@postgresql.o 1223 :GNC 19937261 : ret = context->methods->alloc(context, size, 0);
1224 : :
1225 : : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1226 : :
7790 tgl@sss.pgh.pa.us 1227 [ + + + - :CBC 232633844 : MemSetAligned(ret, 0, size);
+ + + + ]
1228 : :
1229 : 19937261 : return ret;
1230 : : }
1231 : :
1232 : : /*
1233 : : * MemoryContextAllocExtended
1234 : : * Allocate space within the specified context using the given flags.
1235 : : */
1236 : : void *
3362 rhaas@postgresql.org 1237 : 3392275 : MemoryContextAllocExtended(MemoryContext context, Size size, int flags)
1238 : : {
1239 : : void *ret;
1240 : :
534 peter@eisentraut.org 1241 [ + - - + : 3392275 : Assert(MemoryContextIsValid(context));
- - - - -
- ]
3362 rhaas@postgresql.org 1242 [ + + - + ]: 3392275 : AssertNotInCriticalSection(context);
1243 : :
548 tgl@sss.pgh.pa.us 1244 [ + + - + ]: 3392275 : if (!((flags & MCXT_ALLOC_HUGE) != 0 ? AllocHugeSizeIsValid(size) :
1245 : : AllocSizeIsValid(size)))
3362 rhaas@postgresql.org 1246 [ # # ]:UBC 0 : elog(ERROR, "invalid memory alloc request size %zu", size);
1247 : :
3362 rhaas@postgresql.org 1248 :CBC 3392275 : context->isReset = false;
1249 : :
47 drowley@postgresql.o 1250 :GNC 3392275 : ret = context->methods->alloc(context, size, flags);
2207 tgl@sss.pgh.pa.us 1251 [ - + ]:CBC 3392275 : if (unlikely(ret == NULL))
3362 rhaas@postgresql.org 1252 :UBC 0 : return NULL;
1253 : :
1254 : : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1255 : :
3362 rhaas@postgresql.org 1256 [ + + ]:CBC 3392275 : if ((flags & MCXT_ALLOC_ZERO) != 0)
1257 [ + + + - : 1474851 : MemSetAligned(ret, 0, size);
+ + + + ]
1258 : :
1259 : 3392275 : return ret;
1260 : : }
1261 : :
1262 : : /*
1263 : : * HandleLogMemoryContextInterrupt
1264 : : * Handle receipt of an interrupt indicating logging of memory
1265 : : * contexts.
1266 : : *
1267 : : * All the actual work is deferred to ProcessLogMemoryContextInterrupt(),
1268 : : * because we cannot safely emit a log message inside the signal handler.
1269 : : */
1270 : : void
1104 fujii@postgresql.org 1271 : 9 : HandleLogMemoryContextInterrupt(void)
1272 : : {
1273 : 9 : InterruptPending = true;
1274 : 9 : LogMemoryContextPending = true;
1275 : : /* latch will be set by procsignal_sigusr1_handler */
1276 : 9 : }
1277 : :
1278 : : /*
1279 : : * ProcessLogMemoryContextInterrupt
1280 : : * Perform logging of memory contexts of this backend process.
1281 : : *
1282 : : * Any backend that participates in ProcSignal signaling must arrange
1283 : : * to call this function if we see LogMemoryContextPending set.
1284 : : * It is called from CHECK_FOR_INTERRUPTS(), which is enough because
1285 : : * the target process for logging of memory contexts is a backend.
1286 : : */
1287 : : void
1288 : 9 : ProcessLogMemoryContextInterrupt(void)
1289 : : {
1290 : 9 : LogMemoryContextPending = false;
1291 : :
1292 : : /*
1293 : : * Use LOG_SERVER_ONLY to prevent this message from being sent to the
1294 : : * connected client.
1295 : : */
807 1296 [ + - ]: 9 : ereport(LOG_SERVER_ONLY,
1297 : : (errhidestmt(true),
1298 : : errhidecontext(true),
1299 : : errmsg("logging memory contexts of PID %d", MyProcPid)));
1300 : :
1301 : : /*
1302 : : * When a backend process is consuming huge memory, logging all its memory
1303 : : * contexts might overrun available disk space. To prevent this, we limit
1304 : : * the depth of the hierarchy, as well as the number of child contexts to
1305 : : * log per parent to 100.
1306 : : *
1307 : : * As with MemoryContextStats(), we suppose that practical cases where the
1308 : : * dump gets long will typically be huge numbers of siblings under the
1309 : : * same parent context; while the additional debugging value from seeing
1310 : : * details about individual siblings beyond 100 will not be large.
1311 : : */
37 akorotkov@postgresql 1312 :GNC 9 : MemoryContextStatsDetail(TopMemoryContext, 100, 100, false);
1104 fujii@postgresql.org 1313 :CBC 9 : }
1314 : :
1315 : : void *
4079 alvherre@alvh.no-ip. 1316 : 237413728 : palloc(Size size)
1317 : : {
1318 : : /* duplicates MemoryContextAlloc to avoid increased overhead */
1319 : : void *ret;
2207 tgl@sss.pgh.pa.us 1320 : 237413728 : MemoryContext context = CurrentMemoryContext;
1321 : :
534 peter@eisentraut.org 1322 [ + - + + : 237413728 : Assert(MemoryContextIsValid(context));
+ - + + -
+ ]
2207 tgl@sss.pgh.pa.us 1323 [ + + - + ]: 237413728 : AssertNotInCriticalSection(context);
1324 : :
1325 : 237413728 : context->isReset = false;
1326 : :
1327 : : /*
1328 : : * For efficiency reasons, we purposefully offload the handling of
1329 : : * allocation failures to the MemoryContextMethods implementation as this
1330 : : * allows these checks to be performed only when an actual malloc needs to
1331 : : * be done to request more memory from the OS. Additionally, not having
1332 : : * to execute any instructions after this call allows the compiler to use
1333 : : * the sibling call optimization. If you're considering adding code after
1334 : : * this call, consider making it the responsibility of the 'alloc'
1335 : : * function instead.
1336 : : */
47 drowley@postgresql.o 1337 :GNC 237413728 : ret = context->methods->alloc(context, size, 0);
1338 : : /* We expect OOM to be handled by the alloc function */
1339 [ - + ]: 237413728 : Assert(ret != NULL);
1340 : : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1341 : :
3945 noah@leadboat.com 1342 :CBC 237413728 : return ret;
1343 : : }
1344 : :
1345 : : void *
4079 alvherre@alvh.no-ip. 1346 : 145922806 : palloc0(Size size)
1347 : : {
1348 : : /* duplicates MemoryContextAllocZero to avoid increased overhead */
1349 : : void *ret;
2207 tgl@sss.pgh.pa.us 1350 : 145922806 : MemoryContext context = CurrentMemoryContext;
1351 : :
534 peter@eisentraut.org 1352 [ + - + + : 145922806 : Assert(MemoryContextIsValid(context));
+ - + - -
+ ]
2207 tgl@sss.pgh.pa.us 1353 [ - + - - ]: 145922806 : AssertNotInCriticalSection(context);
1354 : :
1355 : 145922806 : context->isReset = false;
1356 : :
47 drowley@postgresql.o 1357 :GNC 145922806 : ret = context->methods->alloc(context, size, 0);
1358 : :
1359 : : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1360 : :
4079 alvherre@alvh.no-ip. 1361 [ + + + - :CBC 1461981733 : MemSetAligned(ret, 0, size);
+ + + + ]
1362 : :
1363 : 145922806 : return ret;
1364 : : }
1365 : :
1366 : : void *
3299 fujii@postgresql.org 1367 : 915822 : palloc_extended(Size size, int flags)
1368 : : {
1369 : : /* duplicates MemoryContextAllocExtended to avoid increased overhead */
1370 : : void *ret;
2207 tgl@sss.pgh.pa.us 1371 : 915822 : MemoryContext context = CurrentMemoryContext;
1372 : :
534 peter@eisentraut.org 1373 [ + - - + : 915822 : Assert(MemoryContextIsValid(context));
- - - - -
- ]
2207 tgl@sss.pgh.pa.us 1374 [ - + - - ]: 915822 : AssertNotInCriticalSection(context);
1375 : :
1376 : 915822 : context->isReset = false;
1377 : :
47 drowley@postgresql.o 1378 :GNC 915822 : ret = context->methods->alloc(context, size, flags);
2207 tgl@sss.pgh.pa.us 1379 [ - + ]:CBC 915822 : if (unlikely(ret == NULL))
1380 : : {
3299 fujii@postgresql.org 1381 :UBC 0 : return NULL;
1382 : : }
1383 : :
1384 : : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1385 : :
3299 fujii@postgresql.org 1386 [ + + ]:CBC 915822 : if ((flags & MCXT_ALLOC_ZERO) != 0)
1387 [ + - + - : 2626 : MemSetAligned(ret, 0, size);
- + - - ]
1388 : :
1389 : 915822 : return ret;
1390 : : }
1391 : :
1392 : : /*
1393 : : * MemoryContextAllocAligned
1394 : : * Allocate 'size' bytes of memory in 'context' aligned to 'alignto'
1395 : : * bytes.
1396 : : *
1397 : : * Currently, we align addresses by requesting additional bytes from the
1398 : : * MemoryContext's standard allocator function and then aligning the returned
1399 : : * address by the required alignment. This means that the given MemoryContext
1400 : : * must support providing us with a chunk of memory that's larger than 'size'.
1401 : : * For allocators such as Slab, that's not going to work, as slab only allows
1402 : : * chunks of the size that's specified when the context is created.
1403 : : *
1404 : : * 'alignto' must be a power of 2.
1405 : : * 'flags' may be 0 or set the same as MemoryContextAllocExtended().
1406 : : */
1407 : : void *
479 drowley@postgresql.o 1408 : 1526541 : MemoryContextAllocAligned(MemoryContext context,
1409 : : Size size, Size alignto, int flags)
1410 : : {
1411 : : MemoryChunk *alignedchunk;
1412 : : Size alloc_size;
1413 : : void *unaligned;
1414 : : void *aligned;
1415 : :
1416 : : /* wouldn't make much sense to waste that much space */
1417 [ - + ]: 1526541 : Assert(alignto < (128 * 1024 * 1024));
1418 : :
1419 : : /* ensure alignto is a power of 2 */
1420 [ - + ]: 1526541 : Assert((alignto & (alignto - 1)) == 0);
1421 : :
1422 : : /*
1423 : : * If the alignment requirements are less than what we already guarantee
1424 : : * then just use the standard allocation function.
1425 : : */
1426 [ - + ]: 1526541 : if (unlikely(alignto <= MAXIMUM_ALIGNOF))
479 drowley@postgresql.o 1427 :UBC 0 : return MemoryContextAllocExtended(context, size, flags);
1428 : :
1429 : : /*
1430 : : * We implement aligned pointers by simply allocating enough memory for
1431 : : * the requested size plus the alignment and an additional "redirection"
1432 : : * MemoryChunk. This additional MemoryChunk is required for operations
1433 : : * such as pfree when used on the pointer returned by this function. We
1434 : : * use this redirection MemoryChunk in order to find the pointer to the
1435 : : * memory that was returned by the MemoryContextAllocExtended call below.
1436 : : * We do that by "borrowing" the block offset field and instead of using
1437 : : * that to find the offset into the owning block, we use it to find the
1438 : : * original allocated address.
1439 : : *
1440 : : * Here we must allocate enough extra memory so that we can still align
1441 : : * the pointer returned by MemoryContextAllocExtended and also have enough
1442 : : * space for the redirection MemoryChunk. Since allocations will already
1443 : : * be at least aligned by MAXIMUM_ALIGNOF, we can subtract that amount
1444 : : * from the allocation size to save a little memory.
1445 : : */
479 drowley@postgresql.o 1446 :CBC 1526541 : alloc_size = size + PallocAlignedExtraBytes(alignto);
1447 : :
1448 : : #ifdef MEMORY_CONTEXT_CHECKING
1449 : : /* ensure there's space for a sentinel byte */
1450 : 1526541 : alloc_size += 1;
1451 : : #endif
1452 : :
1453 : : /* perform the actual allocation */
1454 : 1526541 : unaligned = MemoryContextAllocExtended(context, alloc_size, flags);
1455 : :
1456 : : /* set the aligned pointer */
1457 : 1526541 : aligned = (void *) TYPEALIGN(alignto, (char *) unaligned +
1458 : : sizeof(MemoryChunk));
1459 : :
1460 : 1526541 : alignedchunk = PointerGetMemoryChunk(aligned);
1461 : :
1462 : : /*
1463 : : * We set the redirect MemoryChunk so that the block offset calculation is
1464 : : * used to point back to the 'unaligned' allocated chunk. This allows us
1465 : : * to use MemoryChunkGetBlock() to find the unaligned chunk when we need
1466 : : * to perform operations such as pfree() and repalloc().
1467 : : *
1468 : : * We store 'alignto' in the MemoryChunk's 'value' so that we know what
1469 : : * the alignment was set to should we ever be asked to realloc this
1470 : : * pointer.
1471 : : */
1472 : 1526541 : MemoryChunkSetHdrMask(alignedchunk, unaligned, alignto,
1473 : : MCTX_ALIGNED_REDIRECT_ID);
1474 : :
1475 : : /* double check we produced a correctly aligned pointer */
1476 [ - + ]: 1526541 : Assert((void *) TYPEALIGN(alignto, aligned) == aligned);
1477 : :
1478 : : #ifdef MEMORY_CONTEXT_CHECKING
1479 : 1526541 : alignedchunk->requested_size = size;
1480 : : /* set mark to catch clobber of "unused" space */
1481 : 1526541 : set_sentinel(aligned, size);
1482 : : #endif
1483 : :
1484 : : /* Mark the bytes before the redirection header as noaccess */
1485 : : VALGRIND_MAKE_MEM_NOACCESS(unaligned,
1486 : : (char *) alignedchunk - (char *) unaligned);
1487 : :
1488 : : /* Disallow access to the redirection chunk header. */
1489 : : VALGRIND_MAKE_MEM_NOACCESS(alignedchunk, sizeof(MemoryChunk));
1490 : :
1491 : 1526541 : return aligned;
1492 : : }
1493 : :
1494 : : /*
1495 : : * palloc_aligned
1496 : : * Allocate 'size' bytes returning a pointer that's aligned to the
1497 : : * 'alignto' boundary.
1498 : : *
1499 : : * Currently, we align addresses by requesting additional bytes from the
1500 : : * MemoryContext's standard allocator function and then aligning the returned
1501 : : * address by the required alignment. This means that the given MemoryContext
1502 : : * must support providing us with a chunk of memory that's larger than 'size'.
1503 : : * For allocators such as Slab, that's not going to work, as slab only allows
1504 : : * chunks of the size that's specified when the context is created.
1505 : : *
1506 : : * 'alignto' must be a power of 2.
1507 : : * 'flags' may be 0 or set the same as MemoryContextAllocExtended().
1508 : : */
1509 : : void *
1510 : 1472487 : palloc_aligned(Size size, Size alignto, int flags)
1511 : : {
1512 : 1472487 : return MemoryContextAllocAligned(CurrentMemoryContext, size, alignto, flags);
1513 : : }
1514 : :
1515 : : /*
1516 : : * pfree
1517 : : * Release an allocated chunk.
1518 : : */
1519 : : void
8691 tgl@sss.pgh.pa.us 1520 : 203873307 : pfree(void *pointer)
1521 : : {
1522 : : #ifdef USE_VALGRIND
1523 : : MemoryContextMethodID method = GetMemoryChunkMethodID(pointer);
1524 : : MemoryContext context = GetMemoryChunkContext(pointer);
1525 : : #endif
1526 : :
594 drowley@postgresql.o 1527 : 203873307 : MCXT_METHOD(pointer, free_p) (pointer);
1528 : :
1529 : : #ifdef USE_VALGRIND
1530 : : if (method != MCTX_ALIGNED_REDIRECT_ID)
1531 : : VALGRIND_MEMPOOL_FREE(context, pointer);
1532 : : #endif
10141 scrappy@hub.org 1533 : 203873307 : }
1534 : :
1535 : : /*
1536 : : * repalloc
1537 : : * Adjust the size of a previously allocated chunk.
1538 : : */
1539 : : void *
8691 tgl@sss.pgh.pa.us 1540 : 2372282 : repalloc(void *pointer, Size size)
1541 : : {
1542 : : #ifdef USE_VALGRIND
1543 : : MemoryContextMethodID method = GetMemoryChunkMethodID(pointer);
1544 : : #endif
1545 : : #if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND)
2603 andres@anarazel.de 1546 : 2372282 : MemoryContext context = GetMemoryChunkContext(pointer);
1547 : : #endif
1548 : : void *ret;
1549 : :
3663 heikki.linnakangas@i 1550 [ + + - + ]: 2372282 : AssertNotInCriticalSection(context);
1551 : :
1552 : : /* isReset must be false already */
3944 noah@leadboat.com 1553 [ - + ]: 2372282 : Assert(!context->isReset);
1554 : :
1555 : : /*
1556 : : * For efficiency reasons, we purposefully offload the handling of
1557 : : * allocation failures to the MemoryContextMethods implementation as this
1558 : : * allows these checks to be performed only when an actual malloc needs to
1559 : : * be done to request more memory from the OS. Additionally, not having
1560 : : * to execute any instructions after this call allows the compiler to use
1561 : : * the sibling call optimization. If you're considering adding code after
1562 : : * this call, consider making it the responsibility of the 'realloc'
1563 : : * function instead.
1564 : : */
47 drowley@postgresql.o 1565 :GNC 2372282 : ret = MCXT_METHOD(pointer, realloc) (pointer, size, 0);
1566 : :
1567 : : #ifdef USE_VALGRIND
1568 : : if (method != MCTX_ALIGNED_REDIRECT_ID)
1569 : : VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size);
1570 : : #endif
1571 : :
3944 noah@leadboat.com 1572 :CBC 2372282 : return ret;
1573 : : }
1574 : :
1575 : : /*
1576 : : * repalloc_extended
1577 : : * Adjust the size of a previously allocated chunk,
1578 : : * with HUGE and NO_OOM options.
1579 : : */
1580 : : void *
548 tgl@sss.pgh.pa.us 1581 : 43338 : repalloc_extended(void *pointer, Size size, int flags)
1582 : : {
1583 : : #if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND)
1584 : 43338 : MemoryContext context = GetMemoryChunkContext(pointer);
1585 : : #endif
1586 : : void *ret;
1587 : :
1588 [ - + - - ]: 43338 : AssertNotInCriticalSection(context);
1589 : :
1590 : : /* isReset must be false already */
1591 [ - + ]: 43338 : Assert(!context->isReset);
1592 : :
1593 : : /*
1594 : : * For efficiency reasons, we purposefully offload the handling of
1595 : : * allocation failures to the MemoryContextMethods implementation as this
1596 : : * allows these checks to be performed only when an actual malloc needs to
1597 : : * be done to request more memory from the OS. Additionally, not having
1598 : : * to execute any instructions after this call allows the compiler to use
1599 : : * the sibling call optimization. If you're considering adding code after
1600 : : * this call, consider making it the responsibility of the 'realloc'
1601 : : * function instead.
1602 : : */
47 drowley@postgresql.o 1603 :GNC 43338 : ret = MCXT_METHOD(pointer, realloc) (pointer, size, flags);
548 tgl@sss.pgh.pa.us 1604 [ - + ]:CBC 43338 : if (unlikely(ret == NULL))
548 tgl@sss.pgh.pa.us 1605 :UBC 0 : return NULL;
1606 : :
1607 : : VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size);
1608 : :
548 tgl@sss.pgh.pa.us 1609 :CBC 43338 : return ret;
1610 : : }
1611 : :
1612 : : /*
1613 : : * repalloc0
1614 : : * Adjust the size of a previously allocated chunk and zero out the added
1615 : : * space.
1616 : : */
1617 : : void *
519 peter@eisentraut.org 1618 : 23007 : repalloc0(void *pointer, Size oldsize, Size size)
1619 : : {
1620 : : void *ret;
1621 : :
1622 : : /* catch wrong argument order */
1623 [ - + ]: 23007 : if (unlikely(oldsize > size))
519 peter@eisentraut.org 1624 [ # # ]:UBC 0 : elog(ERROR, "invalid repalloc0 call: oldsize %zu, new size %zu",
1625 : : oldsize, size);
1626 : :
519 peter@eisentraut.org 1627 :CBC 23007 : ret = repalloc(pointer, size);
1628 : 23007 : memset((char *) ret + oldsize, 0, (size - oldsize));
1629 : 23007 : return ret;
1630 : : }
1631 : :
1632 : : /*
1633 : : * MemoryContextAllocHuge
1634 : : * Allocate (possibly-expansive) space within the specified context.
1635 : : *
1636 : : * See considerations in comment at MaxAllocHugeSize.
1637 : : */
1638 : : void *
3944 noah@leadboat.com 1639 : 1593 : MemoryContextAllocHuge(MemoryContext context, Size size)
1640 : : {
1641 : : void *ret;
1642 : :
534 peter@eisentraut.org 1643 [ + - - + : 1593 : Assert(MemoryContextIsValid(context));
- - - - -
- ]
3663 heikki.linnakangas@i 1644 [ - + - - ]: 1593 : AssertNotInCriticalSection(context);
1645 : :
3944 noah@leadboat.com 1646 : 1593 : context->isReset = false;
1647 : :
1648 : : /*
1649 : : * For efficiency reasons, we purposefully offload the handling of
1650 : : * allocation failures to the MemoryContextMethods implementation as this
1651 : : * allows these checks to be performed only when an actual malloc needs to
1652 : : * be done to request more memory from the OS. Additionally, not having
1653 : : * to execute any instructions after this call allows the compiler to use
1654 : : * the sibling call optimization. If you're considering adding code after
1655 : : * this call, consider making it the responsibility of the 'alloc'
1656 : : * function instead.
1657 : : */
47 drowley@postgresql.o 1658 :GNC 1593 : ret = context->methods->alloc(context, size, MCXT_ALLOC_HUGE);
1659 : :
1660 : : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1661 : :
3944 noah@leadboat.com 1662 :CBC 1593 : return ret;
1663 : : }
1664 : :
1665 : : /*
1666 : : * repalloc_huge
1667 : : * Adjust the size of a previously allocated chunk, permitting a large
1668 : : * value. The previous allocation need not have been "huge".
1669 : : */
1670 : : void *
1671 : 42962 : repalloc_huge(void *pointer, Size size)
1672 : : {
1673 : : /* this one seems not worth its own implementation */
548 tgl@sss.pgh.pa.us 1674 : 42962 : return repalloc_extended(pointer, size, MCXT_ALLOC_HUGE);
1675 : : }
1676 : :
1677 : : /*
1678 : : * MemoryContextStrdup
1679 : : * Like strdup(), but allocate from the specified context
1680 : : */
1681 : : char *
8691 1682 : 23404790 : MemoryContextStrdup(MemoryContext context, const char *string)
1683 : : {
1684 : : char *nstr;
1685 : 23404790 : Size len = strlen(string) + 1;
1686 : :
1687 : 23404790 : nstr = (char *) MemoryContextAlloc(context, len);
1688 : :
1689 : 23404790 : memcpy(nstr, string, len);
1690 : :
1691 : 23404790 : return nstr;
1692 : : }
1693 : :
1694 : : char *
4079 alvherre@alvh.no-ip. 1695 : 21900583 : pstrdup(const char *in)
1696 : : {
1697 : 21900583 : return MemoryContextStrdup(CurrentMemoryContext, in);
1698 : : }
1699 : :
1700 : : /*
1701 : : * pnstrdup
1702 : : * Like pstrdup(), but append null byte to a
1703 : : * not-necessarily-null-terminated input string.
1704 : : */
1705 : : char *
5769 tgl@sss.pgh.pa.us 1706 : 646174 : pnstrdup(const char *in, Size len)
1707 : : {
1708 : : char *out;
1709 : :
2378 andres@anarazel.de 1710 : 646174 : len = strnlen(in, len);
1711 : :
2379 1712 : 646174 : out = palloc(len + 1);
5769 tgl@sss.pgh.pa.us 1713 : 646174 : memcpy(out, in, len);
1714 : 646174 : out[len] = '\0';
1715 : :
1716 : 646174 : return out;
1717 : : }
1718 : :
1719 : : /*
1720 : : * Make copy of string with all trailing newline characters removed.
1721 : : */
1722 : : char *
2603 peter_e@gmx.net 1723 : 349 : pchomp(const char *in)
1724 : : {
1725 : : size_t n;
1726 : :
1727 : 349 : n = strlen(in);
1728 [ + - + + ]: 698 : while (n > 0 && in[n - 1] == '\n')
1729 : 349 : n--;
1730 : 349 : return pnstrdup(in, n);
1731 : : }
|