46#define Generation_BLOCKHDRSZ MAXALIGN(sizeof(GenerationBlock))
47#define Generation_CHUNKHDRSZ sizeof(MemoryChunk)
48#define FIRST_BLOCKHDRSZ (MAXALIGN(sizeof(GenerationContext)) + \
49 Generation_BLOCKHDRSZ)
51#define Generation_CHUNK_FRACTION 8
104#define GenerationIsValid(set) \
105 ((set) && IsA(set, GenerationContext))
111#define GenerationBlockIsValid(block) \
112 ((block) && GenerationIsValid((block)->context))
118#define GenerationBlockIsEmpty(b) ((b)->nchunks == 0)
125#define ExternalChunkGetBlock(chunk) \
126 (GenerationBlock *) ((char *) chunk - Generation_BLOCKHDRSZ)
129#define KeeperBlock(set) \
130 ((GenerationBlock *) (((char *) set) + \
131 MAXALIGN(sizeof(GenerationContext))))
134#define IsKeeperBlock(set, block) ((block) == (KeeperBlock(set)))
175 "sizeof(MemoryChunk) is not maxaligned");
189 initBlockSize >= 1024);
191 maxBlockSize >= initBlockSize &&
193 Assert(minContextSize == 0 ||
194 (minContextSize ==
MAXALIGN(minContextSize) &&
195 minContextSize >= 1024 &&
196 minContextSize <= maxBlockSize));
202 if (minContextSize != 0)
203 allocSize =
Max(allocSize, minContextSize);
205 allocSize =
Max(allocSize, initBlockSize);
216 (
errcode(ERRCODE_OUT_OF_MEMORY),
218 errdetail(
"Failed while creating memory context \"%s\".",
298#ifdef MEMORY_CONTEXT_CHECKING
300 GenerationCheck(context);
375#ifdef MEMORY_CONTEXT_CHECKING
407#ifdef MEMORY_CONTEXT_CHECKING
408 chunk->requested_size = size;
410 Assert(size < chunk_size);
413#ifdef RANDOMIZE_ALLOCATED_MEMORY
455#ifdef MEMORY_CONTEXT_CHECKING
456 chunk->requested_size = size;
458 Assert(size < chunk_size);
461#ifdef RANDOMIZE_ALLOCATED_MEMORY
505 if (blksize < required_size)
562#ifdef MEMORY_CONTEXT_CHECKING
603 if (freeblock != NULL &&
608 set->
block = freeblock;
644 block->
endptr = ((
char *) block) + blksize;
658#if defined(USE_VALGRIND) || defined(CLOBBER_FREED_MEMORY)
662#ifdef CLOBBER_FREED_MEMORY
663 wipe_mem(datastart, block->
freeptr - datastart);
702#ifdef CLOBBER_FREED_MEMORY
703 wipe_mem(block, block->
blksize);
723#if (defined(MEMORY_CONTEXT_CHECKING) && defined(USE_ASSERT_CHECKING)) \
724 || defined(CLOBBER_FREED_MEMORY)
740 elog(
ERROR,
"could not find block containing chunk %p", chunk);
742#if (defined(MEMORY_CONTEXT_CHECKING) && defined(USE_ASSERT_CHECKING)) \
743 || defined(CLOBBER_FREED_MEMORY)
744 chunksize = block->
endptr - (
char *) pointer;
758#if (defined(MEMORY_CONTEXT_CHECKING) && defined(USE_ASSERT_CHECKING)) \
759 || defined(CLOBBER_FREED_MEMORY)
764#ifdef MEMORY_CONTEXT_CHECKING
766 Assert(chunk->requested_size < chunksize);
767 if (!sentinel_ok(pointer, chunk->requested_size))
768 elog(
WARNING,
"detected write past chunk end in %s %p",
772#ifdef CLOBBER_FREED_MEMORY
773 wipe_mem(pointer, chunksize);
776#ifdef MEMORY_CONTEXT_CHECKING
849 elog(
ERROR,
"could not find block containing chunk %p", chunk);
851 oldsize = block->
endptr - (
char *) pointer;
869#ifdef MEMORY_CONTEXT_CHECKING
871 Assert(chunk->requested_size < oldsize);
872 if (!sentinel_ok(pointer, chunk->requested_size))
873 elog(
WARNING,
"detected write past chunk end in %s %p",
887#ifdef MEMORY_CONTEXT_CHECKING
894#ifdef MEMORY_CONTEXT_CHECKING
895 Size oldrequest = chunk->requested_size;
897#ifdef RANDOMIZE_ALLOCATED_MEMORY
899 if (size > oldrequest)
900 randomize_mem((
char *) pointer + oldrequest,
904 chunk->requested_size = size;
910 if (size > oldrequest)
918 set_sentinel(pointer, size);
940 if (newPointer == NULL)
956#ifdef MEMORY_CONTEXT_CHECKING
957 oldsize = chunk->requested_size;
963 memcpy(newPointer, pointer, oldsize);
1015 chunksize = block->
endptr - (
char *) pointer;
1069 Size nfreechunks = 0;
1085 nfreechunks += block->
nfree;
1092 char stats_string[200];
1094 snprintf(stats_string,
sizeof(stats_string),
1095 "%zu total in %zu blocks (%zu chunks); %zu free (%zu chunks); %zu used",
1096 totalspace, nblocks, nchunks, freespace,
1097 nfreechunks, totalspace - freespace);
1098 printfunc(context, passthru, stats_string, print_to_stderr);
1111#ifdef MEMORY_CONTEXT_CHECKING
1127 Size total_allocated = 0;
1136 bool has_external_chunk =
false;
1138 total_allocated += block->
blksize;
1145 elog(
WARNING,
"problem in Generation %s: number of free chunks %d in block %p exceeds %d allocated",
1150 elog(
WARNING,
"problem in Generation %s: bogus context link in block %p",
1158 while (ptr < block->freeptr)
1171 has_external_chunk =
true;
1185 if (chunkblock != block)
1186 elog(
WARNING,
"problem in Generation %s: bogus block link in block %p, chunk %p",
1187 name, block, chunk);
1194 if (chunksize < chunk->requested_size ||
1196 elog(
WARNING,
"problem in Generation %s: bogus chunk size in block %p, chunk %p",
1197 name, block, chunk);
1200 Assert(chunk->requested_size < chunksize);
1202 elog(
WARNING,
"problem in Generation %s: detected write past chunk end in block %p, chunk %p",
1203 name, block, chunk);
1217 if (nchunks != block->
nchunks)
1218 elog(
WARNING,
"problem in Generation %s: number of allocated chunks %d in block %p does not match header %d",
1221 if (nfree != block->
nfree)
1222 elog(
WARNING,
"problem in Generation %s: number of free chunks %d in block %p does not match header %d",
1225 if (has_external_chunk && nchunks > 1)
1226 elog(
WARNING,
"problem in Generation %s: external chunk on non-dedicated block %p",
#define StaticAssertDecl(condition, errmessage)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
void * GenerationRealloc(void *pointer, Size size, int flags)
static void GenerationBlockInit(GenerationContext *context, GenerationBlock *block, Size blksize)
static pg_noinline void * GenerationAllocLarge(MemoryContext context, Size size, int flags)
#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
static void * GenerationAllocChunkFromBlock(MemoryContext context, GenerationBlock *block, Size size, Size chunk_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 GenerationBlockIsEmpty(b)
#define Generation_BLOCKHDRSZ
MemoryContext GenerationContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
static pg_noinline void * GenerationAllocFromNewBlock(MemoryContext context, Size size, int flags, Size chunk_size)
void GenerationDelete(MemoryContext context)
#define GenerationIsValid(set)
void * GenerationAlloc(MemoryContext context, Size size, int flags)
#define ExternalChunkGetBlock(chunk)
Assert(PointerIsAligned(start, uint64))
#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)
static dlist_node * dlist_head_node(dlist_head *head)
#define dlist_foreach_modify(iter, lhead)
static bool dlist_is_empty(const dlist_head *head)
#define dlist_container(type, membername, ptr)
void MemoryContextCreate(MemoryContext node, NodeTag tag, MemoryContextMethodID method_id, MemoryContext parent, const char *name)
MemoryContext TopMemoryContext
void MemoryContextStats(MemoryContext context)
void * MemoryContextAllocationFailure(MemoryContext context, Size size, int flags)
#define VALGRIND_DESTROY_MEMPOOL(context)
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
#define VALGRIND_CREATE_MEMPOOL(context, redzones, zeroed)
#define VALGRIND_MEMPOOL_ALLOC(context, addr, size)
#define VALGRIND_MEMPOOL_TRIM(context, addr, size)
#define VALGRIND_MEMPOOL_FREE(context, addr)
#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)
static void MemoryContextCheckSize(MemoryContext context, Size size, int flags)
#define MEMORYCHUNK_MAX_BLOCKOFFSET
#define MEMORYCHUNK_MAX_VALUE
static Size MemoryChunkGetValue(MemoryChunk *chunk)
#define MemoryChunkGetPointer(c)
static bool MemoryChunkIsExternal(MemoryChunk *chunk)
static void * MemoryChunkGetBlock(MemoryChunk *chunk)
static void MemoryChunkSetHdrMaskExternal(MemoryChunk *chunk, MemoryContextMethodID methodid)
#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