新增GUC参数disable_memory_stats控制STANDARD MEMORY CONTEXT的分配,

开启该参数时逻辑简化,去除一些内存跟踪统计。
This commit is contained in:
lancer
2022-12-19 18:42:03 +08:00
committed by April01xxx
parent e6e79d9da0
commit 3b47d9cd6f
14 changed files with 1410 additions and 34 deletions

View File

@ -274,6 +274,7 @@ static const TagStr g_tagStrArr[] = {{T_Invalid, "Invalid"},
{T_MergeAction, "MergeAction"},
{T_MemoryContext, "MemoryContext"},
{T_AllocSetContext, "AllocSetContext"},
{T_OptAllocSetContext, "OptAllocSetContext"},
{T_StackAllocSetContext, "StackAllocSetContext"},
{T_SharedAllocSetContext, "SharedAllocSetContext"},
{T_MemalignAllocSetContext, "MemalignAllocSetContext"},

View File

@ -273,6 +273,19 @@ static void InitMemoryConfigureNamesBool()
NULL,
NULL},
// variable to disable memory stats
{{"disable_memory_stats",
PGC_POSTMASTER,
NODE_ALL,
RESOURCES_MEM,
gettext_noop("disable memory stats for query execution."),
NULL},
&g_instance.attr.attr_memory.disable_memory_stats,
false,
NULL,
NULL,
NULL},
#ifdef MEMORY_CONTEXT_CHECKING
// variable to enable memory check
{{"enable_memory_context_check_debug",

View File

@ -19,6 +19,6 @@ ifneq "$(MAKECMDGOALS)" "clean"
endif
endif
endif
OBJS = aset.o mcxt.o portalmem.o memprot.o asetstk.o asetalg.o memtrack.o AsanMemoryAllocator.o memgroup.o memtrace.o mem_snapshot.o
OBJS = aset.o mcxt.o opt_aset.o opt_mcxt.o portalmem.o memprot.o asetstk.o asetalg.o memtrack.o AsanMemoryAllocator.o memgroup.o memtrace.o mem_snapshot.o
include $(top_srcdir)/src/gausskernel/common.mk

View File

@ -379,9 +379,14 @@ MemoryContext AllocSetContextCreate(_in_ MemoryContext parent, _in_ const char*
}
switch (contextType) {
#ifndef ENABLE_MEMORY_CHECK
case STANDARD_CONTEXT:
return GenericMemoryAllocator::AllocSetContextCreate(
parent, name, minContextSize, initBlockSize, maxBlockSize, maxSize, false, isSession);
case STANDARD_CONTEXT: {
if (g_instance.attr.attr_memory.disable_memory_stats) {
return opt_AllocSetContextCreate(parent, name, minContextSize, initBlockSize, maxBlockSize);
} else {
return GenericMemoryAllocator::AllocSetContextCreate(
parent, name, minContextSize, initBlockSize, maxBlockSize, maxSize, false, isSession);
}
}
case SHARED_CONTEXT:
return GenericMemoryAllocator::AllocSetContextCreate(
parent, name, minContextSize, initBlockSize, maxBlockSize, maxSize, true, false);

View File

@ -216,6 +216,10 @@ void MemoryContextReset(MemoryContext context)
{
AssertArg(MemoryContextIsValid(context));
if (IsOptAllocSetContext(context)) {
return opt_MemoryContextReset(context);
}
PreventActionOnSealedContext(context);
if (MemoryContextIsShared(context))
@ -300,6 +304,11 @@ void MemoryContextDeleteInternal(MemoryContext context, bool parent_locked,
/* And not CurrentMemoryContext, either */
Assert(context != CurrentMemoryContext);
if (IsOptAllocSetContext(context)) {
opt_MemoryContextDeleteInternal(context, context_list);
return;
}
MemoryContextDeleteChildren(context, context_list);
#ifdef MEMORY_CONTEXT_CHECKING
@ -991,6 +1000,11 @@ void MemoryContextCheckSessionMemory(MemoryContext context, Size size, const cha
void* MemoryAllocFromContext(MemoryContext context, Size size, const char* file, int line)
{
void* ret = NULL;
if (IsOptAllocSetContext(context)) {
return opt_MemoryAllocFromContext(context, size);
}
if (!AllocSizeIsValid(size)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@ -1049,6 +1063,10 @@ void* MemoryContextAllocZeroDebug(MemoryContext context, Size size, const char*
{
void* ret = NULL;
if (IsOptAllocSetContext(context)) {
return opt_MemoryContextAllocZeroDebug(context, size, file, line);
}
AssertArg(MemoryContextIsValid(context));
#ifdef MEMORY_CONTEXT_CHECKING
PreventActionOnSealedContext(context);
@ -1099,6 +1117,10 @@ void* MemoryContextAllocZeroAlignedDebug(MemoryContext context, Size size, const
{
void* ret = NULL;
if (IsOptAllocSetContext(context)) {
return opt_MemoryContextAllocZeroAlignedDebug(context, size, file, line);
}
AssertArg(MemoryContextIsValid(context));
PreventActionOnSealedContext(context);
@ -1275,6 +1297,11 @@ void pfree(void* pointer)
context = &(block->aset->header);
#endif
if (IsOptAllocSetContext(context)) {
opt_pfree(pointer);
return;
}
AssertArg(MemoryContextIsValid(context));
#ifdef MEMORY_CONTEXT_CHECKING
if (!IsTopMemCxt(context)) {
@ -1292,6 +1319,20 @@ void* repalloc_noexcept_Debug(void* pointer, Size size, const char* file, int li
MemoryContext context;
void* ret = NULL;
#ifndef ENABLE_MEMORY_CHECK
/*
* OK, it's probably safe to look at the chunk header.
*/
context = ((StandardChunkHeader*)((char*)pointer - STANDARDCHUNKHEADERSIZE))->context;
#else
AsanBlock block = ((AsanBlock)(((char*)(pointer)) - ASAN_BLOCKHDRSZ));
context = &(block->aset->header);
#endif
if (IsOptAllocSetContext(context)) {
return opt_repalloc_noexcept_Debug(pointer, size, file, line);
}
if (!AllocSizeIsValid(size)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@ -1306,16 +1347,6 @@ void* repalloc_noexcept_Debug(void* pointer, Size size, const char* file, int li
Assert(pointer != NULL);
Assert(pointer == (void*)MAXALIGN(pointer));
#ifndef ENABLE_MEMORY_CHECK
/*
* OK, it's probably safe to look at the chunk header.
*/
context = ((StandardChunkHeader*)((char*)pointer - STANDARDCHUNKHEADERSIZE))->context;
#else
AsanBlock block = ((AsanBlock)(((char*)(pointer)) - ASAN_BLOCKHDRSZ));
context = &(block->aset->header);
#endif
AssertArg(MemoryContextIsValid(context));
/* isReset must be false already */
@ -1346,6 +1377,20 @@ void* repallocDebug(void* pointer, Size size, const char* file, int line)
MemoryContext context;
void* ret = NULL;
#ifndef ENABLE_MEMORY_CHECK
/*
* OK, it's probably safe to look at the chunk header.
*/
context = ((StandardChunkHeader*)((char*)pointer - STANDARDCHUNKHEADERSIZE))->context;
#else
AsanBlock block = ((AsanBlock)(((char*)(pointer)) - ASAN_BLOCKHDRSZ));
context = &(block->aset->header);
#endif
if (IsOptAllocSetContext(context)) {
return opt_repallocDebug(pointer, size, file, line);
}
if (!AllocSizeIsValid(size)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@ -1359,15 +1404,7 @@ void* repallocDebug(void* pointer, Size size, const char* file, int line)
*/
Assert(pointer != NULL);
Assert(pointer == (void*)MAXALIGN(pointer));
#ifndef ENABLE_MEMORY_CHECK
/*
* OK, it's probably safe to look at the chunk header.
*/
context = ((StandardChunkHeader*)((char*)pointer - STANDARDCHUNKHEADERSIZE))->context;
#else
AsanBlock block = ((AsanBlock)(((char*)(pointer)) - ASAN_BLOCKHDRSZ));
context = &(block->aset->header);
#endif
AssertArg(MemoryContextIsValid(context));
PreventActionOnSealedContext(context);
/* isReset must be false already */
@ -1455,6 +1492,10 @@ void* MemoryContextAllocHugeDebug(MemoryContext context, Size size, const char*
{
void* ret = NULL;
if (IsOptAllocSetContext(context)) {
return opt_MemoryAllocFromContext(context, size);
}
AssertArg(MemoryContextIsValid(context));
if (!AllocHugeSizeIsValid(size)) {
@ -1502,6 +1543,20 @@ void* repallocHugeDebug(void* pointer, Size size, const char* file, int line)
MemoryContext context;
void* ret = NULL;
#ifndef ENABLE_MEMORY_CHECK
/*
* OK, it's probably safe to look at the chunk header.
*/
context = ((StandardChunkHeader*)((char*)pointer - STANDARDCHUNKHEADERSIZE))->context;
#else
AsanBlock block = ((AsanBlock)(((char*)(pointer)) - ASAN_BLOCKHDRSZ));
context = &(block->aset->header);
#endif
if (IsOptAllocSetContext(context)) {
return opt_repallocDebug(pointer, size, file, line);
}
if (!AllocHugeSizeIsValid(size)) {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid memory alloc request size %lu in %s:%d", size, file, line)));
@ -1514,15 +1569,7 @@ void* repallocHugeDebug(void* pointer, Size size, const char* file, int line)
*/
Assert(pointer != NULL);
Assert(pointer == (void*)MAXALIGN(pointer));
#ifndef ENABLE_MEMORY_CHECK
/*
* OK, it's probably safe to look at the chunk header.
*/
context = ((StandardChunkHeader*)((char*)pointer - STANDARDCHUNKHEADERSIZE))->context;
#else
AsanBlock block = ((AsanBlock)(((char*)(pointer)) - ASAN_BLOCKHDRSZ));
context = &(block->aset->header);
#endif
AssertArg(MemoryContextIsValid(context));
/* isReset must be false already */

View File

@ -0,0 +1,954 @@
/* -------------------------------------------------------------------------
*
* std_aset.cpp
* Allocation set definitions.
*
* AllocSet is our standard implementation of the abstract MemoryContext
* type.
*
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* src/backend/utils/mmgr/aset.c
*
* NOTE:
* This is a new (Feb. 05, 1999) implementation of the allocation set
* routines. AllocSet...() does not use OrderedSet...() any more.
* Instead it manages allocations in a block pool by itself, combining
* many small allocations in a few bigger blocks. AllocSetFree() normally
* doesn't free() memory really. It just add's the free'd area to some
* list for later reuse by AllocSetAlloc(). All memory blocks are free()'d
* at once on AllocSetReset(), which happens when the memory context gets
* destroyed.
* Jan Wieck
*
* Performance improvement from Tom Lane, 8/99: for extremely large request
* sizes, we do want to be able to give the memory back to free() as soon
* as it is pfree()'d. Otherwise we risk tying up a lot of memory in
* freelist entries that might never be usable. This is specially needed
* when the caller is repeatedly repalloc()'ing a block bigger and bigger;
* the previous instances of the block were guaranteed to be wasted until
* AllocSetReset() under the old way.
*
* Further improvement 12/00: as the code stood, request sizes in the
* midrange between "small" and "large" were handled very inefficiently,
* because any sufficiently large free chunk would be used to satisfy a
* request, even if it was much larger than necessary. This led to more
* and more wasted space in allocated chunks over time. To fix, get rid
* of the midrange behavior: we now handle only "small" power-of-2-size
* chunks as chunks. Anything "large" is passed off to malloc(). Change
* the number of freelists to change the small/large boundary.
*
*
* About CLOBBER_FREED_MEMORY:
*
* If this symbol is defined, all freed memory is overwritten with 0x7F's.
* This is useful for catching places that reference already-freed memory.
*
* About MEMORY_CONTEXT_CHECKING:
*
* Since we usually round request sizes up to the next power of 2, there
* is often some unused space immediately after a requested data area.
* Thus, if someone makes the common error of writing past what they've
* requested, the problem is likely to go unnoticed ... until the day when
* there *isn't* any wasted space, perhaps because of different memory
* alignment on a new platform, or some other effect. To catch this sort
* of problem, the MEMORY_CONTEXT_CHECKING option stores 0x7E just beyond
* the requested space whenever the request is less than the actual chunk
* size, and verifies that the byte is undamaged when the chunk is freed.
*
* -------------------------------------------------------------------------
*/
#include <sys/mman.h>
#include "postgres.h"
#include "knl/knl_variable.h"
#include "utils/dynahash.h"
#include "utils/memutils.h"
#include "utils/mmpool.h"
#include "utils/aset.h"
#include "gssignal/gs_signal.h"
#include "gs_register/gs_malloc.h"
#include "pgstat.h"
#include "miscadmin.h"
#include "utils/memprot.h"
#include "utils/memtrack.h"
#include "storage/procarray.h"
/* Define this to detail debug alloc information . HAVE_ALLOCINFO */
/* --------------------
* Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
* for k = 0 .. ALLOCSET_NUM_FREELISTS-1.
*
* Note that all chunks in the freelists have power-of-2 sizes. This
* improves recyclability: we may waste some space, but the wasted space
* should stay pretty constant as requests are made and released.
*
* A request too large for the last freelist is handled by allocating a
* dedicated block from malloc(). The block still has a block header and
* chunk header, but when the chunk is freed we'll return the whole block
* to malloc(), not put it on our freelists.
*
* CAUTION: ALLOC_MINBITS must be large enough so that
* 1<<ALLOC_MINBITS is at least MAXALIGN,
* or we may fail to align the smallest chunks adequately.
* 8-byte alignment is enough on all currently known machines.
*
* With the current parameters, request sizes up to 8K are treated as chunks,
* larger requests go into dedicated blocks. Change ALLOCSET_NUM_FREELISTS
* to adjust the boundary point. (But in contexts with small maxBlockSize,
* we may set the allocChunkLimit to less than 8K, so as to avoid space
* wastage.)
* --------------------
*/
#define ALLOC_MINBITS 3 /* smallest chunk size is 8 bytes */
#define ALLOCSET_NUM_FREELISTS 11
#define ALLOC_CHUNK_LIMIT (1 << (ALLOCSET_NUM_FREELISTS - 1 + ALLOC_MINBITS))
/* Size of largest chunk that we use a fixed size for */
#define ALLOC_CHUNK_FRACTION 4
/* We allow chunks to be at most 1/4 of maxBlockSize (less overhead) */
/* --------------------
* The first block allocated for an allocset has size initBlockSize.
* Each time we have to allocate another block, we double the block size
* (if possible, and without exceeding maxBlockSize), so as to reduce
* the bookkeeping load on malloc().
*
* Blocks allocated to hold oversize chunks do not follow this rule, however;
* they are just however big they need to be to hold that single chunk.
* --------------------
*/
#define ALLOC_MAGICHDRSZ 0
/*
* AllocPointerIsValid
* True iff pointer is valid allocation pointer.
*/
#define AllocPointerIsValid(pointer) PointerIsValid(pointer)
/*
* AllocSetIsValid
* True iff set is valid allocation set.
*/
#define AllocSetIsValid(set) PointerIsValid(set)
#define AllocPointerGetChunk(ptr) ((AllocChunk)(((char*)(ptr)) - ALLOC_CHUNKHDRSZ))
#define AllocChunkGetPointer(chk) ((AllocPointer)(((char*)(chk)) + ALLOC_CHUNKHDRSZ))
/*
* Table for opt_AllocSetFreeIndex
*/
#define LT16(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
static const unsigned char LogTable256[256] = {0,
1,
2,
2,
3,
3,
3,
3,
4,
4,
4,
4,
4,
4,
4,
4,
LT16(5),
LT16(6),
LT16(6),
LT16(7),
LT16(7),
LT16(7),
LT16(7),
LT16(8),
LT16(8),
LT16(8),
LT16(8),
LT16(8),
LT16(8),
LT16(8),
LT16(8)};
#define MAX_FREE_CONTEXTS 100 /* arbitrary limit on freelist length */
typedef struct AllocSetFreeList
{
int num_free; /* current list length */
AllocSetContext *first_free; /* list header */
} AllocSetFreeList;
/* context_freelists[0] is for default params, [1] for small params */
THR_LOCAL AllocSetFreeList context_freelists[2] =
{
{
0, NULL
},
{
0, NULL
}
};
/* ----------
* opt_AllocSetFreeIndex -
*
* Depending on the size of an allocation compute which freechunk
* list of the alloc set it belongs to. Caller must have verified
* that size <= ALLOC_CHUNK_LIMIT.
* ----------
*/
static inline int opt_AllocSetFreeIndex(Size size)
{
int idx;
if (size > (1 << ALLOC_MINBITS)) {
idx = 31 - __builtin_clz((uint32) size - 1) - ALLOC_MINBITS + 1;
Assert(idx < ALLOCSET_NUM_FREELISTS);
} else
idx = 0;
return idx;
}
static void* opt_AllocSetAlloc(MemoryContext context, Size align, Size size, const char* file, int line);
static void opt_AllocSetFree(MemoryContext context, void* pointer);
static void* opt_AllocSetRealloc(MemoryContext context, void* pointer, Size align, Size size, const char* file, int line);
static void opt_AllocSetInit(MemoryContext context);
static void opt_AllocSetReset(MemoryContext context);
static void opt_AllocSetDelete(MemoryContext context);
static Size opt_AllocSetGetChunkSpace(MemoryContext context, void* pointer);
static bool opt_AllocSetIsEmpty(MemoryContext context);
static void opt_AllocSetStats(MemoryContext context, int level);
/*
* Public routines
*/
static MemoryContextMethods AllocSetMethods = {
opt_AllocSetAlloc,
opt_AllocSetFree,
opt_AllocSetRealloc,
opt_AllocSetInit,
opt_AllocSetReset,
opt_AllocSetDelete,
opt_AllocSetGetChunkSpace,
opt_AllocSetIsEmpty,
opt_AllocSetStats
};
MemoryContextMethods *get_AllocSetMethods()
{
return &AllocSetMethods;
}
/*
* AllocSetContextCreate
* Create a new AllocSet context.
*
* parent: parent context, or NULL if top-level context
* name: name of context (for debugging --- string will be copied)
* minContextSize: minimum context size
* initBlockSize: initial allocation block size
* maxBlockSize: maximum allocation block size
*/
MemoryContext opt_AllocSetContextCreate(MemoryContext parent, const char* name, Size minContextSize,
Size initBlockSize, Size maxBlockSize)
{
AllocSet context;
AllocBlock block;
int freeListIndex;
Size firstBlockSize;
if (minContextSize == ALLOCSET_DEFAULT_MINSIZE &&
initBlockSize == ALLOCSET_DEFAULT_INITSIZE)
freeListIndex = 0;
else if (minContextSize == ALLOCSET_SMALL_MINSIZE &&
initBlockSize == ALLOCSET_SMALL_INITSIZE)
freeListIndex = 1;
else
freeListIndex = -1;
if (freeListIndex >= 0)
{
AllocSetFreeList *freelist = &context_freelists[freeListIndex];
if (freelist->first_free != NULL)
{
/* Remove entry from freelist */
context = freelist->first_free;
freelist->first_free = (AllocSet) context->header.nextchild;
freelist->num_free--;
/* Update its maxBlockSize; everything else should be OK */
context->maxBlockSize = maxBlockSize;
/* Reinitialize its header, installing correct name and parent */
opt_MemoryContextCreate((MemoryContext) context,
T_OptAllocSetContext,
&AllocSetMethods,
parent,
name);
context->maxSpaceSize = SELF_GENRIC_MEMCTX_LIMITATION;
return (MemoryContext) context;
}
}
/* Determine size of initial block */
firstBlockSize = MAXALIGN(sizeof(AllocSetContext)) +
ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
if (minContextSize != 0)
firstBlockSize = Max(firstBlockSize, minContextSize);
else
firstBlockSize = Max(firstBlockSize, initBlockSize);
context = (AllocSet) malloc(firstBlockSize);
if (context == NULL)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"),
errdetail("Failed while creating memory context \"%s\".",
name)));
block = (AllocBlock) (((char *) context) + MAXALIGN(sizeof(AllocSetContext)));
block->aset = context;
block->freeptr = ((char*)block) + ALLOC_BLOCKHDRSZ;
block->endptr = ((char*)context) + firstBlockSize;
block->allocSize = firstBlockSize;
context->totalSpace += firstBlockSize;
context->freeSpace += block->endptr - block->freeptr;
block->prev = NULL;
block->next = NULL;
/* Remember block as part of block list */
context->blocks = block;
/* Mark block as not to be released at reset time */
context->keeper = block;
MemSetAligned(context->freelist, 0, sizeof(context->freelist));
context->initBlockSize = initBlockSize;
context->maxBlockSize = maxBlockSize;
context->nextBlockSize = initBlockSize;
context->freeListIndex = freeListIndex;
context->allocChunkLimit = ALLOC_CHUNK_LIMIT;
while ((Size)(context->allocChunkLimit + ALLOC_CHUNKHDRSZ) >
(Size)((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION)) {
context->allocChunkLimit >>= 1;
}
opt_MemoryContextCreate((MemoryContext) context,
T_OptAllocSetContext,
&AllocSetMethods,
parent,
name);
context->maxSpaceSize = SELF_GENRIC_MEMCTX_LIMITATION;
return (MemoryContext) context;
}
/*
* AllocSetInit
* Context-type-specific initialization routine.
*
* This is called by MemoryContextCreate() after setting up the
* generic MemoryContext fields and before linking the new context
* into the context tree. We must do whatever is needed to make the
* new context minimally valid for deletion. We must *not* risk
* failure --- thus, for example, allocating more memory is not cool.
* (AllocSetContextCreate can allocate memory when it gets control
* back, however.)
*/
static void opt_AllocSetInit(MemoryContext context)
{
/*
* Since MemoryContextCreate already zeroed the context node, we don't
* have to do anything here: it's already OK.
*/
}
/*
* AllocSetReset
* Frees all memory which is allocated in the given set.
*
* Actually, this routine has some discretion about what to do.
* It should mark all allocated chunks freed, but it need not necessarily
* give back all the resources the set owns. Our actual implementation is
* that we hang onto any "keeper" block specified for the set. In this way,
* we don't thrash malloc() when a context is repeatedly reset after small
* allocations, which is typical behavior for per-tuple contexts.
*/
static void opt_AllocSetReset(MemoryContext context)
{
AllocSet set = (AllocSet)context;
AllocBlock block;
AssertArg(AllocSetIsValid(set));
/* Clear chunk freelists */
MemSetAligned(set->freelist, 0, sizeof(set->freelist));
block = set->blocks;
/* New blocks list is either empty or just the keeper block */
set->blocks = set->keeper;
while (block != NULL) {
AllocBlock next = block->next;
Size tempSize = block->allocSize;
if (block == set->keeper) {
/* Reset the block, but don't return it to malloc */
char* datastart = ((char*)block) + ALLOC_BLOCKHDRSZ;
block->freeptr = datastart;
block->allocSize = tempSize;
block->next = NULL;
block->prev = NULL;
} else {
free(block);
}
block = next;
}
/* Reset block size allocation sequence, too */
set->nextBlockSize = set->initBlockSize;
if (set->blocks != NULL) {
/* calculate memory statisic after reset. */
block = set->blocks;
set->freeSpace = block->endptr - block->freeptr;
set->totalSpace = block->endptr - (char*)block;
} else {
set->freeSpace = 0;
set->totalSpace = 0;
}
}
/*
* AllocSetDelete
* Frees all memory which is allocated in the given set,
* in preparation for deletion of the set.
*
* Unlike AllocSetReset, this *must* free all resources of the set.
* But note we are not responsible for deleting the context node itself.
*/
static void opt_AllocSetDelete(MemoryContext context)
{
AllocSet set = (AllocSet)context;
AssertArg(AllocSetIsValid(set));
AllocBlock block = set->blocks;
if (set->freeListIndex >= 0)
{
AllocSetFreeList *freelist = &context_freelists[set->freeListIndex];
if (!context->isReset) {
context->methods->reset(context);
context->isReset = true;
}
if (freelist->num_free >= MAX_FREE_CONTEXTS)
{
while (freelist->first_free != NULL)
{
AllocSetContext *oldset = freelist->first_free;
freelist->first_free = (AllocSetContext *) oldset->header.nextchild;
freelist->num_free--;
/* All that remains is to free the header/initial block */
free(oldset);
}
Assert(freelist->num_free == 0);
}
/* Now add the just-deleted context to the freelist. */
set->header.nextchild = (MemoryContext) freelist->first_free;
freelist->first_free = set;
freelist->num_free++;
return;
}
while (block != NULL) {
AllocBlock next = block->next;
if (block != set->keeper)
free(block);
block = next;
}
free(set);
}
/*
* AllocSetAlloc
* Returns pointer to allocated memory of given size; memory is added
* to the set.
*/
static void* opt_AllocSetAlloc(MemoryContext context, Size align, Size size, const char* file, int line)
{
Assert(file != NULL);
Assert(line != 0);
AllocSet set = (AllocSet)context;
AllocBlock block;
AllocChunk chunk;
#ifndef ENABLE_MEMORY_CHECK
unsigned int fidx;
#endif
Size chunk_size;
Size blksize;
AssertArg(AllocSetIsValid(set));
AssertArg(align == 0);
size += ALLOC_MAGICHDRSZ;
/*
* If requested size exceeds maximum for chunks, allocate an entire block
* for this request.
*/
#ifndef ENABLE_MEMORY_CHECK
if (size > set->allocChunkLimit) {
#endif
chunk_size = MAXALIGN(size);
blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
block = (AllocBlock) malloc(blksize);
if (block == NULL) {
return NULL;
}
block->aset = set;
block->freeptr = block->endptr = ((char*)block) + blksize;
block->allocSize = blksize;
/* enlarge total space only. */
set->totalSpace += blksize;
chunk = (AllocChunk)(((char*)block) + ALLOC_BLOCKHDRSZ);
chunk->aset = set;
chunk->size = chunk_size;
/*
* Stick the new block underneath the active allocation block, so that
* we don't lose the use of the space remaining therein.
*/
if (set->blocks != NULL) {
block->prev = set->blocks;
block->next = set->blocks->next;
if (block->next)
block->next->prev = block;
set->blocks->next = block;
} else {
block->prev = NULL;
block->next = NULL;
set->blocks = block;
}
return AllocChunkGetPointer(chunk);
#ifndef ENABLE_MEMORY_CHECK
}
/*
* Request is small enough to be treated as a chunk. Look in the
* corresponding free list to see if there is a free chunk we could reuse.
* If one is found, remove it from the free list, make it again a member
* of the alloc set and return its data address.
*/
fidx = opt_AllocSetFreeIndex(size);
chunk = set->freelist[fidx];
if (chunk != NULL) {
Assert(chunk->size >= size);
Assert(chunk->aset != set);
Assert((int)fidx == opt_AllocSetFreeIndex(chunk->size));
set->freelist[fidx] = (AllocChunk)chunk->aset;
chunk->aset = (void*)set;
set->freeSpace -= (chunk->size + ALLOC_CHUNKHDRSZ);
return AllocChunkGetPointer(chunk);
}
/*
* Choose the actual chunk size to allocate.
*/
chunk_size = ((unsigned long)1 << ALLOC_MINBITS) << fidx;
Assert(chunk_size >= size);
/*
* If there is enough room in the active allocation block, we will put the
* chunk into that block. Else must start a new one.
*/
if ((block = set->blocks) != NULL) {
Size availspace = block->endptr - block->freeptr;
if (availspace < (chunk_size + ALLOC_CHUNKHDRSZ)) {
/*
* The existing active (top) block does not have enough room for
* the requested allocation, but it might still have a useful
* amount of space in it. Once we push it down in the block list,
* we'll never try to allocate more space from it. So, before we
* do that, carve up its free space into chunks that we can put on
* the set's freelists.
*
* Because we can only get here when there's less than
* ALLOC_CHUNK_LIMIT left in the block, this loop cannot iterate
* more than ALLOCSET_NUM_FREELISTS-1 times.
*/
while (availspace >= ((1 << ALLOC_MINBITS) + ALLOC_CHUNKHDRSZ)) {
Size availchunk = availspace - ALLOC_CHUNKHDRSZ;
int a_fidx = opt_AllocSetFreeIndex(availchunk);
/*
* In most cases, we'll get back the index of the next larger
* freelist than the one we need to put this chunk on. The
* exception is when availchunk is exactly a power of 2.
*/
if (availchunk != ((Size)1 << ((unsigned int)a_fidx + ALLOC_MINBITS))) {
a_fidx--;
Assert(a_fidx >= 0);
availchunk = ((Size)1 << ((unsigned int)a_fidx + ALLOC_MINBITS));
}
chunk = (AllocChunk)(block->freeptr);
block->freeptr += (availchunk + ALLOC_CHUNKHDRSZ);
availspace -= (availchunk + ALLOC_CHUNKHDRSZ);
chunk->size = availchunk;
chunk->aset = (void*)set->freelist[a_fidx];
set->freelist[a_fidx] = chunk;
}
/* Mark that we need to create a new block */
block = NULL;
}
}
/*
* Time to create a new regular (multi-chunk) block?
*/
if (block == NULL) {
Size required_size;
/*
* The first such block has size initBlockSize, and we double the
* space in each succeeding block, but not more than maxBlockSize.
*/
blksize = set->nextBlockSize;
set->nextBlockSize <<= 1;
if (set->nextBlockSize > set->maxBlockSize)
set->nextBlockSize = set->maxBlockSize;
/*
* If initBlockSize is less than ALLOC_CHUNK_LIMIT, we could need more
* space... but try to keep it a power of 2.
*/
required_size = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
while (blksize < required_size)
blksize <<= 1;
/* Try to allocate it */
block = (AllocBlock) malloc(blksize);
if (block == NULL) {
return NULL;
}
block->aset = set;
block->freeptr = ((char*)block) + ALLOC_BLOCKHDRSZ;
block->endptr = ((char*)block) + blksize;
block->allocSize = blksize;
set->totalSpace += blksize;
set->freeSpace += blksize - ALLOC_BLOCKHDRSZ;
/*
* If this is the first block of the set, make it the "keeper" block.
* Formerly, a keeper block could only be created during context
* creation, but allowing it to happen here lets us have fast reset
* cycling even for contexts created with minContextSize = 0; that way
* we don't have to force space to be allocated in contexts that might
* never need any space. Don't mark an oversize block as a keeper,
* however.
*/
if (set->keeper == NULL && blksize == set->initBlockSize)
set->keeper = block;
block->prev = NULL;
block->next = set->blocks;
if (block->next)
block->next->prev = block;
set->blocks = block;
}
/*
* OK, do the allocation
*/
chunk = (AllocChunk)(block->freeptr);
block->freeptr += (chunk_size + ALLOC_CHUNKHDRSZ);
set->freeSpace -= (chunk_size + ALLOC_CHUNKHDRSZ);
Assert(block->freeptr <= block->endptr);
chunk->aset = (void*)set;
chunk->size = chunk_size;
return AllocChunkGetPointer(chunk);
#endif
}
/*
* AllocSetFree
* Frees allocated memory; memory is removed from the set.
*/
static void opt_AllocSetFree(MemoryContext context, void* pointer)
{
AllocSet set = (AllocSet)context;
AllocChunk chunk = AllocPointerGetChunk(pointer);
Size tempSize = 0;
AssertArg(AllocSetIsValid(set));
#ifndef ENABLE_MEMORY_CHECK
if (chunk->size > set->allocChunkLimit) {
#endif
/*
* Big chunks are certain to have been allocated as single-chunk
* blocks. Find the containing block and return it to malloc().
*/
AllocBlock block = (AllocBlock)(((char*)chunk) - ALLOC_BLOCKHDRSZ);
/* OK, remove block from aset's list and free it */
if (block->prev)
block->prev->next = block->next;
else
set->blocks = block->next;
if (block->next)
block->next->prev = block->prev;
tempSize = block->allocSize;
set->totalSpace -= block->allocSize;
/* clean the structure of block */
block->aset = NULL;
block->prev = NULL;
block->next = NULL;
block->freeptr = NULL;
block->endptr = NULL;
block->allocSize = 0;
free(block);
#ifndef ENABLE_MEMORY_CHECK
} else {
/* Normal case, put the chunk into appropriate freelist */
int fidx = opt_AllocSetFreeIndex(chunk->size);
chunk->aset = (void*)set->freelist[fidx];
set->freeSpace += chunk->size + ALLOC_CHUNKHDRSZ;
set->freelist[fidx] = chunk;
Assert(chunk->aset != set);
}
#endif
}
/*
* AllocSetRealloc
* Returns new pointer to allocated memory of given size; this memory
* is added to the set. Memory associated with given pointer is copied
* into the new memory, and the old memory is freed.
*/
static void* opt_AllocSetRealloc(MemoryContext context, void* pointer, Size align, Size size, const char* file, int line)
{
AllocSet set = (AllocSet)context;
AllocChunk chunk = AllocPointerGetChunk(pointer);
Size oldsize = chunk->size;
AssertArg(AllocSetIsValid(set));
AssertArg(align == 0);
/*
* Chunk sizes are aligned to power of 2 in AllocSetAlloc(). Maybe the
* allocated area already is >= the new size. (In particular, we always
* fall out here if the requested size is a decrease.)
*/
if (oldsize >= (size + ALLOC_MAGICHDRSZ)) {
size += ALLOC_MAGICHDRSZ;
return pointer;
}
#ifndef ENABLE_MEMORY_CHECK
if (oldsize > set->allocChunkLimit)
#endif
{
/*
* The chunk must have been allocated as a single-chunk block. Find
* the containing block and use realloc() to make it bigger with
* minimum space wastage.
*/
AllocBlock block = (AllocBlock)(((char*)chunk) - ALLOC_BLOCKHDRSZ);
AllocBlock oldBlock = NULL;
Size chksize;
Size blksize;
size += ALLOC_MAGICHDRSZ;
/*
* Try to verify that we have a sane block pointer: it should
* reference the correct aset, and freeptr and endptr should point
* just past the chunk.
*/
/* Do the realloc */
chksize = MAXALIGN(size);
blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
oldBlock = block;
oldsize = block->allocSize;
block = (AllocBlock) realloc(block, blksize);
if (block == NULL) {
return NULL;
}
block->freeptr = block->endptr = ((char*)block) + blksize;
block->allocSize = blksize;
set->totalSpace += blksize - oldsize;
/* Update pointers since block has likely been moved */
chunk = (AllocChunk)(((char*)block) + ALLOC_BLOCKHDRSZ);
if (block->prev)
block->prev->next = block;
else
set->blocks = block;
if (block->next)
block->next->prev = block;
chunk->size = chksize;
return AllocChunkGetPointer(chunk);
}
#ifndef ENABLE_MEMORY_CHECK
else {
/*
* Small-chunk case. We just do this by brute force, ie, allocate a
* new chunk and copy the data. Since we know the existing data isn't
* huge, this won't involve any great memcpy expense, so it's not
* worth being smarter. (At one time we tried to avoid memcpy when it
* was possible to enlarge the chunk in-place, but that turns out to
* misbehave unpleasantly for repeated cycles of
* palloc/repalloc/pfree: the eventually freed chunks go into the
* wrong freelist for the next initial palloc request, and so we leak
* memory indefinitely. See pgsql-hackers archives for 2007-08-11.)
*/
AllocPointer newPointer;
/* allocate new chunk */
newPointer =
opt_AllocSetAlloc((MemoryContext)set, align, size, __FILE__, __LINE__);
/* leave immediately if request was not completed */
if (newPointer == NULL)
return NULL;
/* transfer existing data (certain to fit) */
memcpy(newPointer, pointer, oldsize);
/* free old chunk */
opt_AllocSetFree((MemoryContext)set, pointer);
return newPointer;
}
#endif
}
/*
* AllocSetGetChunkSpace
* Given a currently-allocated chunk, determine the total space
* it occupies (including all memory-allocation overhead).
*/
static Size opt_AllocSetGetChunkSpace(MemoryContext context, void* pointer)
{
AllocChunk chunk = AllocPointerGetChunk(pointer);
return chunk->size + ALLOC_CHUNKHDRSZ;
}
/*
* AllocSetIsEmpty
* Is an allocset empty of any allocated space?
*/
static bool opt_AllocSetIsEmpty(MemoryContext context)
{
/*
* For now, we say "empty" only if the context is new or just reset. We
* could examine the freelists to determine if all space has been freed,
* but it's not really worth the trouble for present uses of this
* functionality.
*/
if (context->isReset)
return true;
return false;
}
/*
* AllocSetStats
* Displays stats about memory consumption of an allocset.
*/
static void opt_AllocSetStats(MemoryContext context, int level)
{
AllocSet set = (AllocSet)context;
long nblocks = 0;
long nchunks = 0;
long totalspace = 0;
long freespace = 0;
AllocBlock block;
AllocChunk chunk;
int fidx;
int i;
for (block = set->blocks; block != NULL; block = block->next) {
nblocks++;
totalspace += block->endptr - ((char*)block);
freespace += block->endptr - block->freeptr;
}
for (fidx = 0; fidx < ALLOCSET_NUM_FREELISTS; fidx++) {
for (chunk = set->freelist[fidx]; chunk != NULL; chunk = (AllocChunk)chunk->aset) {
nchunks++;
freespace += chunk->size + ALLOC_CHUNKHDRSZ;
}
}
for (i = 0; i < level; i++)
fprintf(stderr, " ");
fprintf(stderr,
"%s: %ld total in %ld blocks; %ld free (%ld chunks); %ld used\n",
set->header.name,
totalspace,
nblocks,
freespace,
nchunks,
totalspace - freespace);
}

View File

@ -0,0 +1,336 @@
/* -------------------------------------------------------------------------
*
* std_mcxt.cpp
* openGauss memory context management code.
*
* This module handles context management operations that are independent
* of the particular kind of context being operated on. It calls
* context-type-specific operations via the function pointers in a
* context's MemoryContextMethods struct.
*
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/backend/utils/mmgr/mcxt.c
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "postmaster/postmaster.h"
#include "utils/memutils.h"
#include "utils/memtrace.h"
#include "pgxc/pgxc.h"
#include "miscadmin.h"
#include "storage/proc.h"
#include "storage/cstore/cstore_mem_alloc.h"
#include "threadpool/threadpool.h"
#include "tcop/tcopprot.h"
#include "workload/workload.h"
#include "pgstat.h"
/*****************************************************************************
* GLOBAL MEMORY *
*****************************************************************************/
void* opt_MemoryAllocFromContext(MemoryContext context, Size size)
{
void* ret = NULL;
context->isReset = false;
ret = (*context->methods->alloc)(context, 0, size, __FILE__, __LINE__);
if (ret == NULL)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_LOGICAL_MEMORY),
errmsg("memory is temporarily unavailable"),
errdetail("Failed on request of size %lu bytes under queryid %lu.",
(unsigned long)size,
u_sess->debug_query_id)));
return ret;
}
static void opt_TagMemoryContextSessionId(MemoryContext node, MemoryContext parent)
{
uint64 sessId = 0;
if (parent) {
if (parent->session_id > 0) {
if (u_sess && u_sess->session_id > 0) {
Assert(parent->is_shared || parent->session_id == u_sess->session_id);
}
sessId = parent->session_id;
} else {
Assert(parent->is_shared || parent->thread_id == gs_thread_self());
}
} else {
if (u_sess && u_sess->session_id)
sessId = u_sess->session_id;
}
node->session_id = sessId;
}
/* --------------------
* MemoryContextCreate
* Context-type-independent part of context creation.
*
* This is only intended to be called by context-type-specific
* context creation routines, not by the unwashed masses.
*
* The context creation procedure is a little bit tricky because
* we want to be sure that we don't leave the context tree invalid
* in case of failure (such as insufficient memory to allocate the
* context node itself). The procedure goes like this:
* 1. Context-type-specific routine first calls MemoryContextCreate(),
* passing the appropriate tag/size/methods values (the methods
* pointer will ordinarily point to statically allocated data).
* The parent and name parameters usually come from the caller.
* 2. MemoryContextCreate() attempts to allocate the context node,
* plus space for the name. If this fails we can ereport() with no
* damage done.
* 3. We fill in all of the type-independent MemoryContext fields.
* 4. We call the type-specific init routine (using the methods pointer).
* The init routine is required to make the node minimally valid
* with zero chance of failure --- it can't allocate more memory,
* for example.
* 5. Now we have a minimally valid node that can behave correctly
* when told to reset or delete itself. We link the node to its
* parent (if any), making the node part of the context tree.
* 6. We return to the context-type-specific routine, which finishes
* up type-specific initialization. This routine can now do things
* that might fail (like allocate more memory), so long as it's
* sure the node is left in a state that delete will handle.
*
* This protocol doesn't prevent us from leaking memory if step 6 fails
* during creation of a top-level context, since there's no parent link
* in that case. However, if you run out of memory while you're building
* a top-level context, you might as well go home anyway...
*
* Normally, the context node and the name are allocated from
* t_thrd.top_mem_cxt (NOT from the parent context, since the node must
* survive resets of its parent context!). However, this routine is itself
* used to create t_thrd.top_mem_cxt! If we see that t_thrd.top_mem_cxt is NULL,
* we assume we are creating t_thrd.top_mem_cxt and use malloc() to allocate
* the node.
*
* Note that the name field of a MemoryContext does not point to
* separately-allocated storage, so it should not be freed at context
* deletion.
* --------------------
*/
MemoryContext opt_MemoryContextCreate(MemoryContext node, NodeTag tag,
MemoryContextMethods *methods, MemoryContext parent, const char* name)
{
node->type = tag;
node->parent = NULL; /* for the moment */
node->firstchild = NULL;
node->prevchild = NULL;
node->nextchild = NULL;
node->isReset = true;
node->is_sealed = false;
node->is_shared = false;
node->methods = methods;
node->name = (char *)name;
node->cell.data.ptr_value = (void*)node;
node->cell.next = NULL;
node->thread_id = gs_thread_self();
opt_TagMemoryContextSessionId(node, parent);
/* OK to link node to parent (if any) */
/* Could use MemoryContextSetParent here, but doesn't seem worthwhile */
if (parent) {
node->parent = parent;
node->nextchild = parent->firstchild;
if (parent->firstchild != NULL)
parent->firstchild->prevchild = node;
parent->firstchild = node;
node->level = parent->level + 1;
} else {
node->nextchild = NULL;
node->level = 0;
}
/* Return to type-specific creation routine to finish up */
return node;
}
void* opt_MemoryContextAllocZeroAlignedDebug(MemoryContext context, Size size, const char* file, int line)
{
void* ret = NULL;
AssertArg(IsOptAllocSetContext(context));
context->isReset = false;
ret = (*context->methods->alloc)(context, 0, size, file, line);
if (ret == NULL)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_LOGICAL_MEMORY),
errmsg("memory is temporarily unavailable"),
errdetail("Failed on request of size %lu bytes under queryid %lu in %s:%d.",
(unsigned long)size,
u_sess->debug_query_id,
file,
line)));
MemSetLoop(ret, 0, size);
return ret;
}
void* opt_MemoryContextAllocZeroDebug(MemoryContext context, Size size, const char* file, int line)
{
void* ret = NULL;
AssertArg(IsOptAllocSetContext(context));
context->isReset = false;
ret = (*context->methods->alloc)(context, 0, size, file, line);
if (ret == NULL)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_LOGICAL_MEMORY),
errmsg("memory is temporarily unavailable"),
errdetail("Failed on request of size %lu bytes under queryid %lu in %s:%d.",
(unsigned long)size,
u_sess->debug_query_id,
file,
line)));
MemSetAligned(ret, 0, size);
return ret;
}
void opt_MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
{
AssertArg(IsOptAllocSetContext(context));
AssertArg(context != new_parent);
if (new_parent == context->parent)
return;
/* Delink from existing parent, if any */
if (context->parent) {
MemoryContext parent = context->parent;
if (context->prevchild != NULL)
context->prevchild->nextchild = context->nextchild;
else {
Assert(parent->firstchild == context);
parent->firstchild = context->nextchild;
}
if (context->nextchild != NULL)
context->nextchild->prevchild = context->prevchild;
}
/* And relink */
if (new_parent) {
AssertArg(IsOptAllocSetContext(new_parent));
context->parent = new_parent;
context->prevchild = NULL;
context->nextchild = new_parent->firstchild;
if (new_parent->firstchild != NULL)
new_parent->firstchild->prevchild = context;
new_parent->firstchild = context;
} else {
context->parent = NULL;
context->prevchild = NULL;
context->nextchild = NULL;
}
}
void opt_MemoryContextDeleteInternal(MemoryContext context, List *context_list)
{
AssertArg(IsOptAllocSetContext(context));
/* save a function call in common case where there are no children */
if (context->firstchild != NULL)
MemoryContextDeleteChildren(context, context_list);
opt_MemoryContextSetParent(context, NULL);
context->methods->delete_context(context);
}
void opt_MemoryContextReset(MemoryContext context)
{
AssertArg(IsOptAllocSetContext(context));
/* save a function call in common case where there are no children */
if (context->firstchild != NULL)
MemoryContextResetChildren(context);
/* Nothing to do if no pallocs since startup or last reset */
if (!context->isReset) {
(*context->methods->reset)(context);
context->isReset = true;
}
}
/*
* pfree
* Release an allocated chunk.
*/
void
opt_pfree(void *pointer)
{
MemoryContext context = GetMemoryChunkContext(pointer);
context->methods->free_p(context, pointer);
}
void*
opt_repallocDebug(void* pointer, Size size, const char *file, int line)
{
MemoryContext context;
void* ret = NULL;
Assert(pointer != NULL);
Assert(pointer == (void*)MAXALIGN(pointer));
context = GetMemoryChunkContext(pointer);
/* isReset must be false already */
Assert(!context->isReset);
ret = (*context->methods->realloc)(context, pointer, 0, size, file, line);
if (unlikely(ret == NULL))
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_LOGICAL_MEMORY),
errmsg("memory is temporarily unavailable"),
errdetail("Failed on request of size %lu bytes under queryid %lu in %s:%d.",
(unsigned long)size,
u_sess->debug_query_id,
file,
line)));
return ret;
}
void*
opt_repalloc_noexcept_Debug(void* pointer, Size size, const char *file, int line)
{
MemoryContext context;
void* ret = NULL;
Assert(pointer != NULL);
Assert(pointer == (void*)MAXALIGN(pointer));
context = GetMemoryChunkContext(pointer);
/* isReset must be false already */
Assert(!context->isReset);
ret = (*context->methods->realloc)(context, pointer, 0, size, file, line);
return ret;
}

View File

@ -68,6 +68,7 @@ extern void* MemoryContextAllocZeroAligned(MemoryContext context, Size size);
: MemoryContextAllocZero(CurrentMemoryContext, sz))
extern void pfree(void* pointer);
extern void opt_pfree(void* pointer);
extern void* repalloc(void* pointer, Size size);

View File

@ -47,6 +47,7 @@ typedef struct knl_instance_attr_memory {
int max_process_memory;
bool enable_memory_context_check_debug;
int global_syscache_threshold;
bool disable_memory_stats;
} knl_instance_attr_memory;
#endif /* SRC_INCLUDE_KNL_KNL_INSTANCE_ATTR_MEMORY_H_ */

View File

@ -148,6 +148,7 @@ typedef struct AllocSetContext {
/* maximum memory allocation of MemoryContext.For more information,we could see @StackSetContext too. */
Size maxSpaceSize;
int freeListIndex;
MemoryTrack track; /* used to track the memory allocation information */
} AllocSetContext;
@ -278,6 +279,9 @@ extern MemoryProtectFuncDef GenericFunctions;
extern MemoryProtectFuncDef SessionFunctions;
extern MemoryProtectFuncDef SharedFunctions;
#define IsOptAllocSetContext(cxt) \
((cxt) != NULL && (IsA((cxt), OptAllocSetContext)))
/*
* MemoryContextIsValid
* True iff memory context is valid.
@ -288,7 +292,7 @@ extern MemoryProtectFuncDef SharedFunctions;
((context) != NULL && \
(IsA((context), AllocSetContext) || IsA((context), AsanSetContext) || IsA((context), StackAllocSetContext) || \
IsA((context), SharedAllocSetContext) || IsA((context), MemalignAllocSetContext) || \
IsA((context), MemalignSharedAllocSetContext)))
IsA((context), MemalignSharedAllocSetContext) || IsA((context), OptAllocSetContext)))
#define AllocSetContextUsedSpace(aset) ((aset)->totalSpace - (aset)->freeSpace)

View File

@ -359,6 +359,7 @@ typedef enum NodeTag {
*/
T_MemoryContext = 600,
T_AllocSetContext,
T_OptAllocSetContext,
T_AsanSetContext,
T_StackAllocSetContext,
T_SharedAllocSetContext,

View File

@ -94,12 +94,15 @@ extern THR_LOCAL PGDLLIMPORT MemoryContext ErrorContext;
*/
extern void MemoryContextInit(void);
extern void MemoryContextReset(MemoryContext context);
extern void opt_MemoryContextReset(MemoryContext context);
extern void MemoryContextDelete(MemoryContext context);
extern void opt_MemoryContextDeleteInternal(MemoryContext context, List* context_list = NULL);
extern void MemoryContextResetChildren(MemoryContext context);
extern void MemoryContextDeleteChildren(MemoryContext context, List* context_list = NULL);
extern void MemoryContextDestroyAtThreadExit(MemoryContext context);
extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
extern void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent);
extern void opt_MemoryContextSetParent(MemoryContext context, MemoryContext new_parent);
extern Size GetMemoryChunkSpace(void* pointer);
extern MemoryContext GetMemoryChunkContext(void* pointer);
extern MemoryContext MemoryContextGetParent(MemoryContext context);
@ -131,6 +134,8 @@ extern MemoryContext MemoryContextCreate(
extern MemoryContext MemoryContextCreate(
NodeTag tag, Size size, MemoryContextMethods* methods, MemoryContext parent, const char* name);
extern MemoryContext opt_MemoryContextCreate(MemoryContext node, NodeTag tag,
MemoryContextMethods *methods, MemoryContext parent, const char* name);
/*
* Memory-context-type-specific functions
*/
@ -140,6 +145,8 @@ extern MemoryContext MemoryContextCreate(
extern MemoryContext AllocSetContextCreate(MemoryContext parent, const char* name, Size minContextSize,
Size initBlockSize, Size maxBlockSize, MemoryContextType type = STANDARD_CONTEXT,
Size maxSize = DEFAULT_MEMORY_CONTEXT_MAX_SIZE, bool isSession = false);
extern MemoryContext opt_AllocSetContextCreate(MemoryContext parent,
const char* name, Size minContextSize, Size initBlockSize, Size maxBlockSize);
/*
* Recommended default alloc parameters, suitable for "ordinary" contexts

View File

@ -87,12 +87,15 @@ extern THR_LOCAL PGDLLIMPORT MemoryContext TopMemoryContext;
* Fundamental memory-allocation operations (more are in utils/memutils.h)
*/
extern void* MemoryAllocFromContext(MemoryContext context, Size size, const char* file, int line);
extern void* opt_MemoryAllocFromContext(MemoryContext context, Size size);
extern void* MemoryContextAllocDebug(MemoryContext context, Size size, const char* file, int line);
extern void* MemoryContextAllocHugeDebug(MemoryContext context, Size size, const char* file, int line);
extern void* repallocHugeDebug(void* pointer, Size size, const char* file, int line);
extern void* MemoryContextAllocZeroDebug(MemoryContext context, Size size, const char* file, int line);
extern void* opt_MemoryContextAllocZeroDebug(MemoryContext context, Size size, const char* file, int line);
extern void* MemoryContextAllocZeroAlignedDebug(MemoryContext context, Size size, const char* file, int line);
extern void* MemoryContextAllocExtendedDebug(MemoryContext context, Size size, int flags, const char* file, int line);
extern void* opt_MemoryContextAllocZeroAlignedDebug(MemoryContext context, Size size, const char* file, int line);
extern char* MemoryContextStrdupDebug(MemoryContext context, const char* string, const char* file, int line);
extern void* MemoryContextMemalignAllocDebug(MemoryContext context, Size align, Size size, const char* file, int line);
extern void MemoryContextMemalignFree(MemoryContext context, void* pointer);
@ -135,6 +138,7 @@ extern THR_LOCAL MemoryContext AlignMemoryContext;
: MemoryContextAllocZero(CurrentMemoryContext, sz))
extern void pfree(void* pointer);
extern void opt_pfree(void* pointer);
template <typename T>
bool isConst(T& x)
@ -161,7 +165,9 @@ bool isConst(T const& x)
#define pfree_ext(__p) FREE_POINTER(__p)
extern void* repallocDebug(void* pointer, Size size, const char* file, int line);
extern void* opt_repallocDebug(void* pointer, Size size, const char* file, int line);
extern void* repalloc_noexcept_Debug(void* pointer, Size size, const char* file, int line);
extern void* opt_repalloc_noexcept_Debug(void* pointer, Size size, const char* file, int line);
/*
* MemoryContextSwitchTo can't be a macro in standard C compilers.

View File

@ -5412,7 +5412,7 @@ static void CheckCleanCodeWarningInfo(const int baseNum, const int currentNum,
return;
}
#define BASE_GLOBAL_VARIABLE_NUM 220
#define BASE_GLOBAL_VARIABLE_NUM 221
#define CMAKE_CMD_BUF_LEN 1000