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
513 elog(
ERROR,
"unexpected alloc chunk size %zu (expected %u)",
565 blocklist = &slab->
blocklist[blocklist_idx];
577 int new_blocklist_idx;
615 Assert(SlabChunkMod(slab, block, chunk) == 0);
622 #ifdef MEMORY_CONTEXT_CHECKING
632 #ifdef RANDOMIZE_ALLOCATED_MEMORY
669 #ifdef MEMORY_CONTEXT_CHECKING
672 if (!sentinel_ok(pointer, slab->
chunkSize))
673 elog(
WARNING,
"detected write past chunk end in %s %p",
686 #ifdef CLOBBER_FREED_MEMORY
699 if (
unlikely(curBlocklistIdx != newBlocklistIdx))
742 #ifdef CLOBBER_FREED_MEMORY
794 elog(
ERROR,
"could not find block containing chunk %p", chunk);
801 elog(
ERROR,
"slab allocator does not support realloc()");
879 bool print_to_stderr)
907 freechunks += block->
nfree;
913 char stats_string[200];
916 snprintf(stats_string,
sizeof(stats_string),
917 "%zu total in %zu blocks; %u empty blocks; %zu free (%zu chunks); %zu used",
919 freespace, freechunks, totalspace - freespace);
920 printfunc(context, passthru, stats_string, print_to_stderr);
933 #ifdef MEMORY_CONTEXT_CHECKING
964 elog(
WARNING,
"problem in slab %s: empty block %p should have %d free chunks but has %d chunks free",
985 elog(
WARNING,
"problem in slab %s: block %p is on blocklist %d but should be on blocklist %d",
990 elog(
WARNING,
"problem in slab %s: empty block %p incorrectly stored on blocklist element %d",
994 if (block->
slab != slab)
995 elog(
WARNING,
"problem in slab %s: bogus slab link in block %p",
999 memset(slab->isChunkFree, 0, (slab->
chunksPerBlock *
sizeof(
bool)));
1004 while (cur_chunk != NULL)
1006 int chunkidx = SlabChunkIndex(slab, block, cur_chunk);
1014 SlabChunkMod(slab, block, cur_chunk) != 0)
1015 elog(
WARNING,
"problem in slab %s: bogus free list link %p in block %p",
1016 name, cur_chunk, block);
1020 slab->isChunkFree[chunkidx] =
true;
1030 elog(
WARNING,
"problem in slab %s: mismatch detected between nunused chunks and unused pointer in block %p",
1037 cur_chunk = block->
unused;
1040 int chunkidx = SlabChunkIndex(slab, block, cur_chunk);
1045 if (chunkidx < slab->chunksPerBlock)
1046 slab->isChunkFree[chunkidx] =
true;
1054 if (!slab->isChunkFree[
j])
1071 if (chunkblock != block)
1072 elog(
WARNING,
"problem in slab %s: bogus block link in block %p, chunk %p",
1073 name, block, chunk);
1078 elog(
WARNING,
"problem in slab %s: detected write past chunk end in block %p, chunk %p",
1079 name, block, chunk);
1087 if (nfree != block->
nfree)
1088 elog(
WARNING,
"problem in slab %s: nfree in block %p is %d but %d chunk were found as free",
#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,...)
#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)
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 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)
struct SlabBlock SlabBlock
void * SlabAlloc(MemoryContext context, Size size)
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)
#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 * SlabRealloc(void *pointer, Size size)
void SlabDelete(MemoryContext context)
#define SLAB_BLOCKLIST_COUNT
#define SlabBlockIsValid(block)
#define SLAB_MAXIMUM_EMPTY_BLOCKS
dlist_head blocklist[SLAB_BLOCKLIST_COUNT]