77 #define Slab_BLOCKHDRSZ MAXALIGN(sizeof(SlabBlock))
79 #ifdef MEMORY_CONTEXT_CHECKING
85 #define Slab_CONTEXT_HDRSZ(chunksPerBlock) \
86 (sizeof(SlabContext) + ((chunksPerBlock) * sizeof(bool)))
88 #define Slab_CONTEXT_HDRSZ(chunksPerBlock) sizeof(SlabContext)
95 #define SLAB_BLOCKLIST_COUNT 3
98 #define SLAB_MAXIMUM_EMPTY_BLOCKS 10
113 #ifdef MEMORY_CONTEXT_CHECKING
157 #define Slab_CHUNKHDRSZ sizeof(MemoryChunk)
158 #define SlabChunkGetPointer(chk) \
159 ((void *) (((char *) (chk)) + sizeof(MemoryChunk)))
165 #define SlabBlockGetChunk(slab, block, n) \
166 ((MemoryChunk *) ((char *) (block) + Slab_BLOCKHDRSZ \
167 + ((n) * (slab)->fullChunkSize)))
169 #if defined(MEMORY_CONTEXT_CHECKING) || defined(USE_ASSERT_CHECKING)
176 #define SlabChunkIndex(slab, block, chunk) \
177 (((char *) (chunk) - (char *) SlabBlockGetChunk(slab, block, 0)) / \
178 (slab)->fullChunkSize)
186 #define SlabChunkMod(slab, block, chunk) \
187 (((char *) (chunk) - (char *) SlabBlockGetChunk(slab, block, 0)) % \
188 (slab)->fullChunkSize)
196 #define SlabIsValid(set) (PointerIsValid(set) && IsA(set, SlabContext))
202 #define SlabBlockIsValid(block) \
203 (PointerIsValid(block) && SlabIsValid((block)->slab))
216 Assert(nfree >= 0 && nfree <= slab->chunksPerBlock);
230 index = -((-nfree) >> blocklist_shift);
292 SlabChunkMod(slab, block, block->
freehead) == 0));
334 "sizeof(MemoryChunk) is not maxaligned");
345 #ifdef MEMORY_CONTEXT_CHECKING
358 if (chunksPerBlock == 0)
359 elog(
ERROR,
"block size %zu for slab is too small for %zu-byte chunks",
360 blockSize, chunkSize);
369 (
errcode(ERRCODE_OUT_OF_MEMORY),
371 errdetail(
"Failed while creating memory context \"%s\".",
408 #ifdef MEMORY_CONTEXT_CHECKING
410 slab->isChunkFree = (
bool *) ((
char *) slab +
sizeof(
SlabContext));
439 #ifdef MEMORY_CONTEXT_CHECKING
451 #ifdef CLOBBER_FREED_MEMORY
467 #ifdef CLOBBER_FREED_MEMORY
516 #ifdef MEMORY_CONTEXT_CHECKING
526 #ifdef RANDOMIZE_ALLOCATED_MEMORY
584 blocklist = &slab->
blocklist[blocklist_idx];
661 int new_blocklist_idx;
722 #ifdef MEMORY_CONTEXT_CHECKING
725 if (!sentinel_ok(pointer, slab->
chunkSize))
726 elog(
WARNING,
"detected write past chunk end in %s %p",
739 #ifdef CLOBBER_FREED_MEMORY
752 if (
unlikely(curBlocklistIdx != newBlocklistIdx))
795 #ifdef CLOBBER_FREED_MEMORY
854 elog(
ERROR,
"slab allocator does not support realloc()");
916 return (
context->mem_allocated == 0);
932 bool print_to_stderr)
960 freechunks += block->
nfree;
966 char stats_string[200];
969 snprintf(stats_string,
sizeof(stats_string),
970 "%zu total in %zu blocks; %u empty blocks; %zu free (%zu chunks); %zu used",
972 freespace, freechunks, totalspace - freespace);
973 printfunc(
context, passthru, stats_string, print_to_stderr);
986 #ifdef MEMORY_CONTEXT_CHECKING
1017 elog(
WARNING,
"problem in slab %s: empty block %p should have %d free chunks but has %d chunks free",
1038 elog(
WARNING,
"problem in slab %s: block %p is on blocklist %d but should be on blocklist %d",
1043 elog(
WARNING,
"problem in slab %s: empty block %p incorrectly stored on blocklist element %d",
1047 if (block->
slab != slab)
1048 elog(
WARNING,
"problem in slab %s: bogus slab link in block %p",
1052 memset(slab->isChunkFree, 0, (slab->
chunksPerBlock *
sizeof(
bool)));
1057 while (cur_chunk != NULL)
1059 int chunkidx = SlabChunkIndex(slab, block, cur_chunk);
1067 SlabChunkMod(slab, block, cur_chunk) != 0)
1068 elog(
WARNING,
"problem in slab %s: bogus free list link %p in block %p",
1069 name, cur_chunk, block);
1073 slab->isChunkFree[chunkidx] =
true;
1083 elog(
WARNING,
"problem in slab %s: mismatch detected between nunused chunks and unused pointer in block %p",
1090 cur_chunk = block->
unused;
1093 int chunkidx = SlabChunkIndex(slab, block, cur_chunk);
1098 if (chunkidx < slab->chunksPerBlock)
1099 slab->isChunkFree[chunkidx] =
true;
1107 if (!slab->isChunkFree[
j])
1124 if (chunkblock != block)
1125 elog(
WARNING,
"problem in slab %s: bogus block link in block %p, chunk %p",
1131 elog(
WARNING,
"problem in slab %s: detected write past chunk end in block %p, chunk %p",
1140 if (nfree != block->
nfree)
1141 elog(
WARNING,
"problem in slab %s: nfree in block %p is %d but %d chunk were found as free",
#define Assert(condition)
#define StaticAssertDecl(condition, errmessage)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
#define dlist_foreach(iter, lhead)
static void dlist_init(dlist_head *head)
static void dlist_delete_from(dlist_head *head, dlist_node *node)
#define dlist_head_element(type, membername, lhead)
static void dlist_delete(dlist_node *node)
static uint32 dclist_count(const dclist_head *head)
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 void dclist_delete_from(dclist_head *head, dlist_node *node)
static void dclist_push_head(dclist_head *head, dlist_node *node)
static void dclist_init(dclist_head *head)
#define dclist_foreach_modify(iter, lhead)
#define dlist_container(type, membername, ptr)
#define dclist_foreach(iter, lhead)
static dlist_node * dclist_pop_head_node(dclist_head *head)
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_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 MEMORYCHUNK_MAX_BLOCKOFFSET
#define MEMORYCHUNK_MAX_VALUE
#define MemoryChunkGetPointer(c)
static void * MemoryChunkGetBlock(MemoryChunk *chunk)
#define PointerGetMemoryChunk(p)
static void MemoryChunkSetHdrMask(MemoryChunk *chunk, void *block, Size value, MemoryContextMethodID methodid)
static pg_noinline void pg_attribute_noreturn() SlabAllocInvalidSize(MemoryContext context
elog(ERROR, "unexpected alloc chunk size %zu (expected %u)", size, slab->chunkSize)
struct SlabBlock SlabBlock
static pg_noinline void Size size
static pg_noinline void * SlabAllocFromNewBlock(MemoryContext context, Size size, int flags)
void * SlabAlloc(MemoryContext context, Size size, int flags)
void SlabFree(void *pointer)
void SlabReset(MemoryContext context)
struct SlabContext SlabContext
#define SlabChunkGetPointer(chk)
MemoryContext SlabContextCreate(MemoryContext parent, const char *name, Size blockSize, Size chunkSize)
static int32 SlabBlocklistIndex(SlabContext *slab, int nfree)
Size SlabGetChunkSpace(void *pointer)
static void * SlabAllocSetupNewChunk(MemoryContext context, SlabBlock *block, MemoryChunk *chunk, Size size)
#define Slab_CONTEXT_HDRSZ(chunksPerBlock)
bool SlabIsEmpty(MemoryContext context)
MemoryContext SlabGetChunkContext(void *pointer)
static int32 SlabFindNextBlockListIndex(SlabContext *slab)
static MemoryChunk * SlabGetNextFreeChunk(SlabContext *slab, SlabBlock *block)
#define SlabBlockGetChunk(slab, block, n)
void SlabStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
void SlabDelete(MemoryContext context)
#define SLAB_BLOCKLIST_COUNT
#define SlabBlockIsValid(block)
#define SLAB_MAXIMUM_EMPTY_BLOCKS
void * SlabRealloc(void *pointer, Size size, int flags)
dlist_head blocklist[SLAB_BLOCKLIST_COUNT]