46 #define Generation_BLOCKHDRSZ MAXALIGN(sizeof(GenerationBlock))
47 #define Generation_CHUNKHDRSZ sizeof(MemoryChunk)
49 #define Generation_CHUNK_FRACTION 8
104 #define GenerationIsValid(set) \
105 (PointerIsValid(set) && IsA(set, GenerationContext))
111 #define GenerationBlockIsValid(block) \
112 (PointerIsValid(block) && GenerationIsValid((block)->context))
119 #define ExternalChunkGetBlock(chunk) \
120 (GenerationBlock *) ((char *) chunk - Generation_BLOCKHDRSZ)
123 #define KeeperBlock(set) \
124 ((GenerationBlock *) (((char *) set) + \
125 MAXALIGN(sizeof(GenerationContext))))
128 #define IsKeeperBlock(set, block) ((block) == (KeeperBlock(set)))
170 "sizeof(MemoryChunk) is not maxaligned");
184 initBlockSize >= 1024);
186 maxBlockSize >= initBlockSize &&
188 Assert(minContextSize == 0 ||
189 (minContextSize ==
MAXALIGN(minContextSize) &&
190 minContextSize >= 1024 &&
191 minContextSize <= maxBlockSize));
197 if (minContextSize != 0)
198 allocSize =
Max(allocSize, minContextSize);
200 allocSize =
Max(allocSize, initBlockSize);
211 (
errcode(ERRCODE_OUT_OF_MEMORY),
213 errdetail(
"Failed while creating memory context \"%s\".",
285 #ifdef MEMORY_CONTEXT_CHECKING
287 GenerationCheck(context);
355 #ifdef MEMORY_CONTEXT_CHECKING
388 #ifdef MEMORY_CONTEXT_CHECKING
389 chunk->requested_size = size;
391 Assert(size < chunk_size);
394 #ifdef RANDOMIZE_ALLOCATED_MEMORY
435 if (freeblock != NULL &&
467 if (blksize < required_size)
506 #ifdef MEMORY_CONTEXT_CHECKING
507 chunk->requested_size = size;
509 Assert(size < chunk_size);
512 #ifdef RANDOMIZE_ALLOCATED_MEMORY
542 block->
endptr = ((
char *) block) + blksize;
566 #if defined(USE_VALGRIND) || defined(CLOBBER_FREED_MEMORY)
570 #ifdef CLOBBER_FREED_MEMORY
571 wipe_mem(datastart, block->
freeptr - datastart);
610 #ifdef CLOBBER_FREED_MEMORY
611 wipe_mem(block, block->
blksize);
628 #if (defined(MEMORY_CONTEXT_CHECKING) && defined(USE_ASSERT_CHECKING)) \
629 || defined(CLOBBER_FREED_MEMORY)
645 elog(
ERROR,
"could not find block containing chunk %p", chunk);
647 #if (defined(MEMORY_CONTEXT_CHECKING) && defined(USE_ASSERT_CHECKING)) \
648 || defined(CLOBBER_FREED_MEMORY)
649 chunksize = block->
endptr - (
char *) pointer;
663 #if (defined(MEMORY_CONTEXT_CHECKING) && defined(USE_ASSERT_CHECKING)) \
664 || defined(CLOBBER_FREED_MEMORY)
669 #ifdef MEMORY_CONTEXT_CHECKING
671 Assert(chunk->requested_size < chunksize);
672 if (!sentinel_ok(pointer, chunk->requested_size))
673 elog(
WARNING,
"detected write past chunk end in %s %p",
677 #ifdef CLOBBER_FREED_MEMORY
678 wipe_mem(pointer, chunksize);
681 #ifdef MEMORY_CONTEXT_CHECKING
718 if (set->
block == block)
758 elog(
ERROR,
"could not find block containing chunk %p", chunk);
760 oldsize = block->
endptr - (
char *) pointer;
778 #ifdef MEMORY_CONTEXT_CHECKING
780 Assert(chunk->requested_size < oldsize);
781 if (!sentinel_ok(pointer, chunk->requested_size))
782 elog(
WARNING,
"detected write past chunk end in %s %p",
798 #ifdef MEMORY_CONTEXT_CHECKING
799 Size oldrequest = chunk->requested_size;
801 #ifdef RANDOMIZE_ALLOCATED_MEMORY
803 if (size > oldrequest)
804 randomize_mem((
char *) pointer + oldrequest,
808 chunk->requested_size = size;
814 if (size > oldrequest)
822 set_sentinel(pointer, size);
844 if (newPointer == NULL)
860 #ifdef MEMORY_CONTEXT_CHECKING
861 oldsize = chunk->requested_size;
867 memcpy(newPointer, pointer, oldsize);
919 chunksize = block->
endptr - (
char *) pointer;
973 Size nfreechunks = 0;
989 nfreechunks += block->
nfree;
996 char stats_string[200];
998 snprintf(stats_string,
sizeof(stats_string),
999 "%zu total in %zu blocks (%zu chunks); %zu free (%zu chunks); %zu used",
1000 totalspace, nblocks, nchunks, freespace,
1001 nfreechunks, totalspace - freespace);
1002 printfunc(context, passthru, stats_string, print_to_stderr);
1015 #ifdef MEMORY_CONTEXT_CHECKING
1031 Size total_allocated = 0;
1040 bool has_external_chunk =
false;
1042 total_allocated += block->
blksize;
1049 elog(
WARNING,
"problem in Generation %s: number of free chunks %d in block %p exceeds %d allocated",
1054 elog(
WARNING,
"problem in Generation %s: bogus context link in block %p",
1062 while (ptr < block->freeptr)
1075 has_external_chunk =
true;
1089 if (chunkblock != block)
1090 elog(
WARNING,
"problem in Generation %s: bogus block link in block %p, chunk %p",
1091 name, block, chunk);
1098 if (chunksize < chunk->requested_size ||
1100 elog(
WARNING,
"problem in Generation %s: bogus chunk size in block %p, chunk %p",
1101 name, block, chunk);
1104 Assert(chunk->requested_size < chunksize);
1106 elog(
WARNING,
"problem in Generation %s: detected write past chunk end in block %p, chunk %p",
1107 name, block, chunk);
1121 if (nchunks != block->
nchunks)
1122 elog(
WARNING,
"problem in Generation %s: number of allocated chunks %d in block %p does not match header %d",
1125 if (nfree != block->
nfree)
1126 elog(
WARNING,
"problem in Generation %s: number of free chunks %d in block %p does not match header %d",
1129 if (has_external_chunk && nchunks > 1)
1130 elog(
WARNING,
"problem in Generation %s: external chunk on non-dedicated block %p",
#define StaticAssertDecl(condition, errmessage)
elog(ERROR, "%s: %s", p2, msg)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
static void GenerationBlockInit(GenerationContext *context, GenerationBlock *block, Size blksize)
#define IsKeeperBlock(set, block)
#define Generation_CHUNK_FRACTION
void GenerationReset(MemoryContext context)
static Size GenerationBlockFreeBytes(GenerationBlock *block)
static void GenerationBlockFree(GenerationContext *set, GenerationBlock *block)
void GenerationFree(void *pointer)
MemoryContext GenerationGetChunkContext(void *pointer)
Size GenerationGetChunkSpace(void *pointer)
struct GenerationContext GenerationContext
#define Generation_CHUNKHDRSZ
void * GenerationAlloc(MemoryContext context, Size size)
static void GenerationBlockMarkEmpty(GenerationBlock *block)
#define GenerationBlockIsValid(block)
bool GenerationIsEmpty(MemoryContext context)
void GenerationStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
#define Generation_BLOCKHDRSZ
MemoryContext GenerationContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
static bool GenerationBlockIsEmpty(GenerationBlock *block)
void * GenerationRealloc(void *pointer, Size size)
void GenerationDelete(MemoryContext context)
#define GenerationIsValid(set)
#define ExternalChunkGetBlock(chunk)
#define dlist_foreach(iter, lhead)
static void dlist_init(dlist_head *head)
static bool dlist_has_next(const dlist_head *head, const dlist_node *node)
static void dlist_delete(dlist_node *node)
static void dlist_push_head(dlist_head *head, dlist_node *node)
#define dlist_foreach_modify(iter, lhead)
static bool dlist_is_empty(const dlist_head *head)
static dlist_node * dlist_head_node(dlist_head *head)
#define dlist_container(type, membername, ptr)
Assert(fmt[strlen(fmt) - 1] !='\n')
void MemoryContextCreate(MemoryContext node, NodeTag tag, MemoryContextMethodID method_id, MemoryContext parent, const char *name)
MemoryContext TopMemoryContext
void MemoryContextStats(MemoryContext context)
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
#define VALGRIND_MAKE_MEM_UNDEFINED(addr, size)
void(* MemoryStatsPrintFunc)(MemoryContext context, void *passthru, const char *stats_string, bool print_to_stderr)
#define AllocHugeSizeIsValid(size)
#define MEMORYCHUNK_MAX_BLOCKOFFSET
#define MEMORYCHUNK_MAX_VALUE
static Size MemoryChunkGetValue(MemoryChunk *chunk)
#define MemoryChunkGetPointer(c)
static bool MemoryChunkIsExternal(MemoryChunk *chunk)
static void MemoryChunkSetHdrMaskExternal(MemoryChunk *chunk, MemoryContextMethodID methodid)
static void * MemoryChunkGetBlock(MemoryChunk *chunk)
#define PointerGetMemoryChunk(p)
static void MemoryChunkSetHdrMask(MemoryChunk *chunk, void *block, Size value, MemoryContextMethodID methodid)
struct MemoryContextData * MemoryContext
#define pg_nextpower2_size_t
GenerationContext * context
GenerationBlock * freeblock