83#define ALLOC_MINBITS 3
84#define ALLOCSET_NUM_FREELISTS 11
85#define ALLOC_CHUNK_LIMIT (1 << (ALLOCSET_NUM_FREELISTS-1+ALLOC_MINBITS))
87#define ALLOC_CHUNK_FRACTION 4
104#define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
105#define ALLOC_CHUNKHDRSZ sizeof(MemoryChunk)
106#define FIRST_BLOCKHDRSZ (MAXALIGN(sizeof(AllocSetContext)) + \
134#define GetFreeListLink(chkptr) \
135 (AllocFreeListLink *) ((char *) (chkptr) + ALLOC_CHUNKHDRSZ)
138#define FreeListIdxIsValid(fidx) \
139 ((fidx) >= 0 && (fidx) < ALLOCSET_NUM_FREELISTS)
142#define GetChunkSizeFromFreeListIdx(fidx) \
143 ((((Size) 1) << ALLOC_MINBITS) << (fidx))
196#define AllocSetIsValid(set) \
197 ((set) && IsA(set, AllocSetContext))
203#define AllocBlockIsValid(block) \
204 ((block) && AllocSetIsValid((block)->aset))
211#define ExternalChunkGetBlock(chunk) \
212 (AllocBlock) ((char *) chunk - ALLOC_BLOCKHDRSZ)
237#define MAX_FREE_CONTEXTS 100
240#define KeeperBlock(set) \
241 ((AllocBlock) (((char *) set) + MAXALIGN(sizeof(AllocSetContext))))
244#define IsKeeperBlock(set, block) ((block) == (KeeperBlock(set)))
296#ifdef HAVE_BITSCAN_REVERSE
304 "ALLOC_CHUNK_LIMIT must be less than 64kB");
356 "sizeof(MemoryChunk) is not maxaligned");
359 "sizeof(AllocFreeListLink) larger than minimum allocation size");
374 initBlockSize >= 1024);
376 maxBlockSize >= initBlockSize &&
378 Assert(minContextSize == 0 ||
379 (minContextSize ==
MAXALIGN(minContextSize) &&
380 minContextSize >= 1024 &&
381 minContextSize <= maxBlockSize));
400 if (freeListIndex >= 0)
431 if (minContextSize != 0)
432 firstBlockSize =
Max(firstBlockSize, minContextSize);
434 firstBlockSize =
Max(firstBlockSize, initBlockSize);
446 (
errcode(ERRCODE_OUT_OF_MEMORY),
448 errdetail(
"Failed while creating memory context \"%s\".",
476 block->
endptr = ((
char *) set) + firstBlockSize;
507 "ALLOC_CHUNK_LIMIT != ALLOCSET_SEPARATE_THRESHOLD");
556#ifdef MEMORY_CONTEXT_CHECKING
558 AllocSetCheck(context);
562 keepersize =
KeeperBlock(set)->endptr - ((
char *) set);
572 while (block != NULL)
581#ifdef CLOBBER_FREED_MEMORY
582 wipe_mem(datastart, block->
freeptr - datastart);
596#ifdef CLOBBER_FREED_MEMORY
597 wipe_mem(block, block->
freeptr - ((
char *) block));
642#ifdef MEMORY_CONTEXT_CHECKING
644 AllocSetCheck(context);
648 keepersize =
KeeperBlock(set)->endptr - ((
char *) set);
696 while (block != NULL)
703#ifdef CLOBBER_FREED_MEMORY
704 wipe_mem(block, block->
freeptr - ((
char *) block));
748#ifdef MEMORY_CONTEXT_CHECKING
773#ifdef MEMORY_CONTEXT_CHECKING
774 chunk->requested_size = size;
776 Assert(size < chunk_size);
779#ifdef RANDOMIZE_ALLOCATED_MEMORY
819 Size size,
Size chunk_size,
int fidx)
834#ifdef MEMORY_CONTEXT_CHECKING
835 chunk->requested_size = size;
837 if (size < chunk_size)
840#ifdef RANDOMIZE_ALLOCATED_MEMORY
917#ifdef MEMORY_CONTEXT_CHECKING
941 Assert(chunk_size >= size);
948 while (blksize < required_size)
958 while (block == NULL && blksize > 1024 * 1024)
961 if (blksize < required_size)
976 block->
endptr = ((
char *) block) + blksize;
1063#ifdef MEMORY_CONTEXT_CHECKING
1064 chunk->requested_size = size;
1069#ifdef RANDOMIZE_ALLOCATED_MEMORY
1088 Assert(chunk_size >= size);
1127 elog(
ERROR,
"could not find block containing chunk %p", chunk);
1131#ifdef MEMORY_CONTEXT_CHECKING
1134 Assert(chunk->requested_size < (block->
endptr - (
char *) pointer));
1135 if (!sentinel_ok(pointer, chunk->requested_size))
1136 elog(
WARNING,
"detected write past chunk end in %s %p",
1151#ifdef CLOBBER_FREED_MEMORY
1152 wipe_mem(block, block->
freeptr - ((
char *) block));
1179#ifdef MEMORY_CONTEXT_CHECKING
1182 if (!sentinel_ok(pointer, chunk->requested_size))
1183 elog(
WARNING,
"detected write past chunk end in %s %p",
1187#ifdef CLOBBER_FREED_MEMORY
1196#ifdef MEMORY_CONTEXT_CHECKING
1250 elog(
ERROR,
"could not find block containing chunk %p", chunk);
1257 oldchksize = block->
endptr - (
char *) pointer;
1259#ifdef MEMORY_CONTEXT_CHECKING
1261 Assert(chunk->requested_size < oldchksize);
1262 if (!sentinel_ok(pointer, chunk->requested_size))
1263 elog(
WARNING,
"detected write past chunk end in %s %p",
1264 set->header.
name, chunk);
1267#ifdef MEMORY_CONTEXT_CHECKING
1276 oldblksize = block->
endptr - ((
char *) block);
1279 if (newblock == NULL)
1297 block->
freeptr = block->
endptr = ((
char *) block) + blksize;
1305 set->blocks = block;
1309#ifdef MEMORY_CONTEXT_CHECKING
1310#ifdef RANDOMIZE_ALLOCATED_MEMORY
1316 if (size > chunk->requested_size)
1317 randomize_mem((
char *) pointer + chunk->requested_size,
1318 size - chunk->requested_size);
1330 if (
Min(size, oldchksize) > chunk->requested_size)
1332 Min(size, oldchksize) - chunk->requested_size);
1336 chunk->requested_size = size;
1339 set_sentinel(pointer, size);
1377#ifdef MEMORY_CONTEXT_CHECKING
1379 if (chunk->requested_size < oldchksize)
1380 if (!sentinel_ok(pointer, chunk->requested_size))
1381 elog(
WARNING,
"detected write past chunk end in %s %p",
1390 if (oldchksize >= size)
1392#ifdef MEMORY_CONTEXT_CHECKING
1393 Size oldrequest = chunk->requested_size;
1395#ifdef RANDOMIZE_ALLOCATED_MEMORY
1397 if (size > oldrequest)
1398 randomize_mem((
char *) pointer + oldrequest,
1402 chunk->requested_size = size;
1408 if (size > oldrequest)
1416 if (size < oldchksize)
1417 set_sentinel(pointer, size);
1454 if (newPointer == NULL)
1470#ifdef MEMORY_CONTEXT_CHECKING
1471 oldsize = chunk->requested_size;
1473 oldsize = oldchksize;
1478 memcpy(newPointer, pointer, oldsize);
1538 return block->
endptr - (
char *) chunk;
1586 Size freechunks = 0;
1597 for (block = set->
blocks; block != NULL; block = block->
next)
1600 totalspace += block->
endptr - ((
char *) block);
1608 while (chunk != NULL)
1628 char stats_string[200];
1630 snprintf(stats_string,
sizeof(stats_string),
1631 "%zu total in %zu blocks; %zu free (%zu chunks); %zu used",
1632 totalspace, nblocks, freespace, freechunks,
1633 totalspace - freespace);
1634 printfunc(context, passthru, stats_string, print_to_stderr);
1647#ifdef MEMORY_CONTEXT_CHECKING
1664 Size total_allocated = 0;
1666 for (prevblock = NULL, block = set->
blocks;
1668 prevblock = block, block = block->
next)
1671 long blk_used = block->
freeptr - bpoz;
1674 bool has_external_chunk =
false;
1677 total_allocated += block->
endptr - ((
char *) set);
1679 total_allocated += block->
endptr - ((
char *) block);
1687 elog(
WARNING,
"problem in alloc set %s: empty block %p",
1694 if (block->
aset != set ||
1695 block->
prev != prevblock ||
1698 elog(
WARNING,
"problem in alloc set %s: corrupt header in block %p",
1704 while (bpoz < block->freeptr)
1716 has_external_chunk =
true;
1720 elog(
WARNING,
"problem in alloc set %s: bad single-chunk %p in block %p",
1721 name, chunk, block);
1728 elog(
WARNING,
"problem in alloc set %s: bad chunk size for chunk %p in block %p",
1729 name, chunk, block);
1738 elog(
WARNING,
"problem in alloc set %s: bad block offset for chunk %p in block %p",
1739 name, chunk, block);
1741 dsize = chunk->requested_size;
1745 elog(
WARNING,
"problem in alloc set %s: req size > alloc size for chunk %p in block %p",
1746 name, chunk, block);
1750 elog(
WARNING,
"problem in alloc set %s: bad size %zu for chunk %p in block %p",
1751 name, chsize, chunk, block);
1758 elog(
WARNING,
"problem in alloc set %s: detected write past chunk end in block %p, chunk %p",
1759 name, block, chunk);
1772 elog(
WARNING,
"problem in alloc set %s: found inconsistent memory block %p",
1775 if (has_external_chunk && nchunks > 1)
1776 elog(
WARNING,
"problem in alloc set %s: external chunk on non-dedicated block %p",
Datum idx(PG_FUNCTION_ARGS)
void AllocSetReset(MemoryContext context)
static pg_noinline void * AllocSetAllocFromNewBlock(MemoryContext context, Size size, int flags, int fidx)
#define AllocSetIsValid(set)
#define AllocBlockIsValid(block)
void * AllocSetRealloc(void *pointer, Size size, int flags)
#define IsKeeperBlock(set, block)
#define GetFreeListLink(chkptr)
#define FreeListIdxIsValid(fidx)
Size AllocSetGetChunkSpace(void *pointer)
MemoryContext AllocSetGetChunkContext(void *pointer)
void AllocSetStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
#define GetChunkSizeFromFreeListIdx(fidx)
struct AllocBlockData * AllocBlock
#define MAX_FREE_CONTEXTS
static int AllocSetFreeIndex(Size size)
bool AllocSetIsEmpty(MemoryContext context)
struct AllocBlockData AllocBlockData
void * AllocSetAlloc(MemoryContext context, Size size, int flags)
#define ALLOCSET_NUM_FREELISTS
struct AllocSetContext AllocSetContext
#define ALLOC_CHUNK_FRACTION
void AllocSetFree(void *pointer)
void AllocSetDelete(MemoryContext context)
struct AllocSetFreeList AllocSetFreeList
static void * AllocSetAllocChunkFromBlock(MemoryContext context, AllocBlock block, Size size, Size chunk_size, int fidx)
#define ALLOC_CHUNK_LIMIT
struct AllocFreeListLink AllocFreeListLink
static AllocSetFreeList context_freelists[2]
static pg_noinline void * AllocSetAllocLarge(MemoryContext context, Size size, int flags)
#define ExternalChunkGetBlock(chunk)
MemoryContext AllocSetContextCreateInternal(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
AllocSetContext * AllocSet
#define PG_USED_FOR_ASSERTS_ONLY
#define MemSetAligned(start, val, len)
#define StaticAssertDecl(condition, errmessage)
#define StaticAssertStmt(condition, errmessage)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
Assert(PointerIsAligned(start, uint64))
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)
void MemoryContextResetOnly(MemoryContext context)
#define VALGRIND_DESTROY_MEMPOOL(context)
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
#define VALGRIND_MEMPOOL_CHANGE(context, optr, nptr, 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 ALLOCSET_SMALL_MINSIZE
#define ALLOCSET_DEFAULT_MINSIZE
#define AllocHugeSizeIsValid(size)
#define ALLOCSET_SEPARATE_THRESHOLD
#define ALLOCSET_SMALL_INITSIZE
#define ALLOCSET_DEFAULT_INITSIZE
static void MemoryContextCheckSize(MemoryContext context, Size size, int flags)
#define MEMORYCHUNK_MAX_BLOCKOFFSET
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
static int pg_leftmost_one_pos32(uint32 word)
PGDLLIMPORT const uint8 pg_leftmost_one_pos[256]
MemoryChunk * freelist[ALLOCSET_NUM_FREELISTS]
AllocSetContext * first_free
int link(const char *src, const char *dst)