/src/postgres/src/backend/utils/mmgr/mcxt.c
Line | Count | Source |
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 | 12.3M | 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 | 598k | 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 |
214 | | GetMemoryChunkMethodID(const void *pointer) |
215 | 598k | { |
216 | 598k | 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 | 598k | Assert(pointer == (const void *) MAXALIGN(pointer)); |
224 | | |
225 | | /* Allow access to the uint64 header */ |
226 | 598k | VALGRIND_MAKE_MEM_DEFINED((char *) pointer - sizeof(uint64), sizeof(uint64)); |
227 | | |
228 | 598k | header = *((const uint64 *) ((const char *) pointer - sizeof(uint64))); |
229 | | |
230 | | /* Disallow access to the uint64 header */ |
231 | 598k | VALGRIND_MAKE_MEM_NOACCESS((char *) pointer - sizeof(uint64), sizeof(uint64)); |
232 | | |
233 | 598k | return (MemoryContextMethodID) (header & MEMORY_CONTEXT_METHODID_MASK); |
234 | 598k | } |
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 |
243 | | GetMemoryChunkHeader(const void *pointer) |
244 | 0 | { |
245 | 0 | uint64 header; |
246 | | |
247 | | /* Allow access to the uint64 header */ |
248 | 0 | VALGRIND_MAKE_MEM_DEFINED((char *) pointer - sizeof(uint64), sizeof(uint64)); |
249 | |
|
250 | 0 | header = *((const uint64 *) ((const char *) pointer - sizeof(uint64))); |
251 | | |
252 | | /* Disallow access to the uint64 header */ |
253 | 0 | VALGRIND_MAKE_MEM_NOACCESS((char *) pointer - sizeof(uint64), sizeof(uint64)); |
254 | |
|
255 | 0 | return header; |
256 | 0 | } |
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 |
280 | | MemoryContextTraverseNext(MemoryContext curr, MemoryContext top) |
281 | 0 | { |
282 | | /* After processing a node, traverse to its first child if any */ |
283 | 0 | if (curr->firstchild != NULL) |
284 | 0 | 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 | 0 | while (curr->nextchild == NULL) |
294 | 0 | { |
295 | 0 | curr = curr->parent; |
296 | 0 | if (curr == top) |
297 | 0 | return NULL; |
298 | 0 | } |
299 | 0 | return curr->nextchild; |
300 | 0 | } |
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 |
309 | | BogusFree(void *pointer) |
310 | 0 | { |
311 | 0 | elog(ERROR, "pfree called with invalid pointer %p (header 0x%016" PRIx64 ")", |
312 | 0 | pointer, GetMemoryChunkHeader(pointer)); |
313 | 0 | } |
314 | | |
315 | | static void * |
316 | | BogusRealloc(void *pointer, Size size, int flags) |
317 | 0 | { |
318 | 0 | elog(ERROR, "repalloc called with invalid pointer %p (header 0x%016" PRIx64 ")", |
319 | 0 | pointer, GetMemoryChunkHeader(pointer)); |
320 | 0 | return NULL; /* keep compiler quiet */ |
321 | 0 | } |
322 | | |
323 | | static MemoryContext |
324 | | BogusGetChunkContext(void *pointer) |
325 | 0 | { |
326 | 0 | elog(ERROR, "GetMemoryChunkContext called with invalid pointer %p (header 0x%016" PRIx64 ")", |
327 | 0 | pointer, GetMemoryChunkHeader(pointer)); |
328 | 0 | return NULL; /* keep compiler quiet */ |
329 | 0 | } |
330 | | |
331 | | static Size |
332 | | BogusGetChunkSpace(void *pointer) |
333 | 0 | { |
334 | 0 | elog(ERROR, "GetMemoryChunkSpace called with invalid pointer %p (header 0x%016" PRIx64 ")", |
335 | 0 | pointer, GetMemoryChunkHeader(pointer)); |
336 | 0 | return 0; /* keep compiler quiet */ |
337 | 0 | } |
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 |
362 | | MemoryContextInit(void) |
363 | 2.03k | { |
364 | 2.03k | Assert(TopMemoryContext == NULL); |
365 | | |
366 | | /* |
367 | | * First, initialize TopMemoryContext, which is the parent of all others. |
368 | | */ |
369 | 2.03k | TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL, |
370 | 2.03k | "TopMemoryContext", |
371 | 2.03k | 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 | 2.03k | 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 | | */ |
392 | 2.03k | ErrorContext = AllocSetContextCreate(TopMemoryContext, |
393 | 2.03k | "ErrorContext", |
394 | 2.03k | 8 * 1024, |
395 | 2.03k | 8 * 1024, |
396 | 2.03k | 8 * 1024); |
397 | 2.03k | MemoryContextAllowInCriticalSection(ErrorContext, true); |
398 | 2.03k | } |
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 |
406 | | MemoryContextReset(MemoryContext context) |
407 | 14.9k | { |
408 | 14.9k | Assert(MemoryContextIsValid(context)); |
409 | | |
410 | | /* save a function call in common case where there are no children */ |
411 | 14.9k | if (context->firstchild != NULL) |
412 | 2.03k | MemoryContextDeleteChildren(context); |
413 | | |
414 | | /* save a function call if no pallocs since startup or last reset */ |
415 | 14.9k | if (!context->isReset) |
416 | 12.4k | MemoryContextResetOnly(context); |
417 | 14.9k | } |
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 | | MemoryContextResetOnly(MemoryContext context) |
426 | 12.4k | { |
427 | 12.4k | Assert(MemoryContextIsValid(context)); |
428 | | |
429 | | /* Nothing to do if no pallocs since startup or last reset */ |
430 | 12.4k | if (!context->isReset) |
431 | 12.4k | { |
432 | 12.4k | 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 | | |
442 | 12.4k | context->methods->reset(context); |
443 | 12.4k | context->isReset = true; |
444 | 12.4k | } |
445 | 12.4k | } |
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 |
454 | | MemoryContextResetChildren(MemoryContext context) |
455 | 0 | { |
456 | 0 | Assert(MemoryContextIsValid(context)); |
457 | |
|
458 | 0 | for (MemoryContext curr = context->firstchild; |
459 | 0 | curr != NULL; |
460 | 0 | curr = MemoryContextTraverseNext(curr, context)) |
461 | 0 | { |
462 | 0 | MemoryContextResetOnly(curr); |
463 | 0 | } |
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 |
475 | | MemoryContextDelete(MemoryContext context) |
476 | 2.03k | { |
477 | 2.03k | MemoryContext curr; |
478 | | |
479 | 2.03k | 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 | 2.03k | curr = context; |
490 | 2.03k | for (;;) |
491 | 2.03k | { |
492 | 2.03k | MemoryContext parent; |
493 | | |
494 | | /* Descend down until we find a leaf context with no children */ |
495 | 2.03k | while (curr->firstchild != NULL) |
496 | 0 | 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 | 2.03k | parent = curr->parent; |
503 | 2.03k | MemoryContextDeleteOnly(curr); |
504 | | |
505 | 2.03k | if (curr == context) |
506 | 2.03k | break; |
507 | 0 | curr = parent; |
508 | 0 | } |
509 | 2.03k | } |
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 | | MemoryContextDeleteOnly(MemoryContext context) |
518 | 2.03k | { |
519 | 2.03k | Assert(MemoryContextIsValid(context)); |
520 | | /* We had better not be deleting TopMemoryContext ... */ |
521 | 2.03k | Assert(context != TopMemoryContext); |
522 | | /* And not CurrentMemoryContext, either */ |
523 | 2.03k | Assert(context != CurrentMemoryContext); |
524 | | /* All the children should've been deleted already */ |
525 | 2.03k | 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 | | */ |
533 | 2.03k | 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 | | */ |
540 | 2.03k | 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 | | */ |
547 | 2.03k | context->ident = NULL; |
548 | | |
549 | 2.03k | context->methods->delete_context(context); |
550 | 2.03k | } |
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 |
558 | | MemoryContextDeleteChildren(MemoryContext context) |
559 | 2.03k | { |
560 | 2.03k | 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 | | */ |
566 | 4.07k | while (context->firstchild != NULL) |
567 | 2.03k | MemoryContextDelete(context->firstchild); |
568 | 2.03k | } |
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 |
585 | | MemoryContextRegisterResetCallback(MemoryContext context, |
586 | | MemoryContextCallback *cb) |
587 | 0 | { |
588 | 0 | Assert(MemoryContextIsValid(context)); |
589 | | |
590 | | /* Push onto head so this will be called before older registrants. */ |
591 | 0 | cb->next = context->reset_cbs; |
592 | 0 | context->reset_cbs = cb; |
593 | | /* Mark the context as non-reset (it probably is already). */ |
594 | 0 | context->isReset = false; |
595 | 0 | } |
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 |
610 | | MemoryContextUnregisterResetCallback(MemoryContext context, |
611 | | MemoryContextCallback *cb) |
612 | 0 | { |
613 | 0 | MemoryContextCallback *prev, |
614 | 0 | *cur; |
615 | |
|
616 | 0 | Assert(MemoryContextIsValid(context)); |
617 | |
|
618 | 0 | for (prev = NULL, cur = context->reset_cbs; cur != NULL; |
619 | 0 | prev = cur, cur = cur->next) |
620 | 0 | { |
621 | 0 | if (cur != cb) |
622 | 0 | continue; |
623 | 0 | if (prev) |
624 | 0 | prev->next = cur->next; |
625 | 0 | else |
626 | 0 | context->reset_cbs = cur->next; |
627 | 0 | return; |
628 | 0 | } |
629 | 0 | Assert(false); |
630 | 0 | } |
631 | | |
632 | | /* |
633 | | * MemoryContextCallResetCallbacks |
634 | | * Internal function to call all registered callbacks for context. |
635 | | */ |
636 | | static void |
637 | | MemoryContextCallResetCallbacks(MemoryContext context) |
638 | 14.5k | { |
639 | 14.5k | 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 | 14.5k | while ((cb = context->reset_cbs) != NULL) |
647 | 0 | { |
648 | 0 | context->reset_cbs = cb->next; |
649 | 0 | cb->func(cb->arg); |
650 | 0 | } |
651 | 14.5k | } |
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 |
664 | | MemoryContextSetIdentifier(MemoryContext context, const char *id) |
665 | 4 | { |
666 | 4 | Assert(MemoryContextIsValid(context)); |
667 | 4 | context->ident = id; |
668 | 4 | } |
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 |
689 | | MemoryContextSetParent(MemoryContext context, MemoryContext new_parent) |
690 | 2.03k | { |
691 | 2.03k | Assert(MemoryContextIsValid(context)); |
692 | 2.03k | Assert(context != new_parent); |
693 | | |
694 | | /* Fast path if it's got correct parent already */ |
695 | 2.03k | if (new_parent == context->parent) |
696 | 0 | return; |
697 | | |
698 | | /* Delink from existing parent, if any */ |
699 | 2.03k | if (context->parent) |
700 | 2.03k | { |
701 | 2.03k | MemoryContext parent = context->parent; |
702 | | |
703 | 2.03k | if (context->prevchild != NULL) |
704 | 0 | context->prevchild->nextchild = context->nextchild; |
705 | 2.03k | else |
706 | 2.03k | { |
707 | 2.03k | Assert(parent->firstchild == context); |
708 | 2.03k | parent->firstchild = context->nextchild; |
709 | 2.03k | } |
710 | | |
711 | 2.03k | if (context->nextchild != NULL) |
712 | 0 | context->nextchild->prevchild = context->prevchild; |
713 | 2.03k | } |
714 | | |
715 | | /* And relink */ |
716 | 2.03k | if (new_parent) |
717 | 0 | { |
718 | 0 | Assert(MemoryContextIsValid(new_parent)); |
719 | 0 | context->parent = new_parent; |
720 | 0 | context->prevchild = NULL; |
721 | 0 | context->nextchild = new_parent->firstchild; |
722 | 0 | if (new_parent->firstchild != NULL) |
723 | 0 | new_parent->firstchild->prevchild = context; |
724 | 0 | new_parent->firstchild = context; |
725 | 0 | } |
726 | 2.03k | else |
727 | 2.03k | { |
728 | 2.03k | context->parent = NULL; |
729 | 2.03k | context->prevchild = NULL; |
730 | 2.03k | context->nextchild = NULL; |
731 | 2.03k | } |
732 | 2.03k | } |
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 |
746 | | MemoryContextAllowInCriticalSection(MemoryContext context, bool allow) |
747 | 2.03k | { |
748 | 2.03k | Assert(MemoryContextIsValid(context)); |
749 | | |
750 | 2.03k | context->allowInCritSection = allow; |
751 | 2.03k | } |
752 | | |
753 | | /* |
754 | | * GetMemoryChunkContext |
755 | | * Given a currently-allocated chunk, determine the MemoryContext that |
756 | | * the chunk belongs to. |
757 | | */ |
758 | | MemoryContext |
759 | | GetMemoryChunkContext(void *pointer) |
760 | 3.90k | { |
761 | 3.90k | return MCXT_METHOD(pointer, get_chunk_context) (pointer); |
762 | 3.90k | } |
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 |
773 | | GetMemoryChunkSpace(void *pointer) |
774 | 0 | { |
775 | 0 | return MCXT_METHOD(pointer, get_chunk_space) (pointer); |
776 | 0 | } |
777 | | |
778 | | /* |
779 | | * MemoryContextGetParent |
780 | | * Get the parent context (if any) of the specified context |
781 | | */ |
782 | | MemoryContext |
783 | | MemoryContextGetParent(MemoryContext context) |
784 | 0 | { |
785 | 0 | Assert(MemoryContextIsValid(context)); |
786 | |
|
787 | 0 | return context->parent; |
788 | 0 | } |
789 | | |
790 | | /* |
791 | | * MemoryContextIsEmpty |
792 | | * Is a memory context empty of any allocated space? |
793 | | */ |
794 | | bool |
795 | | MemoryContextIsEmpty(MemoryContext context) |
796 | 0 | { |
797 | 0 | 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 | | */ |
803 | 0 | if (context->firstchild != NULL) |
804 | 0 | return false; |
805 | | /* Otherwise use the type-specific inquiry */ |
806 | 0 | return context->methods->is_empty(context); |
807 | 0 | } |
808 | | |
809 | | /* |
810 | | * Find the memory allocated to blocks for this memory context. If recurse is |
811 | | * true, also include children. |
812 | | */ |
813 | | Size |
814 | | MemoryContextMemAllocated(MemoryContext context, bool recurse) |
815 | 0 | { |
816 | 0 | Size total = context->mem_allocated; |
817 | |
|
818 | 0 | Assert(MemoryContextIsValid(context)); |
819 | |
|
820 | 0 | if (recurse) |
821 | 0 | { |
822 | 0 | for (MemoryContext curr = context->firstchild; |
823 | 0 | curr != NULL; |
824 | 0 | curr = MemoryContextTraverseNext(curr, context)) |
825 | 0 | { |
826 | 0 | total += curr->mem_allocated; |
827 | 0 | } |
828 | 0 | } |
829 | |
|
830 | 0 | return total; |
831 | 0 | } |
832 | | |
833 | | /* |
834 | | * Return the memory consumption statistics about the given context and its |
835 | | * children. |
836 | | */ |
837 | | void |
838 | | MemoryContextMemConsumed(MemoryContext context, |
839 | | MemoryContextCounters *consumed) |
840 | 0 | { |
841 | 0 | Assert(MemoryContextIsValid(context)); |
842 | |
|
843 | 0 | memset(consumed, 0, sizeof(*consumed)); |
844 | | |
845 | | /* Examine the context itself */ |
846 | 0 | context->methods->stats(context, NULL, NULL, consumed, false); |
847 | | |
848 | | /* Examine children, using iteration not recursion */ |
849 | 0 | for (MemoryContext curr = context->firstchild; |
850 | 0 | curr != NULL; |
851 | 0 | curr = MemoryContextTraverseNext(curr, context)) |
852 | 0 | { |
853 | 0 | curr->methods->stats(curr, NULL, NULL, consumed, false); |
854 | 0 | } |
855 | 0 | } |
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 |
866 | | MemoryContextStats(MemoryContext context) |
867 | 0 | { |
868 | | /* Hard-wired limits are usually good enough */ |
869 | 0 | MemoryContextStatsDetail(context, 100, 100, true); |
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 |
881 | | MemoryContextStatsDetail(MemoryContext context, |
882 | | int max_level, int max_children, |
883 | | bool print_to_stderr) |
884 | | { |
885 | | MemoryContextCounters grand_totals; |
886 | | |
887 | | memset(&grand_totals, 0, sizeof(grand_totals)); |
888 | | |
889 | | MemoryContextStatsInternal(context, 1, max_level, max_children, |
890 | | &grand_totals, print_to_stderr); |
891 | | |
892 | | if (print_to_stderr) |
893 | | 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 | | 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 | | */ |
910 | | 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 | | } |
918 | | } |
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 | | MemoryContextStatsInternal(MemoryContext context, int level, |
929 | | int max_level, int max_children, |
930 | | MemoryContextCounters *totals, |
931 | | bool print_to_stderr) |
932 | 0 | { |
933 | 0 | MemoryContext child; |
934 | 0 | int ichild; |
935 | |
|
936 | 0 | Assert(MemoryContextIsValid(context)); |
937 | | |
938 | | /* Examine the context itself */ |
939 | 0 | context->methods->stats(context, |
940 | 0 | MemoryContextStatsPrint, |
941 | 0 | &level, |
942 | 0 | 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 | | */ |
952 | 0 | child = context->firstchild; |
953 | 0 | ichild = 0; |
954 | 0 | if (level <= max_level && !stack_is_too_deep()) |
955 | 0 | { |
956 | 0 | for (; child != NULL && ichild < max_children; |
957 | 0 | child = child->nextchild, ichild++) |
958 | 0 | { |
959 | 0 | MemoryContextStatsInternal(child, level + 1, |
960 | 0 | max_level, max_children, |
961 | 0 | totals, |
962 | 0 | print_to_stderr); |
963 | 0 | } |
964 | 0 | } |
965 | |
|
966 | 0 | if (child != NULL) |
967 | 0 | { |
968 | | /* Summarize the rest of the children, avoiding recursion. */ |
969 | 0 | MemoryContextCounters local_totals; |
970 | |
|
971 | 0 | memset(&local_totals, 0, sizeof(local_totals)); |
972 | |
|
973 | 0 | ichild = 0; |
974 | 0 | while (child != NULL) |
975 | 0 | { |
976 | 0 | child->methods->stats(child, NULL, NULL, &local_totals, false); |
977 | 0 | ichild++; |
978 | 0 | child = MemoryContextTraverseNext(child, context); |
979 | 0 | } |
980 | |
|
981 | 0 | if (print_to_stderr) |
982 | 0 | { |
983 | 0 | for (int i = 0; i < level; i++) |
984 | 0 | fprintf(stderr, " "); |
985 | 0 | fprintf(stderr, |
986 | 0 | "%d more child contexts containing %zu total in %zu blocks; %zu free (%zu chunks); %zu used\n", |
987 | 0 | ichild, |
988 | 0 | local_totals.totalspace, |
989 | 0 | local_totals.nblocks, |
990 | 0 | local_totals.freespace, |
991 | 0 | local_totals.freechunks, |
992 | 0 | local_totals.totalspace - local_totals.freespace); |
993 | 0 | } |
994 | 0 | else |
995 | 0 | ereport(LOG_SERVER_ONLY, |
996 | 0 | (errhidestmt(true), |
997 | 0 | errhidecontext(true), |
998 | 0 | errmsg_internal("level: %d; %d more child contexts containing %zu total in %zu blocks; %zu free (%zu chunks); %zu used", |
999 | 0 | level, |
1000 | 0 | ichild, |
1001 | 0 | local_totals.totalspace, |
1002 | 0 | local_totals.nblocks, |
1003 | 0 | local_totals.freespace, |
1004 | 0 | local_totals.freechunks, |
1005 | 0 | local_totals.totalspace - local_totals.freespace))); |
1006 | | |
1007 | 0 | if (totals) |
1008 | 0 | { |
1009 | 0 | totals->nblocks += local_totals.nblocks; |
1010 | 0 | totals->freechunks += local_totals.freechunks; |
1011 | 0 | totals->totalspace += local_totals.totalspace; |
1012 | 0 | totals->freespace += local_totals.freespace; |
1013 | 0 | } |
1014 | 0 | } |
1015 | 0 | } |
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 |
1025 | | MemoryContextStatsPrint(MemoryContext context, void *passthru, |
1026 | | const char *stats_string, |
1027 | | bool print_to_stderr) |
1028 | | { |
1029 | | int level = *(int *) passthru; |
1030 | | const char *name = context->name; |
1031 | | 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 | | if (ident && strcmp(name, "dynahash") == 0) |
1041 | | { |
1042 | | name = ident; |
1043 | | ident = NULL; |
1044 | | } |
1045 | | |
1046 | | truncated_ident[0] = '\0'; |
1047 | | |
1048 | | 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 | | int idlen = strlen(ident); |
1057 | | bool truncated = false; |
1058 | | |
1059 | | strcpy(truncated_ident, ": "); |
1060 | | i = strlen(truncated_ident); |
1061 | | |
1062 | | if (idlen > 100) |
1063 | | { |
1064 | | idlen = pg_mbcliplen(ident, idlen, 100); |
1065 | | truncated = true; |
1066 | | } |
1067 | | |
1068 | | while (idlen-- > 0) |
1069 | | { |
1070 | | unsigned char c = *ident++; |
1071 | | |
1072 | | if (c < ' ') |
1073 | | c = ' '; |
1074 | | truncated_ident[i++] = c; |
1075 | | } |
1076 | | truncated_ident[i] = '\0'; |
1077 | | |
1078 | | if (truncated) |
1079 | | strcat(truncated_ident, "..."); |
1080 | | } |
1081 | | |
1082 | | if (print_to_stderr) |
1083 | | { |
1084 | | for (i = 1; i < level; i++) |
1085 | | fprintf(stderr, " "); |
1086 | | fprintf(stderr, "%s: %s%s\n", name, stats_string, truncated_ident); |
1087 | | } |
1088 | | else |
1089 | | 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))); |
1094 | | } |
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 |
1104 | | MemoryContextCheck(MemoryContext context) |
1105 | | { |
1106 | | Assert(MemoryContextIsValid(context)); |
1107 | | context->methods->check(context); |
1108 | | |
1109 | | for (MemoryContext curr = context->firstchild; |
1110 | | curr != NULL; |
1111 | | curr = MemoryContextTraverseNext(curr, context)) |
1112 | | { |
1113 | | Assert(MemoryContextIsValid(curr)); |
1114 | | curr->methods->check(curr); |
1115 | | } |
1116 | | } |
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 |
1152 | | MemoryContextCreate(MemoryContext node, |
1153 | | NodeTag tag, |
1154 | | MemoryContextMethodID method_id, |
1155 | | MemoryContext parent, |
1156 | | const char *name) |
1157 | 4.08k | { |
1158 | | /* Creating new memory contexts is not allowed in a critical section */ |
1159 | 4.08k | Assert(CritSectionCount == 0); |
1160 | | |
1161 | | /* Validate parent, to help prevent crazy context linkages */ |
1162 | 4.08k | Assert(parent == NULL || MemoryContextIsValid(parent)); |
1163 | 4.08k | Assert(node != parent); |
1164 | | |
1165 | | /* Initialize all standard fields of memory context header */ |
1166 | 4.08k | node->type = tag; |
1167 | 4.08k | node->isReset = true; |
1168 | 4.08k | node->methods = &mcxt_methods[method_id]; |
1169 | 4.08k | node->parent = parent; |
1170 | 4.08k | node->firstchild = NULL; |
1171 | 4.08k | node->mem_allocated = 0; |
1172 | 4.08k | node->prevchild = NULL; |
1173 | 4.08k | node->name = name; |
1174 | 4.08k | node->ident = NULL; |
1175 | 4.08k | node->reset_cbs = NULL; |
1176 | | |
1177 | | /* OK to link node into context tree */ |
1178 | 4.08k | if (parent) |
1179 | 2.04k | { |
1180 | 2.04k | node->nextchild = parent->firstchild; |
1181 | 2.04k | if (parent->firstchild != NULL) |
1182 | 6 | parent->firstchild->prevchild = node; |
1183 | 2.04k | parent->firstchild = node; |
1184 | | /* inherit allowInCritSection flag from parent */ |
1185 | 2.04k | node->allowInCritSection = parent->allowInCritSection; |
1186 | 2.04k | } |
1187 | 2.03k | else |
1188 | 2.03k | { |
1189 | 2.03k | node->nextchild = NULL; |
1190 | 2.03k | node->allowInCritSection = false; |
1191 | 2.03k | } |
1192 | 4.08k | } |
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 * |
1201 | | MemoryContextAllocationFailure(MemoryContext context, Size size, int flags) |
1202 | 0 | { |
1203 | 0 | if ((flags & MCXT_ALLOC_NO_OOM) == 0) |
1204 | 0 | { |
1205 | 0 | if (TopMemoryContext) |
1206 | 0 | MemoryContextStats(TopMemoryContext); |
1207 | 0 | ereport(ERROR, |
1208 | 0 | (errcode(ERRCODE_OUT_OF_MEMORY), |
1209 | 0 | errmsg("out of memory"), |
1210 | 0 | errdetail("Failed on request of size %zu in memory context \"%s\".", |
1211 | 0 | size, context->name))); |
1212 | 0 | } |
1213 | 0 | return NULL; |
1214 | 0 | } |
1215 | | |
1216 | | /* |
1217 | | * MemoryContextSizeFailure |
1218 | | * For use by MemoryContextMethods implementations to handle invalid |
1219 | | * memory allocation request sizes. |
1220 | | */ |
1221 | | void |
1222 | | MemoryContextSizeFailure(MemoryContext context, Size size, int flags) |
1223 | 0 | { |
1224 | 0 | elog(ERROR, "invalid memory alloc request size %zu", size); |
1225 | 0 | } |
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 * |
1235 | | MemoryContextAlloc(MemoryContext context, Size size) |
1236 | 36.0k | { |
1237 | 36.0k | void *ret; |
1238 | | |
1239 | 36.0k | Assert(MemoryContextIsValid(context)); |
1240 | 36.0k | AssertNotInCriticalSection(context); |
1241 | | |
1242 | 36.0k | 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 | | */ |
1254 | 36.0k | ret = context->methods->alloc(context, size, 0); |
1255 | | |
1256 | 36.0k | VALGRIND_MEMPOOL_ALLOC(context, ret, size); |
1257 | | |
1258 | 36.0k | return ret; |
1259 | 36.0k | } |
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 * |
1269 | | MemoryContextAllocZero(MemoryContext context, Size size) |
1270 | 0 | { |
1271 | 0 | void *ret; |
1272 | |
|
1273 | 0 | Assert(MemoryContextIsValid(context)); |
1274 | 0 | AssertNotInCriticalSection(context); |
1275 | |
|
1276 | 0 | context->isReset = false; |
1277 | |
|
1278 | 0 | ret = context->methods->alloc(context, size, 0); |
1279 | |
|
1280 | 0 | VALGRIND_MEMPOOL_ALLOC(context, ret, size); |
1281 | |
|
1282 | 0 | MemSetAligned(ret, 0, size); |
1283 | |
|
1284 | 0 | return ret; |
1285 | 0 | } |
1286 | | |
1287 | | /* |
1288 | | * MemoryContextAllocExtended |
1289 | | * Allocate space within the specified context using the given flags. |
1290 | | */ |
1291 | | void * |
1292 | | MemoryContextAllocExtended(MemoryContext context, Size size, int flags) |
1293 | 226 | { |
1294 | 226 | void *ret; |
1295 | | |
1296 | 226 | Assert(MemoryContextIsValid(context)); |
1297 | 226 | AssertNotInCriticalSection(context); |
1298 | | |
1299 | 226 | if (!((flags & MCXT_ALLOC_HUGE) != 0 ? AllocHugeSizeIsValid(size) : |
1300 | 226 | AllocSizeIsValid(size))) |
1301 | 226 | elog(ERROR, "invalid memory alloc request size %zu", size); |
1302 | | |
1303 | 226 | context->isReset = false; |
1304 | | |
1305 | 226 | ret = context->methods->alloc(context, size, flags); |
1306 | 226 | if (unlikely(ret == NULL)) |
1307 | 0 | return NULL; |
1308 | | |
1309 | 226 | VALGRIND_MEMPOOL_ALLOC(context, ret, size); |
1310 | | |
1311 | 226 | if ((flags & MCXT_ALLOC_ZERO) != 0) |
1312 | 0 | MemSetAligned(ret, 0, size); |
1313 | | |
1314 | 226 | return ret; |
1315 | 226 | } |
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 |
1326 | | HandleLogMemoryContextInterrupt(void) |
1327 | 0 | { |
1328 | 0 | InterruptPending = true; |
1329 | 0 | LogMemoryContextPending = true; |
1330 | | /* latch will be set by procsignal_sigusr1_handler */ |
1331 | 0 | } |
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 | | ProcessLogMemoryContextInterrupt(void) |
1344 | 0 | { |
1345 | 0 | 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 | | */ |
1353 | 0 | if (LogMemoryContextInProgress) |
1354 | 0 | return; |
1355 | 0 | LogMemoryContextInProgress = true; |
1356 | |
|
1357 | 0 | PG_TRY(); |
1358 | 0 | { |
1359 | | /* |
1360 | | * Use LOG_SERVER_ONLY to prevent this message from being sent to the |
1361 | | * connected client. |
1362 | | */ |
1363 | 0 | ereport(LOG_SERVER_ONLY, |
1364 | 0 | (errhidestmt(true), |
1365 | 0 | errhidecontext(true), |
1366 | 0 | 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 | 0 | MemoryContextStatsDetail(TopMemoryContext, 100, 100, false); |
1381 | 0 | } |
1382 | 0 | PG_FINALLY(); |
1383 | 0 | { |
1384 | 0 | LogMemoryContextInProgress = false; |
1385 | 0 | } |
1386 | 0 | PG_END_TRY(); |
1387 | 0 | } |
1388 | | |
1389 | | void * |
1390 | | palloc(Size size) |
1391 | 6.37M | { |
1392 | | /* duplicates MemoryContextAlloc to avoid increased overhead */ |
1393 | 6.37M | void *ret; |
1394 | 6.37M | MemoryContext context = CurrentMemoryContext; |
1395 | | |
1396 | 6.37M | Assert(MemoryContextIsValid(context)); |
1397 | 6.37M | AssertNotInCriticalSection(context); |
1398 | | |
1399 | 6.37M | 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 | | */ |
1411 | 6.37M | ret = context->methods->alloc(context, size, 0); |
1412 | | /* We expect OOM to be handled by the alloc function */ |
1413 | 6.37M | Assert(ret != NULL); |
1414 | 6.37M | VALGRIND_MEMPOOL_ALLOC(context, ret, size); |
1415 | | |
1416 | 6.37M | return ret; |
1417 | 6.37M | } |
1418 | | |
1419 | | void * |
1420 | | palloc0(Size size) |
1421 | 5.89M | { |
1422 | | /* duplicates MemoryContextAllocZero to avoid increased overhead */ |
1423 | 5.89M | void *ret; |
1424 | 5.89M | MemoryContext context = CurrentMemoryContext; |
1425 | | |
1426 | 5.89M | Assert(MemoryContextIsValid(context)); |
1427 | 5.89M | AssertNotInCriticalSection(context); |
1428 | | |
1429 | 5.89M | context->isReset = false; |
1430 | | |
1431 | 5.89M | ret = context->methods->alloc(context, size, 0); |
1432 | | /* We expect OOM to be handled by the alloc function */ |
1433 | 5.89M | Assert(ret != NULL); |
1434 | 5.89M | VALGRIND_MEMPOOL_ALLOC(context, ret, size); |
1435 | | |
1436 | 5.89M | MemSetAligned(ret, 0, size); |
1437 | | |
1438 | 5.89M | return ret; |
1439 | 5.89M | } |
1440 | | |
1441 | | void * |
1442 | | palloc_extended(Size size, int flags) |
1443 | 4 | { |
1444 | | /* duplicates MemoryContextAllocExtended to avoid increased overhead */ |
1445 | 4 | void *ret; |
1446 | 4 | MemoryContext context = CurrentMemoryContext; |
1447 | | |
1448 | 4 | Assert(MemoryContextIsValid(context)); |
1449 | 4 | AssertNotInCriticalSection(context); |
1450 | | |
1451 | 4 | context->isReset = false; |
1452 | | |
1453 | 4 | ret = context->methods->alloc(context, size, flags); |
1454 | 4 | if (unlikely(ret == NULL)) |
1455 | 0 | { |
1456 | | /* NULL can be returned only when using MCXT_ALLOC_NO_OOM */ |
1457 | 0 | Assert(flags & MCXT_ALLOC_NO_OOM); |
1458 | 0 | return NULL; |
1459 | 0 | } |
1460 | | |
1461 | 4 | VALGRIND_MEMPOOL_ALLOC(context, ret, size); |
1462 | | |
1463 | 4 | if ((flags & MCXT_ALLOC_ZERO) != 0) |
1464 | 0 | MemSetAligned(ret, 0, size); |
1465 | | |
1466 | 4 | return ret; |
1467 | 4 | } |
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 * |
1485 | | MemoryContextAllocAligned(MemoryContext context, |
1486 | | Size size, Size alignto, int flags) |
1487 | 0 | { |
1488 | 0 | MemoryChunk *alignedchunk; |
1489 | 0 | Size alloc_size; |
1490 | 0 | void *unaligned; |
1491 | 0 | 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 | 0 | Assert(alignto < (128 * 1024 * 1024)); |
1501 | | |
1502 | | /* ensure alignto is a power of 2 */ |
1503 | 0 | 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 | 0 | if (unlikely(alignto <= MAXIMUM_ALIGNOF)) |
1510 | 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 | | */ |
1529 | 0 | alloc_size = size + PallocAlignedExtraBytes(alignto); |
1530 | |
|
1531 | | #ifdef MEMORY_CONTEXT_CHECKING |
1532 | | /* ensure there's space for a sentinel byte */ |
1533 | | 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 | | */ |
1541 | 0 | unaligned = MemoryContextAllocExtended(context, alloc_size, |
1542 | 0 | flags & ~MCXT_ALLOC_ZERO); |
1543 | |
|
1544 | 0 | if (unlikely(unaligned == NULL)) |
1545 | 0 | { |
1546 | | /* NULL can be returned only when using MCXT_ALLOC_NO_OOM */ |
1547 | 0 | Assert(flags & MCXT_ALLOC_NO_OOM); |
1548 | 0 | return NULL; |
1549 | 0 | } |
1550 | | |
1551 | | /* compute the aligned pointer */ |
1552 | 0 | aligned = (void *) TYPEALIGN(alignto, (char *) unaligned + |
1553 | 0 | sizeof(MemoryChunk)); |
1554 | |
|
1555 | 0 | alignedchunk = PointerGetMemoryChunk(aligned); |
1556 | | |
1557 | | /* |
1558 | | * We set the redirect MemoryChunk so that the block offset calculation is |
1559 | | * used to point back to the 'unaligned' allocated chunk. This allows us |
1560 | | * to use MemoryChunkGetBlock() to find the unaligned chunk when we need |
1561 | | * to perform operations such as pfree() and repalloc(). |
1562 | | * |
1563 | | * We store 'alignto' in the MemoryChunk's 'value' so that we know what |
1564 | | * the alignment was set to should we ever be asked to realloc this |
1565 | | * pointer. |
1566 | | */ |
1567 | 0 | MemoryChunkSetHdrMask(alignedchunk, unaligned, alignto, |
1568 | 0 | MCTX_ALIGNED_REDIRECT_ID); |
1569 | | |
1570 | | /* double check we produced a correctly aligned pointer */ |
1571 | 0 | Assert((void *) TYPEALIGN(alignto, aligned) == aligned); |
1572 | |
|
1573 | | #ifdef MEMORY_CONTEXT_CHECKING |
1574 | | alignedchunk->requested_size = size; |
1575 | | /* set mark to catch clobber of "unused" space */ |
1576 | | set_sentinel(aligned, size); |
1577 | | #endif |
1578 | | |
1579 | | /* |
1580 | | * MemoryContextAllocExtended marked the whole unaligned chunk as a |
1581 | | * vchunk. Undo that, instead making just the aligned chunk be a vchunk. |
1582 | | * This prevents Valgrind from complaining that the vchunk is possibly |
1583 | | * leaked, since only pointers to the aligned chunk will exist. |
1584 | | * |
1585 | | * After these calls, the aligned chunk will be marked UNDEFINED, and all |
1586 | | * the rest of the unaligned chunk (the redirection chunk header, the |
1587 | | * padding bytes before it, and any wasted trailing bytes) will be marked |
1588 | | * NOACCESS, which is what we want. |
1589 | | */ |
1590 | 0 | VALGRIND_MEMPOOL_FREE(context, unaligned); |
1591 | 0 | VALGRIND_MEMPOOL_ALLOC(context, aligned, size); |
1592 | | |
1593 | | /* Now zero (and make DEFINED) just the aligned chunk, if requested */ |
1594 | 0 | if ((flags & MCXT_ALLOC_ZERO) != 0) |
1595 | 0 | MemSetAligned(aligned, 0, size); |
1596 | |
|
1597 | 0 | return aligned; |
1598 | 0 | } |
1599 | | |
1600 | | /* |
1601 | | * palloc_aligned |
1602 | | * Allocate 'size' bytes returning a pointer that's aligned to the |
1603 | | * 'alignto' boundary. |
1604 | | * |
1605 | | * Currently, we align addresses by requesting additional bytes from the |
1606 | | * MemoryContext's standard allocator function and then aligning the returned |
1607 | | * address by the required alignment. This means that the given MemoryContext |
1608 | | * must support providing us with a chunk of memory that's larger than 'size'. |
1609 | | * For allocators such as Slab, that's not going to work, as slab only allows |
1610 | | * chunks of the size that's specified when the context is created. |
1611 | | * |
1612 | | * 'alignto' must be a power of 2. |
1613 | | * 'flags' may be 0 or set the same as MemoryContextAllocExtended(). |
1614 | | */ |
1615 | | void * |
1616 | | palloc_aligned(Size size, Size alignto, int flags) |
1617 | 0 | { |
1618 | 0 | return MemoryContextAllocAligned(CurrentMemoryContext, size, alignto, flags); |
1619 | 0 | } |
1620 | | |
1621 | | /* |
1622 | | * pfree |
1623 | | * Release an allocated chunk. |
1624 | | */ |
1625 | | void |
1626 | | pfree(void *pointer) |
1627 | 583k | { |
1628 | | #ifdef USE_VALGRIND |
1629 | | MemoryContext context = GetMemoryChunkContext(pointer); |
1630 | | #endif |
1631 | | |
1632 | 583k | MCXT_METHOD(pointer, free_p) (pointer); |
1633 | | |
1634 | 583k | VALGRIND_MEMPOOL_FREE(context, pointer); |
1635 | 583k | } |
1636 | | |
1637 | | /* |
1638 | | * repalloc |
1639 | | * Adjust the size of a previously allocated chunk. |
1640 | | */ |
1641 | | void * |
1642 | | repalloc(void *pointer, Size size) |
1643 | 10.8k | { |
1644 | | #if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND) |
1645 | | MemoryContext context = GetMemoryChunkContext(pointer); |
1646 | | #endif |
1647 | 10.8k | void *ret; |
1648 | | |
1649 | 10.8k | AssertNotInCriticalSection(context); |
1650 | | |
1651 | | /* isReset must be false already */ |
1652 | 10.8k | Assert(!context->isReset); |
1653 | | |
1654 | | /* |
1655 | | * For efficiency reasons, we purposefully offload the handling of |
1656 | | * allocation failures to the MemoryContextMethods implementation as this |
1657 | | * allows these checks to be performed only when an actual malloc needs to |
1658 | | * be done to request more memory from the OS. Additionally, not having |
1659 | | * to execute any instructions after this call allows the compiler to use |
1660 | | * the sibling call optimization. If you're considering adding code after |
1661 | | * this call, consider making it the responsibility of the 'realloc' |
1662 | | * function instead. |
1663 | | */ |
1664 | 10.8k | ret = MCXT_METHOD(pointer, realloc) (pointer, size, 0); |
1665 | | |
1666 | 10.8k | VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size); |
1667 | | |
1668 | 10.8k | return ret; |
1669 | 10.8k | } |
1670 | | |
1671 | | /* |
1672 | | * repalloc_extended |
1673 | | * Adjust the size of a previously allocated chunk, |
1674 | | * with HUGE and NO_OOM options. |
1675 | | */ |
1676 | | void * |
1677 | | repalloc_extended(void *pointer, Size size, int flags) |
1678 | 0 | { |
1679 | | #if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND) |
1680 | | MemoryContext context = GetMemoryChunkContext(pointer); |
1681 | | #endif |
1682 | 0 | void *ret; |
1683 | |
|
1684 | 0 | AssertNotInCriticalSection(context); |
1685 | | |
1686 | | /* isReset must be false already */ |
1687 | 0 | Assert(!context->isReset); |
1688 | | |
1689 | | /* |
1690 | | * For efficiency reasons, we purposefully offload the handling of |
1691 | | * allocation failures to the MemoryContextMethods implementation as this |
1692 | | * allows these checks to be performed only when an actual malloc needs to |
1693 | | * be done to request more memory from the OS. Additionally, not having |
1694 | | * to execute any instructions after this call allows the compiler to use |
1695 | | * the sibling call optimization. If you're considering adding code after |
1696 | | * this call, consider making it the responsibility of the 'realloc' |
1697 | | * function instead. |
1698 | | */ |
1699 | 0 | ret = MCXT_METHOD(pointer, realloc) (pointer, size, flags); |
1700 | 0 | if (unlikely(ret == NULL)) |
1701 | 0 | return NULL; |
1702 | | |
1703 | 0 | VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size); |
1704 | |
|
1705 | 0 | return ret; |
1706 | 0 | } |
1707 | | |
1708 | | /* |
1709 | | * repalloc0 |
1710 | | * Adjust the size of a previously allocated chunk and zero out the added |
1711 | | * space. |
1712 | | */ |
1713 | | void * |
1714 | | repalloc0(void *pointer, Size oldsize, Size size) |
1715 | 0 | { |
1716 | 0 | void *ret; |
1717 | | |
1718 | | /* catch wrong argument order */ |
1719 | 0 | if (unlikely(oldsize > size)) |
1720 | 0 | elog(ERROR, "invalid repalloc0 call: oldsize %zu, new size %zu", |
1721 | 0 | oldsize, size); |
1722 | | |
1723 | 0 | ret = repalloc(pointer, size); |
1724 | 0 | memset((char *) ret + oldsize, 0, (size - oldsize)); |
1725 | 0 | return ret; |
1726 | 0 | } |
1727 | | |
1728 | | /* |
1729 | | * Support for safe calculation of memory request sizes |
1730 | | * |
1731 | | * These functions perform the requested calculation, but throw error if the |
1732 | | * result overflows. |
1733 | | * |
1734 | | * An important property of these functions is that if an argument was a |
1735 | | * negative signed int before promotion (implying overflow in calculating it) |
1736 | | * we will detect that as an error. That happens because we reject results |
1737 | | * larger than SIZE_MAX / 2 later on, in the actual allocation step. |
1738 | | */ |
1739 | | Size |
1740 | | add_size(Size s1, Size s2) |
1741 | 0 | { |
1742 | 0 | Size result; |
1743 | |
|
1744 | 0 | if (unlikely(pg_add_size_overflow(s1, s2, &result))) |
1745 | 0 | add_size_error(s1, s2); |
1746 | 0 | return result; |
1747 | 0 | } |
1748 | | |
1749 | | pg_noreturn static pg_noinline void |
1750 | | add_size_error(Size s1, Size s2) |
1751 | 0 | { |
1752 | 0 | ereport(ERROR, |
1753 | 0 | (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), |
1754 | 0 | errmsg("invalid memory allocation request size %zu + %zu", |
1755 | 0 | s1, s2))); |
1756 | 0 | } |
1757 | | |
1758 | | Size |
1759 | | mul_size(Size s1, Size s2) |
1760 | 0 | { |
1761 | 0 | Size result; |
1762 | |
|
1763 | 0 | if (unlikely(pg_mul_size_overflow(s1, s2, &result))) |
1764 | 0 | mul_size_error(s1, s2); |
1765 | 0 | return result; |
1766 | 0 | } |
1767 | | |
1768 | | pg_noreturn static pg_noinline void |
1769 | | mul_size_error(Size s1, Size s2) |
1770 | 0 | { |
1771 | 0 | ereport(ERROR, |
1772 | 0 | (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), |
1773 | 0 | errmsg("invalid memory allocation request size %zu * %zu", |
1774 | 0 | s1, s2))); |
1775 | 0 | } |
1776 | | |
1777 | | /* |
1778 | | * palloc_mul |
1779 | | * Equivalent to palloc(mul_size(s1, s2)). |
1780 | | */ |
1781 | | void * |
1782 | | palloc_mul(Size s1, Size s2) |
1783 | 0 | { |
1784 | | /* inline mul_size() for efficiency */ |
1785 | 0 | Size req; |
1786 | |
|
1787 | 0 | if (unlikely(pg_mul_size_overflow(s1, s2, &req))) |
1788 | 0 | mul_size_error(s1, s2); |
1789 | 0 | return palloc(req); |
1790 | 0 | } |
1791 | | |
1792 | | /* |
1793 | | * palloc0_mul |
1794 | | * Equivalent to palloc0(mul_size(s1, s2)). |
1795 | | * |
1796 | | * This is comparable to standard calloc's behavior. |
1797 | | */ |
1798 | | void * |
1799 | | palloc0_mul(Size s1, Size s2) |
1800 | 0 | { |
1801 | | /* inline mul_size() for efficiency */ |
1802 | 0 | Size req; |
1803 | |
|
1804 | 0 | if (unlikely(pg_mul_size_overflow(s1, s2, &req))) |
1805 | 0 | mul_size_error(s1, s2); |
1806 | 0 | return palloc0(req); |
1807 | 0 | } |
1808 | | |
1809 | | /* |
1810 | | * palloc_mul_extended |
1811 | | * Equivalent to palloc_extended(mul_size(s1, s2), flags). |
1812 | | */ |
1813 | | void * |
1814 | | palloc_mul_extended(Size s1, Size s2, int flags) |
1815 | 0 | { |
1816 | | /* inline mul_size() for efficiency */ |
1817 | 0 | Size req; |
1818 | |
|
1819 | 0 | if (unlikely(pg_mul_size_overflow(s1, s2, &req))) |
1820 | 0 | mul_size_error(s1, s2); |
1821 | 0 | return palloc_extended(req, flags); |
1822 | 0 | } |
1823 | | |
1824 | | /* |
1825 | | * repalloc_mul |
1826 | | * Equivalent to repalloc(p, mul_size(s1, s2)). |
1827 | | */ |
1828 | | void * |
1829 | | repalloc_mul(void *p, Size s1, Size s2) |
1830 | 6.43k | { |
1831 | | /* inline mul_size() for efficiency */ |
1832 | 6.43k | Size req; |
1833 | | |
1834 | 6.43k | if (unlikely(pg_mul_size_overflow(s1, s2, &req))) |
1835 | 0 | mul_size_error(s1, s2); |
1836 | 6.43k | return repalloc(p, req); |
1837 | 6.43k | } |
1838 | | |
1839 | | /* |
1840 | | * repalloc_mul_extended |
1841 | | * Equivalent to repalloc_extended(p, mul_size(s1, s2), flags). |
1842 | | */ |
1843 | | void * |
1844 | | repalloc_mul_extended(void *p, Size s1, Size s2, int flags) |
1845 | 0 | { |
1846 | | /* inline mul_size() for efficiency */ |
1847 | 0 | Size req; |
1848 | |
|
1849 | 0 | if (unlikely(pg_mul_size_overflow(s1, s2, &req))) |
1850 | 0 | mul_size_error(s1, s2); |
1851 | 0 | return repalloc_extended(p, req, flags); |
1852 | 0 | } |
1853 | | |
1854 | | /* |
1855 | | * MemoryContextAllocHuge |
1856 | | * Allocate (possibly-expansive) space within the specified context. |
1857 | | * |
1858 | | * See considerations in comment at MaxAllocHugeSize. |
1859 | | */ |
1860 | | void * |
1861 | | MemoryContextAllocHuge(MemoryContext context, Size size) |
1862 | 0 | { |
1863 | 0 | void *ret; |
1864 | |
|
1865 | 0 | Assert(MemoryContextIsValid(context)); |
1866 | 0 | AssertNotInCriticalSection(context); |
1867 | |
|
1868 | 0 | context->isReset = false; |
1869 | | |
1870 | | /* |
1871 | | * For efficiency reasons, we purposefully offload the handling of |
1872 | | * allocation failures to the MemoryContextMethods implementation as this |
1873 | | * allows these checks to be performed only when an actual malloc needs to |
1874 | | * be done to request more memory from the OS. Additionally, not having |
1875 | | * to execute any instructions after this call allows the compiler to use |
1876 | | * the sibling call optimization. If you're considering adding code after |
1877 | | * this call, consider making it the responsibility of the 'alloc' |
1878 | | * function instead. |
1879 | | */ |
1880 | 0 | ret = context->methods->alloc(context, size, MCXT_ALLOC_HUGE); |
1881 | |
|
1882 | 0 | VALGRIND_MEMPOOL_ALLOC(context, ret, size); |
1883 | |
|
1884 | 0 | return ret; |
1885 | 0 | } |
1886 | | |
1887 | | /* |
1888 | | * repalloc_huge |
1889 | | * Adjust the size of a previously allocated chunk, permitting a large |
1890 | | * value. The previous allocation need not have been "huge". |
1891 | | */ |
1892 | | void * |
1893 | | repalloc_huge(void *pointer, Size size) |
1894 | 0 | { |
1895 | | /* this one seems not worth its own implementation */ |
1896 | 0 | return repalloc_extended(pointer, size, MCXT_ALLOC_HUGE); |
1897 | 0 | } |
1898 | | |
1899 | | /* |
1900 | | * MemoryContextStrdup |
1901 | | * Like strdup(), but allocate from the specified context |
1902 | | */ |
1903 | | char * |
1904 | | MemoryContextStrdup(MemoryContext context, const char *string) |
1905 | 32.1k | { |
1906 | 32.1k | char *nstr; |
1907 | 32.1k | Size len = strlen(string) + 1; |
1908 | | |
1909 | 32.1k | nstr = (char *) MemoryContextAlloc(context, len); |
1910 | | |
1911 | 32.1k | memcpy(nstr, string, len); |
1912 | | |
1913 | 32.1k | return nstr; |
1914 | 32.1k | } |
1915 | | |
1916 | | char * |
1917 | | pstrdup(const char *in) |
1918 | 32.1k | { |
1919 | 32.1k | return MemoryContextStrdup(CurrentMemoryContext, in); |
1920 | 32.1k | } |
1921 | | |
1922 | | /* |
1923 | | * pnstrdup |
1924 | | * Like pstrdup(), but append null byte to a |
1925 | | * not-necessarily-null-terminated input string. |
1926 | | */ |
1927 | | char * |
1928 | | pnstrdup(const char *in, Size len) |
1929 | 0 | { |
1930 | 0 | char *out; |
1931 | |
|
1932 | 0 | len = strnlen(in, len); |
1933 | |
|
1934 | 0 | out = palloc(len + 1); |
1935 | 0 | memcpy(out, in, len); |
1936 | 0 | out[len] = '\0'; |
1937 | |
|
1938 | 0 | return out; |
1939 | 0 | } |
1940 | | |
1941 | | /* |
1942 | | * Make copy of string with all trailing newline characters removed. |
1943 | | */ |
1944 | | char * |
1945 | | pchomp(const char *in) |
1946 | 0 | { |
1947 | 0 | size_t n; |
1948 | |
|
1949 | 0 | n = strlen(in); |
1950 | 0 | while (n > 0 && in[n - 1] == '\n') |
1951 | 0 | n--; |
1952 | 0 | return pnstrdup(in, n); |
1953 | 0 | } |