PostgreSQL Source Code  git master
slab.c File Reference
#include "postgres.h"
#include "utils/memdebug.h"
#include "utils/memutils.h"
#include "lib/ilist.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)
 
#define SlabFreeInfo(_cxt, _chunk)
 
#define SlabAllocInfo(_cxt, _chunk)
 

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)
 
MemoryContext SlabContextCreate (MemoryContext parent, const char *name, Size blockSize, Size chunkSize)
 

Variables

static const MemoryContextMethods SlabMethods
 

Macro Definition Documentation

◆ SlabAllocInfo

#define SlabAllocInfo (   _cxt,
  _chunk 
)

Definition at line 171 of file slab.c.

Referenced by SlabAlloc().

◆ SlabBlockGetChunk

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

Definition at line 116 of file slab.c.

Referenced by SlabAlloc(), and SlabStats().

◆ SlabBlockStart

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

Definition at line 119 of file slab.c.

◆ SlabChunkGetPointer

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

Definition at line 114 of file slab.c.

Referenced by SlabAlloc(), and SlabStats().

◆ SlabChunkIndex

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

Definition at line 121 of file slab.c.

Referenced by SlabFree().

◆ SlabFreeInfo

#define SlabFreeInfo (   _cxt,
  _chunk 
)

Definition at line 170 of file slab.c.

Referenced by SlabFree().

◆ SlabPointerGetChunk

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

Definition at line 112 of file slab.c.

Referenced by SlabFree().

Typedef Documentation

◆ SlabBlock

◆ SlabChunk

◆ SlabContext

Function Documentation

◆ SlabAlloc()

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

Definition at line 335 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, SlabContext::minFreeChunks, SlabContext::nblocks, SlabBlock::nfree, SlabBlock::node, SlabChunk::slab, SlabAllocInfo, SlabBlockGetChunk, SlabChunkGetPointer, VALGRIND_MAKE_MEM_DEFINED, VALGRIND_MAKE_MEM_NOACCESS, and VALGRIND_MAKE_MEM_UNDEFINED.

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

◆ SlabContextCreate()

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

Definition at line 188 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(), SlabContext::minFreeChunks, SlabContext::nblocks, offsetof, StaticAssertStmt, T_SlabContext, and TopMemoryContext.

Referenced by ReorderBufferAllocate().

192 {
193  int chunksPerBlock;
194  Size fullChunkSize;
195  Size freelistSize;
196  Size headerSize;
197  SlabContext *slab;
198  int i;
199 
200  /* Assert we padded SlabChunk properly */
201  StaticAssertStmt(sizeof(SlabChunk) == MAXALIGN(sizeof(SlabChunk)),
202  "sizeof(SlabChunk) is not maxaligned");
204  sizeof(SlabChunk),
205  "padding calculation in SlabChunk is wrong");
206 
207  /* Make sure the linked list node fits inside a freed chunk */
208  if (chunkSize < sizeof(int))
209  chunkSize = sizeof(int);
210 
211  /* chunk, including SLAB header (both addresses nicely aligned) */
212  fullChunkSize = sizeof(SlabChunk) + MAXALIGN(chunkSize);
213 
214  /* Make sure the block can store at least one chunk. */
215  if (blockSize < fullChunkSize + sizeof(SlabBlock))
216  elog(ERROR, "block size %zu for slab is too small for %zu chunks",
217  blockSize, chunkSize);
218 
219  /* Compute maximum number of chunks per block */
220  chunksPerBlock = (blockSize - sizeof(SlabBlock)) / fullChunkSize;
221 
222  /* The freelist starts with 0, ends with chunksPerBlock. */
223  freelistSize = sizeof(dlist_head) * (chunksPerBlock + 1);
224 
225  /*
226  * Allocate the context header. Unlike aset.c, we never try to combine
227  * this with the first regular block; not worth the extra complication.
228  */
229 
230  /* Size of the memory context header */
231  headerSize = offsetof(SlabContext, freelist) + freelistSize;
232 
233  slab = (SlabContext *) malloc(headerSize);
234  if (slab == NULL)
235  {
237  ereport(ERROR,
238  (errcode(ERRCODE_OUT_OF_MEMORY),
239  errmsg("out of memory"),
240  errdetail("Failed while creating memory context \"%s\".",
241  name)));
242  }
243 
244  /*
245  * Avoid writing code that can fail between here and MemoryContextCreate;
246  * we'd leak the header if we ereport in this stretch.
247  */
248 
249  /* Fill in SlabContext-specific header fields */
250  slab->chunkSize = chunkSize;
251  slab->fullChunkSize = fullChunkSize;
252  slab->blockSize = blockSize;
253  slab->headerSize = headerSize;
254  slab->chunksPerBlock = chunksPerBlock;
255  slab->minFreeChunks = 0;
256  slab->nblocks = 0;
257 
258  /* initialize the freelist slots */
259  for (i = 0; i < (slab->chunksPerBlock + 1); i++)
260  dlist_init(&slab->freelist[i]);
261 
262  /* Finally, do the type-independent part of context creation */
265  &SlabMethods,
266  parent,
267  name);
268 
269  return (MemoryContext) slab;
270 }
int nblocks
Definition: slab.c:73
Size blockSize
Definition: slab.c:69
struct dlist_head dlist_head
int errcode(int sqlerrcode)
Definition: elog.c:570
dlist_head freelist[FLEXIBLE_ARRAY_MEMBER]
Definition: slab.c:75
Size chunkSize
Definition: slab.c:67
#define malloc(a)
Definition: header.h:50
static const MemoryContextMethods SlabMethods
Definition: slab.c:144
Size headerSize
Definition: slab.c:70
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:842
#define ERROR
Definition: elog.h:43
int chunksPerBlock
Definition: slab.c:71
void MemoryContextStats(MemoryContext context)
Definition: mcxt.c:474
Size fullChunkSize
Definition: slab.c:68
int errdetail(const char *fmt,...)
Definition: elog.c:860
void MemoryContextCreate(MemoryContext node, NodeTag tag, const MemoryContextMethods *methods, MemoryContext parent, const char *name)
Definition: mcxt.c:724
#define ereport(elevel, rest)
Definition: elog.h:141
MemoryContext TopMemoryContext
Definition: mcxt.c:44
static void dlist_init(dlist_head *head)
Definition: ilist.h:278
struct SlabBlock SlabBlock
size_t Size
Definition: c.h:466
#define MAXALIGN(LEN)
Definition: c.h:685
const char * name
Definition: encode.c:521
Definition: slab.c:86
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
int i
int minFreeChunks
Definition: slab.c:72
struct SlabChunk SlabChunk
#define offsetof(type, field)
Definition: c.h:655

◆ SlabDelete()

static void SlabDelete ( MemoryContext  context)
static

Definition at line 321 of file slab.c.

References free, and SlabReset().

322 {
323  /* Reset to release all the SlabBlocks */
324  SlabReset(context);
325  /* And free the context header */
326  free(context);
327 }
static void SlabReset(MemoryContext context)
Definition: slab.c:280
#define free(a)
Definition: header.h:65

◆ SlabFree()

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

Definition at line 491 of file slab.c.

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

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

◆ SlabGetChunkSpace()

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

Definition at line 599 of file slab.c.

References Assert, castNode, and SlabContext::fullChunkSize.

600 {
601  SlabContext *slab = castNode(SlabContext, context);
602 
603  Assert(slab);
604 
605  return slab->fullChunkSize;
606 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
Size fullChunkSize
Definition: slab.c:68
#define Assert(condition)
Definition: c.h:732

◆ SlabIsEmpty()

static bool SlabIsEmpty ( MemoryContext  context)
static

Definition at line 613 of file slab.c.

References Assert, castNode, and SlabContext::nblocks.

614 {
615  SlabContext *slab = castNode(SlabContext, context);
616 
617  Assert(slab);
618 
619  return (slab->nblocks == 0);
620 }
int nblocks
Definition: slab.c:73
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
#define Assert(condition)
Definition: c.h:732

◆ SlabRealloc()

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

Definition at line 579 of file slab.c.

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

580 {
581  SlabContext *slab = castNode(SlabContext, context);
582 
583  Assert(slab);
584 
585  /* can't do actual realloc with slab, but let's try to be gentle */
586  if (size == slab->chunkSize)
587  return pointer;
588 
589  elog(ERROR, "slab allocator does not support realloc()");
590  return NULL; /* keep compiler quiet */
591 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
Size chunkSize
Definition: slab.c:67
#define ERROR
Definition: elog.h:43
#define Assert(condition)
Definition: c.h:732
#define elog(elevel,...)
Definition: elog.h:226

◆ SlabReset()

static void SlabReset ( MemoryContext  context)
static

Definition at line 280 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, SlabContext::minFreeChunks, and SlabContext::nblocks.

Referenced by SlabDelete().

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

◆ SlabStats()

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

Definition at line 631 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::name, name, MemoryContextCounters::nblocks, SlabContext::nblocks, SlabBlock::nfree, palloc(), SlabChunk::slab, SlabBlockGetChunk, SlabChunkGetPointer, snprintf, MemoryContextCounters::totalspace, VALGRIND_MAKE_MEM_DEFINED, and WARNING.

634 {
635  SlabContext *slab = castNode(SlabContext, context);
636  Size nblocks = 0;
637  Size freechunks = 0;
638  Size totalspace;
639  Size freespace = 0;
640  int i;
641 
642  /* Include context header in totalspace */
643  totalspace = slab->headerSize;
644 
645  for (i = 0; i <= slab->chunksPerBlock; i++)
646  {
647  dlist_iter iter;
648 
649  dlist_foreach(iter, &slab->freelist[i])
650  {
651  SlabBlock *block = dlist_container(SlabBlock, node, iter.cur);
652 
653  nblocks++;
654  totalspace += slab->blockSize;
655  freespace += slab->fullChunkSize * block->nfree;
656  freechunks += block->nfree;
657  }
658  }
659 
660  if (printfunc)
661  {
662  char stats_string[200];
663 
664  snprintf(stats_string, sizeof(stats_string),
665  "%zu total in %zd blocks; %zu free (%zd chunks); %zu used",
666  totalspace, nblocks, freespace, freechunks,
667  totalspace - freespace);
668  printfunc(context, passthru, stats_string);
669  }
670 
671  if (totals)
672  {
673  totals->nblocks += nblocks;
674  totals->freechunks += freechunks;
675  totals->totalspace += totalspace;
676  totals->freespace += freespace;
677  }
678 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
Size blockSize
Definition: slab.c:69
#define dlist_foreach(iter, lhead)
Definition: ilist.h:507
dlist_head freelist[FLEXIBLE_ARRAY_MEMBER]
Definition: slab.c:75
Size headerSize
Definition: slab.c:70
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
int chunksPerBlock
Definition: slab.c:71
Size fullChunkSize
Definition: slab.c:68
int nfree
Definition: slab.c:89
dlist_node * cur
Definition: ilist.h:161
size_t Size
Definition: c.h:466
Definition: slab.c:86
int i
#define snprintf
Definition: port.h:192

Variable Documentation

◆ SlabMethods

const MemoryContextMethods SlabMethods
static
Initial value:
= {
}
static Size SlabGetChunkSpace(MemoryContext context, void *pointer)
Definition: slab.c:599
static void SlabReset(MemoryContext context)
Definition: slab.c:280
static void * SlabRealloc(MemoryContext context, void *pointer, Size size)
Definition: slab.c:579
static void * SlabAlloc(MemoryContext context, Size size)
Definition: slab.c:335
static bool SlabIsEmpty(MemoryContext context)
Definition: slab.c:613
static void SlabFree(MemoryContext context, void *pointer)
Definition: slab.c:491
static void SlabDelete(MemoryContext context)
Definition: slab.c:321
static void SlabStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals)
Definition: slab.c:631

Definition at line 144 of file slab.c.