PostgreSQL Source Code  git master
slab.c File Reference
#include "postgres.h"
#include "lib/ilist.h"
#include "utils/memdebug.h"
#include "utils/memutils.h"
Include dependency graph for slab.c:

Go to the source code of this file.

Data Structures

struct  SlabContext
 
struct  SlabBlock
 
struct  SlabChunk
 

Macros

#define SlabPointerGetChunk(ptr)   ((SlabChunk *)(((char *)(ptr)) - sizeof(SlabChunk)))
 
#define SlabChunkGetPointer(chk)   ((void *)(((char *)(chk)) + sizeof(SlabChunk)))
 
#define SlabBlockGetChunk(slab, block, idx)
 
#define SlabBlockStart(block)   ((char *) block + sizeof(SlabBlock))
 
#define SlabChunkIndex(slab, block, chunk)   (((char *) chunk - SlabBlockStart(block)) / slab->fullChunkSize)
 

Typedefs

typedef struct SlabContext SlabContext
 
typedef struct SlabBlock SlabBlock
 
typedef struct SlabChunk SlabChunk
 

Functions

static void * SlabAlloc (MemoryContext context, Size size)
 
static void SlabFree (MemoryContext context, void *pointer)
 
static void * SlabRealloc (MemoryContext context, void *pointer, Size size)
 
static void SlabReset (MemoryContext context)
 
static void SlabDelete (MemoryContext context)
 
static Size SlabGetChunkSpace (MemoryContext context, void *pointer)
 
static bool SlabIsEmpty (MemoryContext context)
 
static void SlabStats (MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
 
MemoryContext SlabContextCreate (MemoryContext parent, const char *name, Size blockSize, Size chunkSize)
 

Variables

static const MemoryContextMethods SlabMethods
 

Macro Definition Documentation

◆ SlabBlockGetChunk

#define SlabBlockGetChunk (   slab,
  block,
  idx 
)
Value:
((SlabChunk *) ((char *) (block) + sizeof(SlabBlock) \
+ (idx * slab->fullChunkSize)))
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
Definition: slab.c:88

Definition at line 118 of file slab.c.

Referenced by SlabAlloc(), and SlabStats().

◆ SlabBlockStart

#define SlabBlockStart (   block)    ((char *) block + sizeof(SlabBlock))

Definition at line 121 of file slab.c.

◆ SlabChunkGetPointer

#define SlabChunkGetPointer (   chk)    ((void *)(((char *)(chk)) + sizeof(SlabChunk)))

Definition at line 116 of file slab.c.

Referenced by SlabAlloc(), and SlabStats().

◆ SlabChunkIndex

#define SlabChunkIndex (   slab,
  block,
  chunk 
)    (((char *) chunk - SlabBlockStart(block)) / slab->fullChunkSize)

Definition at line 123 of file slab.c.

Referenced by SlabFree().

◆ SlabPointerGetChunk

#define SlabPointerGetChunk (   ptr)    ((SlabChunk *)(((char *)(ptr)) - sizeof(SlabChunk)))

Definition at line 114 of file slab.c.

Referenced by SlabFree().

Typedef Documentation

◆ SlabBlock

typedef struct SlabBlock SlabBlock

◆ SlabChunk

typedef struct SlabChunk SlabChunk

◆ SlabContext

typedef struct SlabContext SlabContext

Function Documentation

◆ SlabAlloc()

static void * SlabAlloc ( MemoryContext  context,
Size  size 
)
static

Definition at line 340 of file slab.c.

References Assert, SlabChunk::block, SlabContext::blockSize, castNode, SlabContext::chunkSize, SlabContext::chunksPerBlock, dlist_delete(), dlist_head_element, dlist_is_empty(), dlist_push_head(), elog, ERROR, SlabBlock::firstFreeChunk, SlabContext::freelist, SlabContext::fullChunkSize, idx(), malloc, MemoryContextData::mem_allocated, SlabContext::minFreeChunks, SlabContext::nblocks, SlabBlock::nfree, SlabBlock::node, SlabChunk::slab, SlabBlockGetChunk, SlabChunkGetPointer, VALGRIND_MAKE_MEM_DEFINED, VALGRIND_MAKE_MEM_NOACCESS, and VALGRIND_MAKE_MEM_UNDEFINED.

341 {
342  SlabContext *slab = castNode(SlabContext, context);
343  SlabBlock *block;
344  SlabChunk *chunk;
345  int idx;
346 
347  Assert(slab);
348 
349  Assert((slab->minFreeChunks >= 0) &&
350  (slab->minFreeChunks < slab->chunksPerBlock));
351 
352  /* make sure we only allow correct request size */
353  if (size != slab->chunkSize)
354  elog(ERROR, "unexpected alloc chunk size %zu (expected %zu)",
355  size, slab->chunkSize);
356 
357  /*
358  * If there are no free chunks in any existing block, create a new block
359  * and put it to the last freelist bucket.
360  *
361  * slab->minFreeChunks == 0 means there are no blocks with free chunks,
362  * thanks to how minFreeChunks is updated at the end of SlabAlloc().
363  */
364  if (slab->minFreeChunks == 0)
365  {
366  block = (SlabBlock *) malloc(slab->blockSize);
367 
368  if (block == NULL)
369  return NULL;
370 
371  block->nfree = slab->chunksPerBlock;
372  block->firstFreeChunk = 0;
373 
374  /*
375  * Put all the chunks on a freelist. Walk the chunks and point each
376  * one to the next one.
377  */
378  for (idx = 0; idx < slab->chunksPerBlock; idx++)
379  {
380  chunk = SlabBlockGetChunk(slab, block, idx);
381  *(int32 *) SlabChunkGetPointer(chunk) = (idx + 1);
382  }
383 
384  /*
385  * And add it to the last freelist with all chunks empty.
386  *
387  * We know there are no blocks in the freelist, otherwise we wouldn't
388  * need a new block.
389  */
391 
392  dlist_push_head(&slab->freelist[slab->chunksPerBlock], &block->node);
393 
394  slab->minFreeChunks = slab->chunksPerBlock;
395  slab->nblocks += 1;
396  context->mem_allocated += slab->blockSize;
397  }
398 
399  /* grab the block from the freelist (even the new block is there) */
400  block = dlist_head_element(SlabBlock, node,
401  &slab->freelist[slab->minFreeChunks]);
402 
403  /* make sure we actually got a valid block, with matching nfree */
404  Assert(block != NULL);
405  Assert(slab->minFreeChunks == block->nfree);
406  Assert(block->nfree > 0);
407 
408  /* we know index of the first free chunk in the block */
409  idx = block->firstFreeChunk;
410 
411  /* make sure the chunk index is valid, and that it's marked as empty */
412  Assert((idx >= 0) && (idx < slab->chunksPerBlock));
413 
414  /* compute the chunk location block start (after the block header) */
415  chunk = SlabBlockGetChunk(slab, block, idx);
416 
417  /*
418  * Update the block nfree count, and also the minFreeChunks as we've
419  * decreased nfree for a block with the minimum number of free chunks
420  * (because that's how we chose the block).
421  */
422  block->nfree--;
423  slab->minFreeChunks = block->nfree;
424 
425  /*
426  * Remove the chunk from the freelist head. The index of the next free
427  * chunk is stored in the chunk itself.
428  */
430  block->firstFreeChunk = *(int32 *) SlabChunkGetPointer(chunk);
431 
432  Assert(block->firstFreeChunk >= 0);
433  Assert(block->firstFreeChunk <= slab->chunksPerBlock);
434 
435  Assert((block->nfree != 0 &&
436  block->firstFreeChunk < slab->chunksPerBlock) ||
437  (block->nfree == 0 &&
438  block->firstFreeChunk == slab->chunksPerBlock));
439 
440  /* move the whole block to the right place in the freelist */
441  dlist_delete(&block->node);
442  dlist_push_head(&slab->freelist[block->nfree], &block->node);
443 
444  /*
445  * And finally update minFreeChunks, i.e. the index to the block with the
446  * lowest number of free chunks. We only need to do that when the block
447  * got full (otherwise we know the current block is the right one). We'll
448  * simply walk the freelist until we find a non-empty entry.
449  */
450  if (slab->minFreeChunks == 0)
451  {
452  for (idx = 1; idx <= slab->chunksPerBlock; idx++)
453  {
454  if (dlist_is_empty(&slab->freelist[idx]))
455  continue;
456 
457  /* found a non-empty freelist */
458  slab->minFreeChunks = idx;
459  break;
460  }
461  }
462 
463  if (slab->minFreeChunks == slab->chunksPerBlock)
464  slab->minFreeChunks = 0;
465 
466  /* Prepare to initialize the chunk header. */
467  VALGRIND_MAKE_MEM_UNDEFINED(chunk, sizeof(SlabChunk));
468 
469  chunk->block = block;
470  chunk->slab = slab;
471 
472 #ifdef MEMORY_CONTEXT_CHECKING
473  /* slab mark to catch clobber of "unused" space */
474  if (slab->chunkSize < (slab->fullChunkSize - sizeof(SlabChunk)))
475  {
476  set_sentinel(SlabChunkGetPointer(chunk), size);
477  VALGRIND_MAKE_MEM_NOACCESS(((char *) chunk) +
478  sizeof(SlabChunk) + slab->chunkSize,
479  slab->fullChunkSize -
480  (slab->chunkSize + sizeof(SlabChunk)));
481  }
482 #endif
483 #ifdef RANDOMIZE_ALLOCATED_MEMORY
484  /* fill the allocated space with junk */
485  randomize_mem((char *) SlabChunkGetPointer(chunk), size);
486 #endif
487 
488  Assert(slab->nblocks * slab->blockSize == context->mem_allocated);
489 
490  return SlabChunkGetPointer(chunk);
491 }
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
int nblocks
Definition: slab.c:72
static void dlist_push_head(dlist_head *head, dlist_node *node)
Definition: ilist.h:300
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
Size blockSize
Definition: slab.c:68
#define VALGRIND_MAKE_MEM_UNDEFINED(addr, size)
Definition: memdebug.h:28
SlabBlock * block
Definition: slab.c:108
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition: memdebug.h:27
dlist_head freelist[FLEXIBLE_ARRAY_MEMBER]
Definition: slab.c:77
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
dlist_node node
Definition: slab.c:90
signed int int32
Definition: c.h:429
Size chunkSize
Definition: slab.c:66
#define malloc(a)
Definition: header.h:50
int firstFreeChunk
Definition: slab.c:92
#define ERROR
Definition: elog.h:46
SlabContext * slab
Definition: slab.c:109
int chunksPerBlock
Definition: slab.c:70
Size fullChunkSize
Definition: slab.c:67
static void dlist_delete(dlist_node *node)
Definition: ilist.h:358
int nfree
Definition: slab.c:91
#define dlist_head_element(type, membername, lhead)
Definition: ilist.h:506
#define Assert(condition)
Definition: c.h:804
static bool dlist_is_empty(dlist_head *head)
Definition: ilist.h:289
Size mem_allocated
Definition: memnodes.h:84
Definition: slab.c:88
#define SlabBlockGetChunk(slab, block, idx)
Definition: slab.c:118
#define elog(elevel,...)
Definition: elog.h:232
int minFreeChunks
Definition: slab.c:71
#define SlabChunkGetPointer(chk)
Definition: slab.c:116

◆ SlabContextCreate()

MemoryContext SlabContextCreate ( MemoryContext  parent,
const char *  name,
Size  blockSize,
Size  chunkSize 
)

Definition at line 175 of file slab.c.

References SlabContext::blockSize, SlabContext::chunkSize, SlabContext::chunksPerBlock, dlist_init(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, SlabContext::freelist, SlabContext::fullChunkSize, SlabContext::headerSize, i, malloc, MAXALIGN, MemoryContextCreate(), MemoryContextStats(), offsetof, StaticAssertStmt, T_SlabContext, and TopMemoryContext.

Referenced by ReorderBufferAllocate().

179 {
180  int chunksPerBlock;
181  Size fullChunkSize;
182  Size freelistSize;
183  Size headerSize;
184  SlabContext *slab;
185  int i;
186 
187  /* Assert we padded SlabChunk properly */
188  StaticAssertStmt(sizeof(SlabChunk) == MAXALIGN(sizeof(SlabChunk)),
189  "sizeof(SlabChunk) is not maxaligned");
191  sizeof(SlabChunk),
192  "padding calculation in SlabChunk is wrong");
193 
194  /* Make sure the linked list node fits inside a freed chunk */
195  if (chunkSize < sizeof(int))
196  chunkSize = sizeof(int);
197 
198  /* chunk, including SLAB header (both addresses nicely aligned) */
199  fullChunkSize = sizeof(SlabChunk) + MAXALIGN(chunkSize);
200 
201  /* Make sure the block can store at least one chunk. */
202  if (blockSize < fullChunkSize + sizeof(SlabBlock))
203  elog(ERROR, "block size %zu for slab is too small for %zu chunks",
204  blockSize, chunkSize);
205 
206  /* Compute maximum number of chunks per block */
207  chunksPerBlock = (blockSize - sizeof(SlabBlock)) / fullChunkSize;
208 
209  /* The freelist starts with 0, ends with chunksPerBlock. */
210  freelistSize = sizeof(dlist_head) * (chunksPerBlock + 1);
211 
212  /*
213  * Allocate the context header. Unlike aset.c, we never try to combine
214  * this with the first regular block; not worth the extra complication.
215  */
216 
217  /* Size of the memory context header */
218  headerSize = offsetof(SlabContext, freelist) + freelistSize;
219 
220 #ifdef MEMORY_CONTEXT_CHECKING
221 
222  /*
223  * With memory checking, we need to allocate extra space for the bitmap of
224  * free chunks. The bitmap is an array of bools, so we don't need to worry
225  * about alignment.
226  */
227  headerSize += chunksPerBlock * sizeof(bool);
228 #endif
229 
230  slab = (SlabContext *) malloc(headerSize);
231  if (slab == NULL)
232  {
234  ereport(ERROR,
235  (errcode(ERRCODE_OUT_OF_MEMORY),
236  errmsg("out of memory"),
237  errdetail("Failed while creating memory context \"%s\".",
238  name)));
239  }
240 
241  /*
242  * Avoid writing code that can fail between here and MemoryContextCreate;
243  * we'd leak the header if we ereport in this stretch.
244  */
245 
246  /* Fill in SlabContext-specific header fields */
247  slab->chunkSize = chunkSize;
248  slab->fullChunkSize = fullChunkSize;
249  slab->blockSize = blockSize;
250  slab->headerSize = headerSize;
251  slab->chunksPerBlock = chunksPerBlock;
252  slab->minFreeChunks = 0;
253  slab->nblocks = 0;
254 
255  /* initialize the freelist slots */
256  for (i = 0; i < (slab->chunksPerBlock + 1); i++)
257  dlist_init(&slab->freelist[i]);
258 
259 #ifdef MEMORY_CONTEXT_CHECKING
260  /* set the freechunks pointer right after the freelists array */
261  slab->freechunks
262  = (bool *) slab + offsetof(SlabContext, freelist) + freelistSize;
263 #endif
264 
265  /* Finally, do the type-independent part of context creation */
268  &SlabMethods,
269  parent,
270  name);
271 
272  return (MemoryContext) slab;
273 }
struct dlist_head dlist_head
int errcode(int sqlerrcode)
Definition: elog.c:698
#define malloc(a)
Definition: header.h:50
static const MemoryContextMethods SlabMethods
Definition: slab.c:147
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:918
#define ERROR
Definition: elog.h:46
void MemoryContextStats(MemoryContext context)
Definition: mcxt.c:505
int errdetail(const char *fmt,...)
Definition: elog.c:1042
void MemoryContextCreate(MemoryContext node, NodeTag tag, const MemoryContextMethods *methods, MemoryContext parent, const char *name)
Definition: mcxt.c:815
MemoryContext TopMemoryContext
Definition: mcxt.c:48
static void dlist_init(dlist_head *head)
Definition: ilist.h:278
#define ereport(elevel,...)
Definition: elog.h:157
struct SlabBlock SlabBlock
size_t Size
Definition: c.h:540
#define MAXALIGN(LEN)
Definition: c.h:757
const char * name
Definition: encode.c:515
Definition: slab.c:88
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
int i
struct SlabChunk SlabChunk
#define offsetof(type, field)
Definition: c.h:727
unsigned char bool
Definition: c.h:391

◆ SlabDelete()

static void SlabDelete ( MemoryContext  context)
static

Definition at line 326 of file slab.c.

References free, and SlabReset().

327 {
328  /* Reset to release all the SlabBlocks */
329  SlabReset(context);
330  /* And free the context header */
331  free(context);
332 }
static void SlabReset(MemoryContext context)
Definition: slab.c:283
#define free(a)
Definition: header.h:65

◆ SlabFree()

static void SlabFree ( MemoryContext  context,
void *  pointer 
)
static

Definition at line 498 of file slab.c.

References Assert, SlabChunk::block, SlabContext::blockSize, castNode, SlabContext::chunkSize, SlabContext::chunksPerBlock, dlist_delete(), dlist_is_empty(), dlist_push_head(), elog, SlabBlock::firstFreeChunk, free, SlabContext::freelist, SlabContext::fullChunkSize, SlabContext::header, idx(), MemoryContextData::mem_allocated, SlabContext::minFreeChunks, MemoryContextData::name, SlabContext::nblocks, SlabBlock::nfree, SlabBlock::node, SlabChunkIndex, SlabPointerGetChunk, and WARNING.

499 {
500  int idx;
501  SlabContext *slab = castNode(SlabContext, context);
502  SlabChunk *chunk = SlabPointerGetChunk(pointer);
503  SlabBlock *block = chunk->block;
504 
505 #ifdef MEMORY_CONTEXT_CHECKING
506  /* Test for someone scribbling on unused space in chunk */
507  if (slab->chunkSize < (slab->fullChunkSize - sizeof(SlabChunk)))
508  if (!sentinel_ok(pointer, slab->chunkSize))
509  elog(WARNING, "detected write past chunk end in %s %p",
510  slab->header.name, chunk);
511 #endif
512 
513  /* compute index of the chunk with respect to block start */
514  idx = SlabChunkIndex(slab, block, chunk);
515 
516  /* add chunk to freelist, and update block nfree count */
517  *(int32 *) pointer = block->firstFreeChunk;
518  block->firstFreeChunk = idx;
519  block->nfree++;
520 
521  Assert(block->nfree > 0);
522  Assert(block->nfree <= slab->chunksPerBlock);
523 
524 #ifdef CLOBBER_FREED_MEMORY
525  /* XXX don't wipe the int32 index, used for block-level freelist */
526  wipe_mem((char *) pointer + sizeof(int32),
527  slab->chunkSize - sizeof(int32));
528 #endif
529 
530  /* remove the block from a freelist */
531  dlist_delete(&block->node);
532 
533  /*
534  * See if we need to update the minFreeChunks field for the slab - we only
535  * need to do that if there the block had that number of free chunks
536  * before we freed one. In that case, we check if there still are blocks
537  * in the original freelist and we either keep the current value (if there
538  * still are blocks) or increment it by one (the new block is still the
539  * one with minimum free chunks).
540  *
541  * The one exception is when the block will get completely free - in that
542  * case we will free it, se we can't use it for minFreeChunks. It however
543  * means there are no more blocks with free chunks.
544  */
545  if (slab->minFreeChunks == (block->nfree - 1))
546  {
547  /* Have we removed the last chunk from the freelist? */
548  if (dlist_is_empty(&slab->freelist[slab->minFreeChunks]))
549  {
550  /* but if we made the block entirely free, we'll free it */
551  if (block->nfree == slab->chunksPerBlock)
552  slab->minFreeChunks = 0;
553  else
554  slab->minFreeChunks++;
555  }
556  }
557 
558  /* If the block is now completely empty, free it. */
559  if (block->nfree == slab->chunksPerBlock)
560  {
561  free(block);
562  slab->nblocks--;
563  context->mem_allocated -= slab->blockSize;
564  }
565  else
566  dlist_push_head(&slab->freelist[block->nfree], &block->node);
567 
568  Assert(slab->nblocks >= 0);
569  Assert(slab->nblocks * slab->blockSize == context->mem_allocated);
570 }
MemoryContextData header
Definition: slab.c:64
int nblocks
Definition: slab.c:72
static void dlist_push_head(dlist_head *head, dlist_node *node)
Definition: ilist.h:300
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
Size blockSize
Definition: slab.c:68
SlabBlock * block
Definition: slab.c:108
dlist_head freelist[FLEXIBLE_ARRAY_MEMBER]
Definition: slab.c:77
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
dlist_node node
Definition: slab.c:90
signed int int32
Definition: c.h:429
Size chunkSize
Definition: slab.c:66
int firstFreeChunk
Definition: slab.c:92
int chunksPerBlock
Definition: slab.c:70
Size fullChunkSize
Definition: slab.c:67
#define SlabChunkIndex(slab, block, chunk)
Definition: slab.c:123
static void dlist_delete(dlist_node *node)
Definition: ilist.h:358
int nfree
Definition: slab.c:91
#define WARNING
Definition: elog.h:40
#define free(a)
Definition: header.h:65
#define Assert(condition)
Definition: c.h:804
static bool dlist_is_empty(dlist_head *head)
Definition: ilist.h:289
Size mem_allocated
Definition: memnodes.h:84
Definition: slab.c:88
#define elog(elevel,...)
Definition: elog.h:232
int minFreeChunks
Definition: slab.c:71
#define SlabPointerGetChunk(ptr)
Definition: slab.c:114
const char * name
Definition: memnodes.h:90

◆ SlabGetChunkSpace()

static Size SlabGetChunkSpace ( MemoryContext  context,
void *  pointer 
)
static

Definition at line 606 of file slab.c.

References Assert, castNode, and SlabContext::fullChunkSize.

607 {
608  SlabContext *slab = castNode(SlabContext, context);
609 
610  Assert(slab);
611 
612  return slab->fullChunkSize;
613 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
Size fullChunkSize
Definition: slab.c:67
#define Assert(condition)
Definition: c.h:804

◆ SlabIsEmpty()

static bool SlabIsEmpty ( MemoryContext  context)
static

Definition at line 620 of file slab.c.

References Assert, castNode, and SlabContext::nblocks.

621 {
622  SlabContext *slab = castNode(SlabContext, context);
623 
624  Assert(slab);
625 
626  return (slab->nblocks == 0);
627 }
int nblocks
Definition: slab.c:72
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
#define Assert(condition)
Definition: c.h:804

◆ SlabRealloc()

static void * SlabRealloc ( MemoryContext  context,
void *  pointer,
Size  size 
)
static

Definition at line 586 of file slab.c.

References Assert, castNode, SlabContext::chunkSize, elog, and ERROR.

587 {
588  SlabContext *slab = castNode(SlabContext, context);
589 
590  Assert(slab);
591 
592  /* can't do actual realloc with slab, but let's try to be gentle */
593  if (size == slab->chunkSize)
594  return pointer;
595 
596  elog(ERROR, "slab allocator does not support realloc()");
597  return NULL; /* keep compiler quiet */
598 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
Size chunkSize
Definition: slab.c:66
#define ERROR
Definition: elog.h:46
#define Assert(condition)
Definition: c.h:804
#define elog(elevel,...)
Definition: elog.h:232

◆ SlabReset()

static void SlabReset ( MemoryContext  context)
static

Definition at line 283 of file slab.c.

References Assert, SlabContext::blockSize, castNode, SlabContext::chunksPerBlock, dlist_mutable_iter::cur, dlist_container, dlist_delete(), dlist_foreach_modify, free, SlabContext::freelist, i, MemoryContextData::mem_allocated, SlabContext::minFreeChunks, and SlabContext::nblocks.

Referenced by SlabDelete().

284 {
285  int i;
286  SlabContext *slab = castNode(SlabContext, context);
287 
288  Assert(slab);
289 
290 #ifdef MEMORY_CONTEXT_CHECKING
291  /* Check for corruption and leaks before freeing */
292  SlabCheck(context);
293 #endif
294 
295  /* walk over freelists and free the blocks */
296  for (i = 0; i <= slab->chunksPerBlock; i++)
297  {
298  dlist_mutable_iter miter;
299 
300  dlist_foreach_modify(miter, &slab->freelist[i])
301  {
302  SlabBlock *block = dlist_container(SlabBlock, node, miter.cur);
303 
304  dlist_delete(miter.cur);
305 
306 #ifdef CLOBBER_FREED_MEMORY
307  wipe_mem(block, slab->blockSize);
308 #endif
309  free(block);
310  slab->nblocks--;
311  context->mem_allocated -= slab->blockSize;
312  }
313  }
314 
315  slab->minFreeChunks = 0;
316 
317  Assert(slab->nblocks == 0);
318  Assert(context->mem_allocated == 0);
319 }
dlist_node * cur
Definition: ilist.h:180
#define dlist_foreach_modify(iter, lhead)
Definition: ilist.h:543
int nblocks
Definition: slab.c:72
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
Size blockSize
Definition: slab.c:68
dlist_head freelist[FLEXIBLE_ARRAY_MEMBER]
Definition: slab.c:77
#define dlist_container(type, membername, ptr)
Definition: ilist.h:496
int chunksPerBlock
Definition: slab.c:70
static void dlist_delete(dlist_node *node)
Definition: ilist.h:358
#define free(a)
Definition: header.h:65
#define Assert(condition)
Definition: c.h:804
Size mem_allocated
Definition: memnodes.h:84
Definition: slab.c:88
int i
int minFreeChunks
Definition: slab.c:71

◆ SlabStats()

static void SlabStats ( MemoryContext  context,
MemoryStatsPrintFunc  printfunc,
void *  passthru,
MemoryContextCounters totals,
bool  print_to_stderr 
)
static

Definition at line 639 of file slab.c.

References Assert, SlabChunk::block, SlabContext::blockSize, castNode, SlabContext::chunkSize, SlabContext::chunksPerBlock, dlist_iter::cur, dlist_container, dlist_foreach, elog, SlabBlock::firstFreeChunk, MemoryContextCounters::freechunks, SlabContext::freelist, MemoryContextCounters::freespace, SlabContext::fullChunkSize, SlabContext::header, SlabContext::headerSize, i, idx(), MemoryContextData::mem_allocated, MemoryContextData::name, name, MemoryContextCounters::nblocks, SlabContext::nblocks, SlabBlock::nfree, SlabChunk::slab, SlabBlockGetChunk, SlabChunkGetPointer, snprintf, MemoryContextCounters::totalspace, VALGRIND_MAKE_MEM_DEFINED, and WARNING.

643 {
644  SlabContext *slab = castNode(SlabContext, context);
645  Size nblocks = 0;
646  Size freechunks = 0;
647  Size totalspace;
648  Size freespace = 0;
649  int i;
650 
651  /* Include context header in totalspace */
652  totalspace = slab->headerSize;
653 
654  for (i = 0; i <= slab->chunksPerBlock; i++)
655  {
656  dlist_iter iter;
657 
658  dlist_foreach(iter, &slab->freelist[i])
659  {
660  SlabBlock *block = dlist_container(SlabBlock, node, iter.cur);
661 
662  nblocks++;
663  totalspace += slab->blockSize;
664  freespace += slab->fullChunkSize * block->nfree;
665  freechunks += block->nfree;
666  }
667  }
668 
669  if (printfunc)
670  {
671  char stats_string[200];
672 
673  snprintf(stats_string, sizeof(stats_string),
674  "%zu total in %zd blocks; %zu free (%zd chunks); %zu used",
675  totalspace, nblocks, freespace, freechunks,
676  totalspace - freespace);
677  printfunc(context, passthru, stats_string, print_to_stderr);
678  }
679 
680  if (totals)
681  {
682  totals->nblocks += nblocks;
683  totals->freechunks += freechunks;
684  totals->totalspace += totalspace;
685  totals->freespace += freespace;
686  }
687 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
Size blockSize
Definition: slab.c:68
#define dlist_foreach(iter, lhead)
Definition: ilist.h:526
dlist_head freelist[FLEXIBLE_ARRAY_MEMBER]
Definition: slab.c:77
Size headerSize
Definition: slab.c:69
#define dlist_container(type, membername, ptr)
Definition: ilist.h:496
int chunksPerBlock
Definition: slab.c:70
Size fullChunkSize
Definition: slab.c:67
int nfree
Definition: slab.c:91
dlist_node * cur
Definition: ilist.h:161
size_t Size
Definition: c.h:540
Definition: slab.c:88
int i
#define snprintf
Definition: port.h:216

Variable Documentation

◆ SlabMethods

const MemoryContextMethods SlabMethods
static
Initial value:
= {
}
static Size SlabGetChunkSpace(MemoryContext context, void *pointer)
Definition: slab.c:606
static void SlabReset(MemoryContext context)
Definition: slab.c:283
static void * SlabRealloc(MemoryContext context, void *pointer, Size size)
Definition: slab.c:586
static void * SlabAlloc(MemoryContext context, Size size)
Definition: slab.c:340
static void SlabStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
Definition: slab.c:639
static bool SlabIsEmpty(MemoryContext context)
Definition: slab.c:620
static void SlabFree(MemoryContext context, void *pointer)
Definition: slab.c:498
static void SlabDelete(MemoryContext context)
Definition: slab.c:326

Definition at line 147 of file slab.c.