From 227251b3e8822c77f43cb13724a34d160d9eec74 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Thu, 26 Feb 2026 15:24:03 -0500 Subject: [PATCH v4 3/5] MemCTX: Add minimal system context type This context just defers allocations to the system malloc. This makes individual allocations more expensive to do, but the overhead of maintaining the allocations over long periods of time is considered to be lower. Co-authored-by: Matthias van de Meent Co-authored-by: Andres Freund --- src/backend/nodes/gen_node_support.pl | 2 +- src/backend/utils/adt/mcxtfuncs.c | 3 + src/backend/utils/mmgr/Makefile | 1 + src/backend/utils/mmgr/README | 14 +- src/backend/utils/mmgr/mcxt.c | 14 +- src/backend/utils/mmgr/meson.build | 1 + src/backend/utils/mmgr/systemcxt.c | 521 ++++++++++++++++++++++++++ src/include/nodes/memnodes.h | 3 +- src/include/utils/memutils.h | 4 + src/include/utils/memutils_internal.h | 18 +- src/tools/pgindent/typedefs.list | 2 + 11 files changed, 577 insertions(+), 6 deletions(-) create mode 100644 src/backend/utils/mmgr/systemcxt.c diff --git a/src/backend/nodes/gen_node_support.pl b/src/backend/nodes/gen_node_support.pl index 0b766272018..6432a908731 100644 --- a/src/backend/nodes/gen_node_support.pl +++ b/src/backend/nodes/gen_node_support.pl @@ -136,7 +136,7 @@ my @abstract_types = qw(Node); # they otherwise don't participate in node support. my @extra_tags = qw( IntList OidList XidList - AllocSetContext GenerationContext SlabContext BumpContext + AllocSetContext GenerationContext SlabContext BumpContext SystemContext TIDBitmap WindowObjectData ); diff --git a/src/backend/utils/adt/mcxtfuncs.c b/src/backend/utils/adt/mcxtfuncs.c index 1a4dbbeb8db..ffc26fbdcd0 100644 --- a/src/backend/utils/adt/mcxtfuncs.c +++ b/src/backend/utils/adt/mcxtfuncs.c @@ -160,6 +160,9 @@ PutMemoryContextsStatsTupleStore(Tuplestorestate *tupstore, case T_BumpContext: type = "Bump"; break; + case T_SystemContext: + type = "SystemContext"; + break; default: type = "???"; break; diff --git a/src/backend/utils/mmgr/Makefile b/src/backend/utils/mmgr/Makefile index 01a1fb85270..8d04b1ae041 100644 --- a/src/backend/utils/mmgr/Makefile +++ b/src/backend/utils/mmgr/Makefile @@ -23,5 +23,6 @@ OBJS = \ memdebug.o \ portalmem.o \ slab.o + systemcxt.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/utils/mmgr/README b/src/backend/utils/mmgr/README index 695088bb66d..1ec4f54074d 100644 --- a/src/backend/utils/mmgr/README +++ b/src/backend/utils/mmgr/README @@ -471,8 +471,8 @@ thrashing. Alternative Memory Context Implementations ------------------------------------------ -aset.c (AllocSetContext) is our default general-purpose allocator. Three other -allocator types also exist which are special-purpose: +aset.c (AllocSetContext) is our default general-purpose allocator. Several +other allocator types also exist which are special-purpose: * slab.c (SlabContext) is designed for allocations of fixed-sized chunks. The fixed chunk size must be specified when creating the context. @@ -495,6 +495,16 @@ allocator types also exist which are special-purpose: allocations. Blocks are only free'd back to the operating system when the context is reset or deleted. +* systemctx.c (SystemContext) is best suited for those use cases that require + long-lived allocations, but have minimal allocation traffic that doesn't + require the lowest latencies, and generally are expected to hold only few + allocations. Allocations get a small header, but are otherwise forwarded + directly the system allocator; similarly, pfree() is forwarded directly to + the system allocator as well. + The most suitable use cases are for contexts that require very few and + long-lived allocations. The context header is also small, so this can be + suitable when a large number of contexts are required. + For further details, please read the header comment in the corresponding .c file. diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index 917cc0ac771..67853db1dd0 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -132,6 +132,19 @@ static const MemoryContextMethods mcxt_methods[] = { [MCTX_BUMP_ID].check = BumpCheck, #endif + /* systemcxt.c */ + [MCTX_SYSTEM_ID].alloc = SystemCxtAlloc, + [MCTX_SYSTEM_ID].free_p = SystemCxtFree, + [MCTX_SYSTEM_ID].realloc = SystemCxtRealloc, + [MCTX_SYSTEM_ID].reset = SystemCxtReset, + [MCTX_SYSTEM_ID].delete_context = SystemCxtDelete, + [MCTX_SYSTEM_ID].get_chunk_context = SystemCxtGetChunkContext, + [MCTX_SYSTEM_ID].get_chunk_space = SystemCxtGetChunkSpace, + [MCTX_SYSTEM_ID].is_empty = SystemCxtIsEmpty, + [MCTX_SYSTEM_ID].stats = SystemCxtStats, +#ifdef MEMORY_CONTEXT_CHECKING + [MCTX_SYSTEM_ID].check = SystemCxtCheck, +#endif /* * Reserved and unused IDs should have dummy entries here. This allows us @@ -141,7 +154,6 @@ static const MemoryContextMethods mcxt_methods[] = { */ BOGUS_MCTX(MCTX_1_RESERVED_GLIBC_ID), BOGUS_MCTX(MCTX_2_RESERVED_GLIBC_ID), - BOGUS_MCTX(MCTX_8_UNUSED_ID), BOGUS_MCTX(MCTX_9_UNUSED_ID), BOGUS_MCTX(MCTX_10_UNUSED_ID), BOGUS_MCTX(MCTX_11_UNUSED_ID), diff --git a/src/backend/utils/mmgr/meson.build b/src/backend/utils/mmgr/meson.build index 61837e9f91b..5a9d6bbb36f 100644 --- a/src/backend/utils/mmgr/meson.build +++ b/src/backend/utils/mmgr/meson.build @@ -11,4 +11,5 @@ backend_sources += files( 'memdebug.c', 'portalmem.c', 'slab.c', + 'systemcxt.c', ) diff --git a/src/backend/utils/mmgr/systemcxt.c b/src/backend/utils/mmgr/systemcxt.c new file mode 100644 index 00000000000..23ff06e692d --- /dev/null +++ b/src/backend/utils/mmgr/systemcxt.c @@ -0,0 +1,521 @@ +/*------------------------------------------------------------------------- +* + * systemcxt.c + * System context allocator definitions. + * + * systemcxt.c (SystemContext) has no concept of grouping several allocations + * into blocks like many of the other allocators do. Each palloc() results in + * a malloc(), and each pfree() results in a free(), therefore, this isn't + * suitable for cases that require many allocations. The most suitable use + * cases are for contexts that require very few and long-lived allocations. + * The context header is also small, so this can be suitable when a large + * number of contexts are required. + * System is a MemoryContext implementation designed for memory usages which + * require their own memory context, but which generally have few allocations + * that generally have a very long lifetime. Compared to ASet, every + * allocation of a System memory context gets an External chunk, i.e. every + * palloc results in a malloc. + * + * Portions Copyright (c) 2024-2026, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/backend/utils/mmgr/systemcxt.c + * + * NOTE: + * SystemCxt is best suited to cases where a memory context with long lifetimes + * is required, but is expected to hold only a small number of small + * allocations, with a total memory usage smaller than the minimum aset block + * size. + * + * Allocations are MAXALIGNed. + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "lib/ilist.h" +#include "utils/memdebug.h" +#include "utils/memutils.h" +#include "utils/memutils_memorychunk.h" +#include "utils/memutils_internal.h" + +/* Struct definition for the System memory context. */ +typedef struct SystemContext +{ + MemoryContextData header; /* Standard memory-context fields */ + + dlist_head allocations; /* list of all allocations of this memcxt */ +} SystemContext; + +/* Struct definition for SystemContext's malloc()'d header. */ +typedef struct SystemBlock +{ + dlist_node node; /* node in SystemCtx->allocations */ + size_t sz; /* size of the requested allocation */ + SystemContext *context; /* direct pointer to the owning context */ +} SystemBlock; + +#define SYSTEM_CONTEXTSIZE (MAXALIGN(sizeof(SystemContext))) +#define SYSTEM_BLOCKHDRSZ (MAXALIGN(sizeof(SystemBlock))) +#define SYSTEM_CHUNKHDRSZ (sizeof(MemoryChunk)) + +/* + * SystemCxtIsValid + * True iff cxt is valid allocation cxt. + */ +#define SystemCxtIsValid(cxt) \ + ((cxt) && IsA(cxt, SystemContext)) + +#define ExternalChunkGetBlock(chunk) \ + ((SystemBlock *) (((char *) chunk) - SYSTEM_BLOCKHDRSZ)) + + +/* + * SystemContextCreate + * Create a SystemCxt memory context + */ +MemoryContext +SystemContextCreate(MemoryContext parent, const char *name) +{ + SystemContext *cxt; + + /* + * Allocate the context struct. Unlike other memory contexts, this + * context doesn't have an attached chunk of palloc'able memory. + */ + cxt = (SystemContext *) malloc(SYSTEM_CONTEXTSIZE); + if (cxt == NULL) + { + MemoryContextStats(TopMemoryContext); + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"), + errdetail("Failed while creating memory context \"%s\".", + name))); + } + + VALGRIND_CREATE_MEMPOOL(cxt, 0, false); + VALGRIND_MEMPOOL_ALLOC(cxt, cxt, SYSTEM_CONTEXTSIZE); + + dlist_init(&cxt->allocations); + + /* Finally, do the type-independent part of context creation */ + MemoryContextCreate((MemoryContext) cxt, T_SystemContext, MCTX_SYSTEM_ID, + parent, name); + + ((MemoryContext) cxt)->mem_allocated = SYSTEM_CONTEXTSIZE; + + return (MemoryContext) cxt; +} + +/* + * SystemCxtAlloc + * Alloc memory into the SystemCxt memory context. + */ +void * +SystemCxtAlloc(MemoryContext context, size_t size, int flags) +{ + SystemContext *cxt = (SystemContext *) context; + size_t blksize; + SystemBlock *block; + MemoryChunk *chunk; + + Assert(SystemCxtIsValid(cxt)); + + /* validate 'size' is within the limits for the given 'flags' */ + MemoryContextCheckSize(context, size, flags); + + /* adjust size for sentinel byte */ +#ifdef MEMORY_CONTEXT_CHECKING + blksize = MAXALIGN(size + 1); +#else + blksize = MAXALIGN(size); +#endif + + blksize += SYSTEM_BLOCKHDRSZ + SYSTEM_CHUNKHDRSZ; + + block = (SystemBlock *) malloc(blksize); + if (block == NULL) + return MemoryContextAllocationFailure(context, size, flags); + + VALGRIND_MEMPOOL_ALLOC(cxt, block, SYSTEM_BLOCKHDRSZ); + + context->mem_allocated += blksize; + + dlist_node_init(&block->node); + + block->context = cxt; + block->sz = blksize; + + dlist_push_tail(&cxt->allocations, &block->node); + + chunk = (MemoryChunk *) (((char *) block) + SYSTEM_BLOCKHDRSZ); + + MemoryChunkSetHdrMaskExternal(chunk, MCTX_SYSTEM_ID); + +#ifdef MEMORY_CONTEXT_CHECKING + chunk->requested_size = size; + /* set mark to catch clobber of "unused" space */ + set_sentinel(MemoryChunkGetPointer(chunk), size); +#endif + +#ifdef RANDOMIZE_ALLOCATED_MEMORY + /* fill the allocated space with junk */ + randomize_mem((char *) MemoryChunkGetPointer(chunk), size); +#endif + + VALGRIND_MAKE_MEM_NOACCESS(chunk, SYSTEM_CHUNKHDRSZ); + + return MemoryChunkGetPointer(chunk); +} + +/* + * SystemCxtAlloc + * Free memory from the SystemCxt memory context. + */ +void +SystemCxtFree(void *pointer) +{ + SystemContext *cxt; + MemoryChunk *chunk = PointerGetMemoryChunk(pointer); + SystemBlock *block; + + VALGRIND_MAKE_MEM_DEFINED(chunk, SYSTEM_CHUNKHDRSZ); + + Assert(MemoryChunkIsExternal(chunk)); + + block = ExternalChunkGetBlock(chunk); + + cxt = block->context; + + Assert(SystemCxtIsValid(cxt)); + +#ifdef MEMORY_CONTEXT_CHECKING + /* Test for someone scribbling on unused space in chunk */ + if (!sentinel_ok(pointer, chunk->requested_size)) + elog(WARNING, "detected write past chunk end in %s %p", + cxt->header.name, chunk); +#endif + + /* ok, remove block from the list, and free it */ + dlist_delete_from(&cxt->allocations, &block->node); + + cxt->header.mem_allocated -= block->sz; + +#ifdef CLOBBER_FREED_MEMORY + wipe_mem(block, block->sz); +#endif + + VALGRIND_MEMPOOL_FREE(cxt, block); + + free(block); +} + +/* + * SystemCxtAlloc + * Realloc memory in the SystemCxt memory context. + */ +void * +SystemCxtRealloc(void *pointer, size_t size, int flags) +{ + SystemBlock *block, + *new_block; + SystemContext *cxt; + MemoryChunk *chunk = PointerGetMemoryChunk(pointer); + size_t new_blksz; + + VALGRIND_MAKE_MEM_DEFINED(chunk, SYSTEM_CHUNKHDRSZ); + + Assert(MemoryChunkIsExternal(chunk)); + + block = ExternalChunkGetBlock(chunk); + + cxt = block->context; + + Assert(SystemCxtIsValid(cxt)); + + /* only check size in paths where the limits could be hit */ + MemoryContextCheckSize((MemoryContext) cxt, size, flags); + +#ifdef MEMORY_CONTEXT_CHECKING + /* Test for someone scribbling on unused space in chunk */ + if (!sentinel_ok(pointer, chunk->requested_size)) + elog(WARNING, "detected write past chunk end in %s %p", + cxt->header.name, chunk); +#endif + + +#ifdef MEMORY_CONTEXT_CHECKING + /* adjust for sentinel byte, and align */ + new_blksz = MAXALIGN(size + 1); +#else + new_blksz = MAXALIGN(size); +#endif + new_blksz += SYSTEM_BLOCKHDRSZ + SYSTEM_CHUNKHDRSZ; + + /* + * Temporarily unlink the allocation, because the address of the + * allocation may change. + */ + dlist_delete_from_thoroughly(&cxt->allocations, &block->node); + + new_block = realloc(block, new_blksz); + if (new_block == NULL) + { + VALGRIND_MAKE_MEM_NOACCESS(chunk, SYSTEM_CHUNKHDRSZ); + return MemoryContextAllocationFailure((MemoryContext) cxt, size, flags); + } + + /* Move the block-header vchunk */ + VALGRIND_MEMPOOL_CHANGE(cxt, block, new_block, SYSTEM_BLOCKHDRSZ); + block = new_block; + + dlist_push_tail(&cxt->allocations, &block->node); + + chunk = (MemoryChunk *) (((char *) block) + SYSTEM_BLOCKHDRSZ); + + /* + * randomize the newly allocated portion, old_len .. new_len + */ +#ifdef RANDOMIZE_ALLOCATED_MEMORY + if (new_blksz > block->sz) + randomize_mem(((char *) block) + block->sz, new_blksz - block->sz); +#endif + + /* update chunk's size data */ +#ifdef MEMORY_CONTEXT_CHECKING + chunk->requested_size = size; + set_sentinel(MemoryChunkGetPointer(chunk), size); +#endif + + /* and adjust the size indicator of the block header */ + block->sz = new_blksz; + + /* Disallow access to the chunk header. */ + VALGRIND_MAKE_MEM_NOACCESS(chunk, SYSTEM_CHUNKHDRSZ); + + return MemoryChunkGetPointer(chunk); +} + +/* + * SystemCxtReset + * Reset the SystemCxt memory context. + */ +void +SystemCxtReset(MemoryContext context) +{ + SystemContext *cxt = (SystemContext *) context; + + Assert(SystemCxtIsValid(cxt)); + + while (!dlist_is_empty(&cxt->allocations)) + { + SystemBlock *block = + dlist_container(SystemBlock, node, + dlist_pop_head_node(&cxt->allocations)); + size_t blksize = block->sz; + +#ifdef CLOBBER_FREED_MEMORY + wipe_mem(block, blksize); +#endif + + cxt->header.mem_allocated -= blksize; + + /* + * We need to free the block header's vchunk explicitly, although + * the user-data vchunks within will go away in the TRIM below. + * Otherwise Valgrind complains about leaked allocations. + */ + VALGRIND_MEMPOOL_FREE(cxt, block); + + free(block); + } + + Assert(cxt->header.mem_allocated == SYSTEM_CONTEXTSIZE); + Assert(SystemCxtIsEmpty(context)); + + /* + * Instruct Valgrind to throw away all the vchunks associated with this + * context, except for the one covering the SystemContext. This gets rid + * of the vchunks for whatever user data is getting discarded by the + * context reset. + */ + VALGRIND_MEMPOOL_TRIM(cxt, cxt, SYSTEM_CONTEXTSIZE); +} + +/* + * SystemCxtAlloc + * Delete this SystemCxt memory context. + */ +void +SystemCxtDelete(MemoryContext context) +{ + SystemContext *cxt = (SystemContext *) context; + + Assert(SystemCxtIsValid(cxt)); + +#ifdef MEMORY_CONTEXT_CHECKING + SystemCxtCheck(context); +#endif + + SystemCxtReset(context); + + VALGRIND_DESTROY_MEMPOOL(context); + + free(cxt); +} + +/* + * SystemCxtGetChunkContext + * Return the MemoryContext that 'pointer' belongs to. + */ +MemoryContext +SystemCxtGetChunkContext(void *pointer) +{ + MemoryChunk *chunk = PointerGetMemoryChunk(pointer); + SystemBlock *block; + SystemContext *cxt; + + VALGRIND_MAKE_MEM_DEFINED(chunk, SYSTEM_CHUNKHDRSZ); + + Assert(MemoryChunkIsExternal(chunk)); + block = ExternalChunkGetBlock(chunk); + + VALGRIND_MAKE_MEM_NOACCESS(chunk, SYSTEM_CHUNKHDRSZ); + + cxt = block->context; + + Assert(SystemCxtIsValid(cxt)); + + return (MemoryContext) cxt; +} + +/* + * SystemCxtGetChunkSpace +* Given a palloc'd chunk, determine the total space + * it occupies (including all memory-allocation overhead). + */ +size_t +SystemCxtGetChunkSpace(void *pointer) +{ + MemoryChunk *chunk = PointerGetMemoryChunk(pointer); + SystemBlock *block; + + VALGRIND_MAKE_MEM_DEFINED(chunk, SYSTEM_CHUNKHDRSZ); + + Assert(MemoryChunkIsExternal(chunk)); + block = ExternalChunkGetBlock(chunk); + + VALGRIND_MAKE_MEM_NOACCESS(chunk, SYSTEM_CHUNKHDRSZ); + + return block->sz; +} + +/* + * SystemCxtIsEmpty +* Is the SystemContext empty of any allocated space? + */ +bool +SystemCxtIsEmpty(MemoryContext context) +{ + SystemContext *cxt = (SystemContext *) context; + + Assert(SystemCxtIsValid(cxt)); + + return dlist_is_empty(&cxt->allocations); +} + +/* + * SystemCxtStats + * Compute stats about memory consumption of a SystemCxt context. + * + * printfunc: if not NULL, pass a human-readable stats string to this. + * passthru: pass this pointer through to printfunc. + * totals: if not NULL, add stats about this context into *totals. + * print_to_stderr: print stats to stderr if true, elog otherwise. + */ +void +SystemCxtStats(MemoryContext context, MemoryStatsPrintFunc printfunc, + void *passthru, MemoryContextCounters *totals, + bool print_to_stderr) +{ + SystemContext *cxt = (SystemContext *) context; + dlist_iter iter; + size_t totalspace; + size_t nchunks = 0; + + totalspace = MAXALIGN(sizeof(SystemContext)); + + dlist_foreach(iter, &cxt->allocations) + { + SystemBlock *block = dlist_container(SystemBlock, node, iter.cur); + + nchunks++; + totalspace += block->sz; + } + + + if (printfunc) + { + char stats_string[200]; + + snprintf(stats_string, sizeof(stats_string), + "%zu total in %zu chunks;", + totalspace, nchunks); + printfunc(context, passthru, stats_string, print_to_stderr); + } + + if (totals) + { + totals->nblocks += nchunks; + totals->totalspace += totalspace; + } +} + +#ifdef MEMORY_CONTEXT_CHECKING +/* + * SystemCxtCheck + * Walk through chunks and check consistency of memory. + * + * NOTE: report errors as WARNING, *not* ERROR or FATAL. Otherwise you'll + * find yourself in an infinite loop when trouble occurs, because this + * routine will be entered again when elog cleanup tries to release memory! + */ +void +SystemCxtCheck(MemoryContext context) +{ + SystemContext *cxt = (SystemContext *) context; + const char *name = context->name; + dlist_iter iter; + size_t total_allocated = sizeof(SystemContext); + + /* walk all blocks in this context */ + dlist_foreach(iter, &cxt->allocations) + { + SystemBlock *block = dlist_container(SystemBlock, node, iter.cur); + MemoryChunk *chunk = (MemoryChunk *) ((char *) block + SYSTEM_BLOCKHDRSZ); + + total_allocated += block->sz; + + if (block->sz != MAXALIGN(chunk->requested_size + 1) + SYSTEM_BLOCKHDRSZ + SYSTEM_CHUNKHDRSZ) + { + elog(WARNING, "problem in SystemCxt %s: bad single-chunk %p in block %p", + name, chunk, block); + } + + if (!sentinel_ok(chunk, chunk->requested_size + SYSTEM_CHUNKHDRSZ)) + { + elog(WARNING, "problem in SystemCxt %s: detected write past chunk end in block %p, chunk %p", + name, block, chunk); + } + } + + Assert(total_allocated == context->mem_allocated); + + if (total_allocated != cxt->header.mem_allocated) + { + elog(WARNING, "problem in SystemCxt %s: sum of memory %zd does not match header's %zd", + name, total_allocated, cxt->header.mem_allocated); + } +} +#endif diff --git a/src/include/nodes/memnodes.h b/src/include/nodes/memnodes.h index 4b24778fe1e..87a7b3b3e57 100644 --- a/src/include/nodes/memnodes.h +++ b/src/include/nodes/memnodes.h @@ -147,6 +147,7 @@ typedef struct MemoryContextData (IsA((context), AllocSetContext) || \ IsA((context), SlabContext) || \ IsA((context), GenerationContext) || \ - IsA((context), BumpContext))) + IsA((context), BumpContext) || \ + IsA((context), SystemContext))) #endif /* MEMNODES_H */ diff --git a/src/include/utils/memutils.h b/src/include/utils/memutils.h index 38036c7c703..8cae0ae3d8d 100644 --- a/src/include/utils/memutils.h +++ b/src/include/utils/memutils.h @@ -150,6 +150,10 @@ extern MemoryContext BumpContextCreate(MemoryContext parent, Size initBlockSize, Size maxBlockSize); +/* systemcxt.c */ +extern MemoryContext SystemContextCreate(MemoryContext parent, + const char *name); + /* * Recommended default alloc parameters, suitable for "ordinary" contexts * that might hold quite a lot of data. diff --git a/src/include/utils/memutils_internal.h b/src/include/utils/memutils_internal.h index 475e91b336b..3f0af809828 100644 --- a/src/include/utils/memutils_internal.h +++ b/src/include/utils/memutils_internal.h @@ -93,6 +93,22 @@ extern void BumpStats(MemoryContext context, MemoryStatsPrintFunc printfunc, bool print_to_stderr); #ifdef MEMORY_CONTEXT_CHECKING extern void BumpCheck(MemoryContext context); +#endif + + /* These functions implement the MemoryContext API for the Proxy context. */ +extern void *SystemCxtAlloc(MemoryContext context, size_t size, int flags); +extern void SystemCxtFree(void *pointer); +extern void *SystemCxtRealloc(void *pointer, size_t size, int flags); +extern void SystemCxtReset(MemoryContext context); +extern void SystemCxtDelete(MemoryContext context); +extern MemoryContext SystemCxtGetChunkContext(void *pointer); +extern size_t SystemCxtGetChunkSpace(void *pointer); +extern bool SystemCxtIsEmpty(MemoryContext context); +extern void SystemCxtStats(MemoryContext context, MemoryStatsPrintFunc printfunc, + void *passthru, MemoryContextCounters *totals, + bool print_to_stderr); +#ifdef MEMORY_CONTEXT_CHECKING +extern void SystemCxtCheck(MemoryContext context); #endif /* @@ -128,7 +144,7 @@ typedef enum MemoryContextMethodID MCTX_SLAB_ID, MCTX_ALIGNED_REDIRECT_ID, MCTX_BUMP_ID, - MCTX_8_UNUSED_ID, + MCTX_SYSTEM_ID, MCTX_9_UNUSED_ID, MCTX_10_UNUSED_ID, MCTX_11_UNUSED_ID, diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index a7a8dbdd23f..ce3ab753927 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2429,6 +2429,8 @@ ProjectionInfo ProjectionPath PromptInterruptContext ProtocolVersion +ProxyContext +ProxyChunk PrsStorage PruneFreezeParams PruneFreezeResult -- 2.54.0 (Apple Git-157)