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

Go to the source code of this file.

Data Structures

struct  AllocSetContext
 
struct  AllocBlockData
 
struct  AllocChunkData
 

Macros

#define ALLOC_MINBITS   3 /* smallest chunk size is 8 bytes */
 
#define ALLOCSET_NUM_FREELISTS   11
 
#define ALLOC_CHUNK_LIMIT   (1 << (ALLOCSET_NUM_FREELISTS-1+ALLOC_MINBITS))
 
#define ALLOC_CHUNK_FRACTION   4
 
#define ALLOC_BLOCKHDRSZ   MAXALIGN(sizeof(AllocBlockData))
 
#define ALLOC_CHUNKHDRSZ   sizeof(struct AllocChunkData)
 
#define AllocPointerIsValid(pointer)   PointerIsValid(pointer)
 
#define AllocSetIsValid(set)   PointerIsValid(set)
 
#define AllocPointerGetChunk(ptr)   ((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ))
 
#define AllocChunkGetPointer(chk)   ((AllocPointer)(((char *)(chk)) + ALLOC_CHUNKHDRSZ))
 
#define LT16(n)   n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
 
#define AllocFreeInfo(_cxt, _chunk)
 
#define AllocAllocInfo(_cxt, _chunk)
 

Typedefs

typedef struct AllocBlockDataAllocBlock
 
typedef struct AllocChunkDataAllocChunk
 
typedef void * AllocPointer
 
typedef struct AllocSetContext AllocSetContext
 
typedef AllocSetContextAllocSet
 
typedef struct AllocBlockData AllocBlockData
 
typedef struct AllocChunkData AllocChunkData
 

Functions

static void * AllocSetAlloc (MemoryContext context, Size size)
 
static void AllocSetFree (MemoryContext context, void *pointer)
 
static void * AllocSetRealloc (MemoryContext context, void *pointer, Size size)
 
static void AllocSetInit (MemoryContext context)
 
static void AllocSetReset (MemoryContext context)
 
static void AllocSetDelete (MemoryContext context)
 
static Size AllocSetGetChunkSpace (MemoryContext context, void *pointer)
 
static bool AllocSetIsEmpty (MemoryContext context)
 
static void AllocSetStats (MemoryContext context, int level, bool print, MemoryContextCounters *totals)
 
static int AllocSetFreeIndex (Size size)
 
MemoryContext AllocSetContextCreate (MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
 

Variables

static MemoryContextMethods AllocSetMethods
 
static const unsigned char LogTable256 [256]
 

Macro Definition Documentation

◆ ALLOC_BLOCKHDRSZ

#define ALLOC_BLOCKHDRSZ   MAXALIGN(sizeof(AllocBlockData))

◆ ALLOC_CHUNK_FRACTION

#define ALLOC_CHUNK_FRACTION   4

Definition at line 85 of file aset.c.

Referenced by AllocSetContextCreate().

◆ ALLOC_CHUNK_LIMIT

#define ALLOC_CHUNK_LIMIT   (1 << (ALLOCSET_NUM_FREELISTS-1+ALLOC_MINBITS))

Definition at line 83 of file aset.c.

Referenced by AllocSetContextCreate().

◆ ALLOC_CHUNKHDRSZ

#define ALLOC_CHUNKHDRSZ   sizeof(struct AllocChunkData)

◆ ALLOC_MINBITS

#define ALLOC_MINBITS   3 /* smallest chunk size is 8 bytes */

Definition at line 81 of file aset.c.

Referenced by AllocSetAlloc(), AllocSetFreeIndex(), and AllocSetStats().

◆ AllocAllocInfo

#define AllocAllocInfo (   _cxt,
  _chunk 
)

Definition at line 259 of file aset.c.

Referenced by AllocSetAlloc().

◆ AllocChunkGetPointer

#define AllocChunkGetPointer (   chk)    ((AllocPointer)(((char *)(chk)) + ALLOC_CHUNKHDRSZ))

Definition at line 195 of file aset.c.

Referenced by AllocSetAlloc(), and AllocSetRealloc().

◆ AllocFreeInfo

#define AllocFreeInfo (   _cxt,
  _chunk 
)

Definition at line 258 of file aset.c.

Referenced by AllocSetFree().

◆ AllocPointerGetChunk

#define AllocPointerGetChunk (   ptr)    ((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ))

Definition at line 193 of file aset.c.

Referenced by AllocSetFree(), AllocSetGetChunkSpace(), and AllocSetRealloc().

◆ AllocPointerIsValid

#define AllocPointerIsValid (   pointer)    PointerIsValid(pointer)

Definition at line 185 of file aset.c.

◆ ALLOCSET_NUM_FREELISTS

#define ALLOCSET_NUM_FREELISTS   11

Definition at line 82 of file aset.c.

Referenced by AllocSetFreeIndex(), and AllocSetStats().

◆ AllocSetIsValid

#define AllocSetIsValid (   set)    PointerIsValid(set)

Definition at line 191 of file aset.c.

Referenced by AllocSetAlloc(), AllocSetDelete(), and AllocSetReset().

◆ LT16

#define LT16 (   n)    n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n

Definition at line 237 of file aset.c.

Typedef Documentation

◆ AllocBlock

Definition at line 102 of file aset.c.

◆ AllocBlockData

◆ AllocChunk

Definition at line 103 of file aset.c.

◆ AllocChunkData

◆ AllocPointer

Definition at line 109 of file aset.c.

◆ AllocSet

Definition at line 134 of file aset.c.

◆ AllocSetContext

Function Documentation

◆ AllocSetAlloc()

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

Definition at line 562 of file aset.c.

References ALLOC_BLOCKHDRSZ, ALLOC_CHUNKHDRSZ, ALLOC_MINBITS, AllocAllocInfo, AllocChunkGetPointer, AllocSetFreeIndex(), AllocSetIsValid, AllocBlockData::aset, AllocChunkData::aset, Assert, AssertArg, AllocBlockData::endptr, AllocBlockData::freeptr, malloc, MAXALIGN, AllocBlockData::next, AllocBlockData::prev, AllocChunkData::size, VALGRIND_MAKE_MEM_NOACCESS, and VALGRIND_MAKE_MEM_UNDEFINED.

Referenced by AllocSetRealloc().

563 {
564  AllocSet set = (AllocSet) context;
565  AllocBlock block;
566  AllocChunk chunk;
567  int fidx;
568  Size chunk_size;
569  Size blksize;
570 
572 
573  /*
574  * If requested size exceeds maximum for chunks, allocate an entire block
575  * for this request.
576  */
577  if (size > set->allocChunkLimit)
578  {
579  chunk_size = MAXALIGN(size);
580  blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
581  block = (AllocBlock) malloc(blksize);
582  if (block == NULL)
583  return NULL;
584  block->aset = set;
585  block->freeptr = block->endptr = ((char *) block) + blksize;
586 
587  chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
588  chunk->aset = set;
589  chunk->size = chunk_size;
590 #ifdef MEMORY_CONTEXT_CHECKING
591  /* Valgrind: Will be made NOACCESS below. */
592  chunk->requested_size = size;
593  /* set mark to catch clobber of "unused" space */
594  if (size < chunk_size)
595  set_sentinel(AllocChunkGetPointer(chunk), size);
596 #endif
597 #ifdef RANDOMIZE_ALLOCATED_MEMORY
598  /* fill the allocated space with junk */
599  randomize_mem((char *) AllocChunkGetPointer(chunk), size);
600 #endif
601 
602  /*
603  * Stick the new block underneath the active allocation block, if any,
604  * so that we don't lose the use of the space remaining therein.
605  */
606  if (set->blocks != NULL)
607  {
608  block->prev = set->blocks;
609  block->next = set->blocks->next;
610  if (block->next)
611  block->next->prev = block;
612  set->blocks->next = block;
613  }
614  else
615  {
616  block->prev = NULL;
617  block->next = NULL;
618  set->blocks = block;
619  }
620 
621  AllocAllocInfo(set, chunk);
622 
623  /*
624  * Chunk's metadata fields remain DEFINED. The requested allocation
625  * itself can be NOACCESS or UNDEFINED; our caller will soon make it
626  * UNDEFINED. Make extra space at the end of the chunk, if any,
627  * NOACCESS.
628  */
629  VALGRIND_MAKE_MEM_NOACCESS((char *) chunk + ALLOC_CHUNKHDRSZ,
630  chunk_size - ALLOC_CHUNKHDRSZ);
631 
632  return AllocChunkGetPointer(chunk);
633  }
634 
635  /*
636  * Request is small enough to be treated as a chunk. Look in the
637  * corresponding free list to see if there is a free chunk we could reuse.
638  * If one is found, remove it from the free list, make it again a member
639  * of the alloc set and return its data address.
640  */
641  fidx = AllocSetFreeIndex(size);
642  chunk = set->freelist[fidx];
643  if (chunk != NULL)
644  {
645  Assert(chunk->size >= size);
646 
647  set->freelist[fidx] = (AllocChunk) chunk->aset;
648 
649  chunk->aset = (void *) set;
650 
651 #ifdef MEMORY_CONTEXT_CHECKING
652  /* Valgrind: Free list requested_size should be DEFINED. */
653  chunk->requested_size = size;
654  VALGRIND_MAKE_MEM_NOACCESS(&chunk->requested_size,
655  sizeof(chunk->requested_size));
656  /* set mark to catch clobber of "unused" space */
657  if (size < chunk->size)
658  set_sentinel(AllocChunkGetPointer(chunk), size);
659 #endif
660 #ifdef RANDOMIZE_ALLOCATED_MEMORY
661  /* fill the allocated space with junk */
662  randomize_mem((char *) AllocChunkGetPointer(chunk), size);
663 #endif
664 
665  AllocAllocInfo(set, chunk);
666  return AllocChunkGetPointer(chunk);
667  }
668 
669  /*
670  * Choose the actual chunk size to allocate.
671  */
672  chunk_size = (1 << ALLOC_MINBITS) << fidx;
673  Assert(chunk_size >= size);
674 
675  /*
676  * If there is enough room in the active allocation block, we will put the
677  * chunk into that block. Else must start a new one.
678  */
679  if ((block = set->blocks) != NULL)
680  {
681  Size availspace = block->endptr - block->freeptr;
682 
683  if (availspace < (chunk_size + ALLOC_CHUNKHDRSZ))
684  {
685  /*
686  * The existing active (top) block does not have enough room for
687  * the requested allocation, but it might still have a useful
688  * amount of space in it. Once we push it down in the block list,
689  * we'll never try to allocate more space from it. So, before we
690  * do that, carve up its free space into chunks that we can put on
691  * the set's freelists.
692  *
693  * Because we can only get here when there's less than
694  * ALLOC_CHUNK_LIMIT left in the block, this loop cannot iterate
695  * more than ALLOCSET_NUM_FREELISTS-1 times.
696  */
697  while (availspace >= ((1 << ALLOC_MINBITS) + ALLOC_CHUNKHDRSZ))
698  {
699  Size availchunk = availspace - ALLOC_CHUNKHDRSZ;
700  int a_fidx = AllocSetFreeIndex(availchunk);
701 
702  /*
703  * In most cases, we'll get back the index of the next larger
704  * freelist than the one we need to put this chunk on. The
705  * exception is when availchunk is exactly a power of 2.
706  */
707  if (availchunk != ((Size) 1 << (a_fidx + ALLOC_MINBITS)))
708  {
709  a_fidx--;
710  Assert(a_fidx >= 0);
711  availchunk = ((Size) 1 << (a_fidx + ALLOC_MINBITS));
712  }
713 
714  chunk = (AllocChunk) (block->freeptr);
715 
716  /* Prepare to initialize the chunk header. */
717  VALGRIND_MAKE_MEM_UNDEFINED(chunk, ALLOC_CHUNKHDRSZ);
718 
719  block->freeptr += (availchunk + ALLOC_CHUNKHDRSZ);
720  availspace -= (availchunk + ALLOC_CHUNKHDRSZ);
721 
722  chunk->size = availchunk;
723 #ifdef MEMORY_CONTEXT_CHECKING
724  chunk->requested_size = 0; /* mark it free */
725 #endif
726  chunk->aset = (void *) set->freelist[a_fidx];
727  set->freelist[a_fidx] = chunk;
728  }
729 
730  /* Mark that we need to create a new block */
731  block = NULL;
732  }
733  }
734 
735  /*
736  * Time to create a new regular (multi-chunk) block?
737  */
738  if (block == NULL)
739  {
740  Size required_size;
741 
742  /*
743  * The first such block has size initBlockSize, and we double the
744  * space in each succeeding block, but not more than maxBlockSize.
745  */
746  blksize = set->nextBlockSize;
747  set->nextBlockSize <<= 1;
748  if (set->nextBlockSize > set->maxBlockSize)
749  set->nextBlockSize = set->maxBlockSize;
750 
751  /*
752  * If initBlockSize is less than ALLOC_CHUNK_LIMIT, we could need more
753  * space... but try to keep it a power of 2.
754  */
755  required_size = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
756  while (blksize < required_size)
757  blksize <<= 1;
758 
759  /* Try to allocate it */
760  block = (AllocBlock) malloc(blksize);
761 
762  /*
763  * We could be asking for pretty big blocks here, so cope if malloc
764  * fails. But give up if there's less than a meg or so available...
765  */
766  while (block == NULL && blksize > 1024 * 1024)
767  {
768  blksize >>= 1;
769  if (blksize < required_size)
770  break;
771  block = (AllocBlock) malloc(blksize);
772  }
773 
774  if (block == NULL)
775  return NULL;
776 
777  block->aset = set;
778  block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
779  block->endptr = ((char *) block) + blksize;
780 
781  /*
782  * If this is the first block of the set, make it the "keeper" block.
783  * Formerly, a keeper block could only be created during context
784  * creation, but allowing it to happen here lets us have fast reset
785  * cycling even for contexts created with minContextSize = 0; that way
786  * we don't have to force space to be allocated in contexts that might
787  * never need any space. Don't mark an oversize block as a keeper,
788  * however.
789  */
790  if (set->keeper == NULL && blksize == set->initBlockSize)
791  set->keeper = block;
792 
793  /* Mark unallocated space NOACCESS. */
795  blksize - ALLOC_BLOCKHDRSZ);
796 
797  block->prev = NULL;
798  block->next = set->blocks;
799  if (block->next)
800  block->next->prev = block;
801  set->blocks = block;
802  }
803 
804  /*
805  * OK, do the allocation
806  */
807  chunk = (AllocChunk) (block->freeptr);
808 
809  /* Prepare to initialize the chunk header. */
810  VALGRIND_MAKE_MEM_UNDEFINED(chunk, ALLOC_CHUNKHDRSZ);
811 
812  block->freeptr += (chunk_size + ALLOC_CHUNKHDRSZ);
813  Assert(block->freeptr <= block->endptr);
814 
815  chunk->aset = (void *) set;
816  chunk->size = chunk_size;
817 #ifdef MEMORY_CONTEXT_CHECKING
818  chunk->requested_size = size;
819  VALGRIND_MAKE_MEM_NOACCESS(&chunk->requested_size,
820  sizeof(chunk->requested_size));
821  /* set mark to catch clobber of "unused" space */
822  if (size < chunk->size)
823  set_sentinel(AllocChunkGetPointer(chunk), size);
824 #endif
825 #ifdef RANDOMIZE_ALLOCATED_MEMORY
826  /* fill the allocated space with junk */
827  randomize_mem((char *) AllocChunkGetPointer(chunk), size);
828 #endif
829 
830  AllocAllocInfo(set, chunk);
831  return AllocChunkGetPointer(chunk);
832 }
#define AllocSetIsValid(set)
Definition: aset.c:191
#define VALGRIND_MAKE_MEM_UNDEFINED(addr, size)
Definition: memdebug.h:28
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition: memdebug.h:27
static int AllocSetFreeIndex(Size size)
Definition: aset.c:271
#define AllocChunkGetPointer(chk)
Definition: aset.c:195
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:99
AllocSet aset
Definition: aset.c:150
char * freeptr
Definition: aset.c:153
#define malloc(a)
Definition: header.h:50
char * endptr
Definition: aset.c:154
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:100
AllocBlock next
Definition: aset.c:152
#define AssertArg(condition)
Definition: c.h:672
struct AllocBlockData * AllocBlock
Definition: aset.c:102
AllocBlock prev
Definition: aset.c:151
struct AllocChunkData * AllocChunk
Definition: aset.c:103
#define Assert(condition)
Definition: c.h:670
size_t Size
Definition: c.h:404
#define MAXALIGN(LEN)
Definition: c.h:623
void * aset
Definition: aset.c:176
AllocSetContext * AllocSet
Definition: aset.c:134
#define ALLOC_MINBITS
Definition: aset.c:81
#define AllocAllocInfo(_cxt, _chunk)
Definition: aset.c:259
Size size
Definition: aset.c:164

◆ AllocSetContextCreate()

MemoryContext AllocSetContextCreate ( MemoryContext  parent,
const char *  name,
Size  minContextSize,
Size  initBlockSize,
Size  maxBlockSize 
)

Definition at line 322 of file aset.c.

References ALLOC_BLOCKHDRSZ, ALLOC_CHUNK_FRACTION, ALLOC_CHUNK_LIMIT, ALLOC_CHUNKHDRSZ, AllocHugeSizeIsValid, ALLOCSET_SEPARATE_THRESHOLD, AllocSetMethods, AllocBlockData::aset, elog, AllocBlockData::endptr, ereport, errcode(), errdetail(), errmsg(), ERROR, AllocBlockData::freeptr, AllocSetContext::initBlockSize, malloc, MAXALIGN, AllocSetContext::maxBlockSize, MemoryContextCreate(), MemoryContextStats(), name, AllocBlockData::next, offsetof, AllocBlockData::prev, StaticAssertStmt, T_AllocSetContext, TopMemoryContext, and VALGRIND_MAKE_MEM_NOACCESS.

Referenced by _bt_preprocess_array_keys(), _SPI_make_plan_non_temp(), _SPI_save_plan(), afterTriggerAddEvent(), afterTriggerInvokeEvents(), AllocateSnapshotBuilder(), ApplyLauncherMain(), ApplyWorkerMain(), AtStart_Memory(), AtSubStart_Memory(), AutoVacLauncherMain(), BackgroundWriterMain(), begin_heap_rewrite(), BeginCopy(), blbuild(), blinsert(), brin_build_desc(), brin_new_memtuple(), bringetbitmap(), brininsert(), bt_check_every_level(), btvacuumscan(), BuildCachedPlan(), BuildEventTriggerCache(), BuildRelationExtStatistics(), CheckpointerMain(), cluster(), compile_plperl_function(), compile_pltcl_function(), CompleteCachedPlan(), compute_index_stats(), CopyCachedPlan(), CopyTo(), CreateCachedPlan(), CreateCacheMemoryContext(), CreateExecutorState(), CreateExprContext(), CreatePortal(), CreateStandaloneExprContext(), createTempGistContext(), createTrgmNFA(), DiscreteKnapsack(), do_analyze_rel(), do_autovacuum(), do_compile(), do_start_worker(), each_worker(), each_worker_jsonb(), elements_worker(), elements_worker_jsonb(), EnablePortalManager(), EventTriggerBeginCompleteQuery(), EventTriggerInvoke(), exec_parse_message(), exec_replication_command(), ExecHashTableCreate(), ExecInitFunctionScan(), ExecInitProjectSet(), ExecInitRecursiveUnion(), ExecInitSetOp(), ExecInitSubPlan(), ExecInitTableFuncScan(), ExecInitUnique(), ExecInitWindowAgg(), expand_array(), file_acquire_sample_rows(), fill_hba_view(), geqo_eval(), get_stmt_mcontext(), GetLocalBufferStorage(), GetMemoryChunkContext(), gin_xlog_startup(), ginbeginscan(), ginbuild(), ginbulkdelete(), gininsert(), ginInsertCleanup(), ginPlaceToPage(), gistrescan(), HandleParallelMessages(), hash_create(), index_register(), init_MultiFuncCall(), init_sql_fcache(), initArrayResult(), initArrayResultArr(), initGISTstate(), initialize_peragg(), InitXLogInsert(), inline_function(), inline_set_returning_function(), libpqrcv_processTuples(), load_domaintype_info(), load_hba(), load_ident(), load_relcache_init_file(), load_tzoffsets(), logicalrep_relmap_init(), LogicalRepApplyLoop(), lookup_ts_dictionary_cache(), materializeQueryResult(), mdinit(), MemoryContextInit(), mXactCachePut(), NIStartBuild(), ParallelWorkerMain(), PerformAuthentication(), pg_decode_startup(), pgoutput_startup(), pgstat_setup_memcxt(), plperl_return_next_internal(), plperl_spi_prepare(), plpgsql_compile_inline(), plpgsql_estate_setup(), plpython_inline_handler(), pltcl_SPI_prepare(), PLy_cursor_plan(), PLy_cursor_query(), PLy_get_scratch_context(), PLy_procedure_create(), PLy_spi_execute_fetch_result(), PLy_spi_prepare(), PortalCreateHoldStore(), postgresAcquireSampleRowsFunc(), postgresBeginDirectModify(), postgresBeginForeignModify(), postgresBeginForeignScan(), PostgresMain(), PostmasterMain(), printtup_startup(), publicationListToArray(), rebuild_database_list(), ReindexMultipleTables(), RelationBuildPartitionDesc(), RelationBuildPartitionKey(), RelationBuildRowSecurity(), RelationBuildRuleLock(), RelationInitIndexAccessInfo(), ReorderBufferAllocate(), ResetUnloggedRelations(), RevalidateCachedQuery(), sepgsql_avc_init(), spg_xlog_startup(), spgbeginscan(), spgbuild(), spginsert(), SPI_connect(), spi_dest_startup(), StartupDecodingContext(), strlist_to_textarray(), tokenize_file(), tuplesort_begin_common(), union_tuples(), vacuum(), WalWriterMain(), XLOGShmemInit(), and xml_is_document().

327 {
328  AllocSet set;
329 
331  MAXALIGN(sizeof(AllocChunkData)),
332  "padding calculation in AllocChunkData is wrong");
333 
334  /*
335  * First, validate allocation parameters. (If we're going to throw an
336  * error, we should do so before the context is created, not after.) We
337  * somewhat arbitrarily enforce a minimum 1K block size.
338  */
339  if (initBlockSize != MAXALIGN(initBlockSize) ||
340  initBlockSize < 1024)
341  elog(ERROR, "invalid initBlockSize for memory context: %zu",
342  initBlockSize);
343  if (maxBlockSize != MAXALIGN(maxBlockSize) ||
344  maxBlockSize < initBlockSize ||
345  !AllocHugeSizeIsValid(maxBlockSize)) /* must be safe to double */
346  elog(ERROR, "invalid maxBlockSize for memory context: %zu",
347  maxBlockSize);
348  if (minContextSize != 0 &&
349  (minContextSize != MAXALIGN(minContextSize) ||
350  minContextSize <= ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
351  elog(ERROR, "invalid minContextSize for memory context: %zu",
352  minContextSize);
353 
354  /* Do the type-independent part of context creation */
356  sizeof(AllocSetContext),
358  parent,
359  name);
360 
361  /* Save allocation parameters */
362  set->initBlockSize = initBlockSize;
363  set->maxBlockSize = maxBlockSize;
364  set->nextBlockSize = initBlockSize;
365 
366  /*
367  * Compute the allocation chunk size limit for this context. It can't be
368  * more than ALLOC_CHUNK_LIMIT because of the fixed number of freelists.
369  * If maxBlockSize is small then requests exceeding the maxBlockSize, or
370  * even a significant fraction of it, should be treated as large chunks
371  * too. For the typical case of maxBlockSize a power of 2, the chunk size
372  * limit will be at most 1/8th maxBlockSize, so that given a stream of
373  * requests that are all the maximum chunk size we will waste at most
374  * 1/8th of the allocated space.
375  *
376  * We have to have allocChunkLimit a power of two, because the requested
377  * and actually-allocated sizes of any chunk must be on the same side of
378  * the limit, else we get confused about whether the chunk is "big".
379  *
380  * Also, allocChunkLimit must not exceed ALLOCSET_SEPARATE_THRESHOLD.
381  */
383  "ALLOC_CHUNK_LIMIT != ALLOCSET_SEPARATE_THRESHOLD");
384 
385  set->allocChunkLimit = ALLOC_CHUNK_LIMIT;
386  while ((Size) (set->allocChunkLimit + ALLOC_CHUNKHDRSZ) >
387  (Size) ((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION))
388  set->allocChunkLimit >>= 1;
389 
390  /*
391  * Grab always-allocated space, if requested
392  */
393  if (minContextSize > 0)
394  {
395  Size blksize = minContextSize;
396  AllocBlock block;
397 
398  block = (AllocBlock) malloc(blksize);
399  if (block == NULL)
400  {
402  ereport(ERROR,
403  (errcode(ERRCODE_OUT_OF_MEMORY),
404  errmsg("out of memory"),
405  errdetail("Failed while creating memory context \"%s\".",
406  name)));
407  }
408  block->aset = set;
409  block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
410  block->endptr = ((char *) block) + blksize;
411  block->prev = NULL;
412  block->next = set->blocks;
413  if (block->next)
414  block->next->prev = block;
415  set->blocks = block;
416  /* Mark block as not to be released at reset time */
417  set->keeper = block;
418 
419  /* Mark unallocated space NOACCESS; leave the block header alone. */
421  blksize - ALLOC_BLOCKHDRSZ);
422  }
423 
424  return (MemoryContext) set;
425 }
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition: memdebug.h:27
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:99
AllocSet aset
Definition: aset.c:150
char * freeptr
Definition: aset.c:153
#define malloc(a)
Definition: header.h:50
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:753
#define ERROR
Definition: elog.h:43
#define ALLOC_CHUNK_LIMIT
Definition: aset.c:83
void MemoryContextStats(MemoryContext context)
Definition: mcxt.c:437
char * endptr
Definition: aset.c:154
#define ALLOCSET_SEPARATE_THRESHOLD
Definition: memutils.h:192
int errdetail(const char *fmt,...)
Definition: elog.c:873
MemoryContext MemoryContextCreate(NodeTag tag, Size size, MemoryContextMethods *methods, MemoryContext parent, const char *name)
Definition: mcxt.c:639
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:100
static MemoryContextMethods AllocSetMethods
Definition: aset.c:219
AllocBlock next
Definition: aset.c:152
#define ereport(elevel, rest)
Definition: elog.h:122
MemoryContext TopMemoryContext
Definition: mcxt.c:43
#define ALLOC_CHUNK_FRACTION
Definition: aset.c:85
struct AllocBlockData * AllocBlock
Definition: aset.c:102
AllocBlock prev
Definition: aset.c:151
size_t Size
Definition: c.h:404
#define MAXALIGN(LEN)
Definition: c.h:623
const char * name
Definition: encode.c:521
#define AllocHugeSizeIsValid(size)
Definition: memutils.h:46
int errmsg(const char *fmt,...)
Definition: elog.c:797
AllocSetContext * AllocSet
Definition: aset.c:134
#define elog
Definition: elog.h:219
#define offsetof(type, field)
Definition: c.h:593

◆ AllocSetDelete()

static void AllocSetDelete ( MemoryContext  context)
static

Definition at line 523 of file aset.c.

References AllocSetIsValid, AssertArg, free, AllocBlockData::freeptr, MemSetAligned, AllocBlockData::next, and next.

524 {
525  AllocSet set = (AllocSet) context;
526  AllocBlock block = set->blocks;
527 
529 
530 #ifdef MEMORY_CONTEXT_CHECKING
531  /* Check for corruption and leaks before freeing */
532  AllocSetCheck(context);
533 #endif
534 
535  /* Make it look empty, just in case... */
536  MemSetAligned(set->freelist, 0, sizeof(set->freelist));
537  set->blocks = NULL;
538  set->keeper = NULL;
539 
540  while (block != NULL)
541  {
542  AllocBlock next = block->next;
543 
544 #ifdef CLOBBER_FREED_MEMORY
545  wipe_mem(block, block->freeptr - ((char *) block));
546 #endif
547  free(block);
548  block = next;
549  }
550 }
#define MemSetAligned(start, val, len)
Definition: c.h:886
static int32 next
Definition: blutils.c:210
#define AllocSetIsValid(set)
Definition: aset.c:191
char * freeptr
Definition: aset.c:153
AllocBlock next
Definition: aset.c:152
#define AssertArg(condition)
Definition: c.h:672
#define free(a)
Definition: header.h:65
AllocSetContext * AllocSet
Definition: aset.c:134

◆ AllocSetFree()

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

Definition at line 839 of file aset.c.

References ALLOC_BLOCKHDRSZ, ALLOC_CHUNKHDRSZ, AllocFreeInfo, AllocPointerGetChunk, AllocSetFreeIndex(), AllocBlockData::aset, AllocChunkData::aset, elog, AllocBlockData::endptr, ERROR, free, AllocBlockData::freeptr, AllocChunkData::size, VALGRIND_MAKE_MEM_DEFINED, and WARNING.

Referenced by AllocSetRealloc().

840 {
841  AllocSet set = (AllocSet) context;
842  AllocChunk chunk = AllocPointerGetChunk(pointer);
843 
844  AllocFreeInfo(set, chunk);
845 
846 #ifdef MEMORY_CONTEXT_CHECKING
847  VALGRIND_MAKE_MEM_DEFINED(&chunk->requested_size,
848  sizeof(chunk->requested_size));
849  /* Test for someone scribbling on unused space in chunk */
850  if (chunk->requested_size < chunk->size)
851  if (!sentinel_ok(pointer, chunk->requested_size))
852  elog(WARNING, "detected write past chunk end in %s %p",
853  set->header.name, chunk);
854 #endif
855 
856  if (chunk->size > set->allocChunkLimit)
857  {
858  /*
859  * Big chunks are certain to have been allocated as single-chunk
860  * blocks. Just unlink that block and return it to malloc().
861  */
862  AllocBlock block = (AllocBlock) (((char *) chunk) - ALLOC_BLOCKHDRSZ);
863 
864  /*
865  * Try to verify that we have a sane block pointer: it should
866  * reference the correct aset, and freeptr and endptr should point
867  * just past the chunk.
868  */
869  if (block->aset != set ||
870  block->freeptr != block->endptr ||
871  block->freeptr != ((char *) block) +
872  (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
873  elog(ERROR, "could not find block containing chunk %p", chunk);
874 
875  /* OK, remove block from aset's list and free it */
876  if (block->prev)
877  block->prev->next = block->next;
878  else
879  set->blocks = block->next;
880  if (block->next)
881  block->next->prev = block->prev;
882 #ifdef CLOBBER_FREED_MEMORY
883  wipe_mem(block, block->freeptr - ((char *) block));
884 #endif
885  free(block);
886  }
887  else
888  {
889  /* Normal case, put the chunk into appropriate freelist */
890  int fidx = AllocSetFreeIndex(chunk->size);
891 
892  chunk->aset = (void *) set->freelist[fidx];
893 
894 #ifdef CLOBBER_FREED_MEMORY
895  wipe_mem(pointer, chunk->size);
896 #endif
897 
898 #ifdef MEMORY_CONTEXT_CHECKING
899  /* Reset requested_size to 0 in chunks that are on freelist */
900  chunk->requested_size = 0;
901 #endif
902  set->freelist[fidx] = chunk;
903  }
904 }
#define AllocFreeInfo(_cxt, _chunk)
Definition: aset.c:258
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
static int AllocSetFreeIndex(Size size)
Definition: aset.c:271
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:99
AllocSet aset
Definition: aset.c:150
char * freeptr
Definition: aset.c:153
#define ERROR
Definition: elog.h:43
char * endptr
Definition: aset.c:154
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:100
#define WARNING
Definition: elog.h:40
struct AllocBlockData * AllocBlock
Definition: aset.c:102
#define free(a)
Definition: header.h:65
AllocSetContext * AllocSet
Definition: aset.c:134
#define elog
Definition: elog.h:219
Size size
Definition: aset.c:164
#define AllocPointerGetChunk(ptr)
Definition: aset.c:193

◆ AllocSetFreeIndex()

static int AllocSetFreeIndex ( Size  size)
inlinestatic

Definition at line 271 of file aset.c.

References ALLOC_MINBITS, ALLOCSET_NUM_FREELISTS, Assert, idx(), and LogTable256.

Referenced by AllocSetAlloc(), and AllocSetFree().

272 {
273  int idx;
274  unsigned int t,
275  tsize;
276 
277  if (size > (1 << ALLOC_MINBITS))
278  {
279  tsize = (size - 1) >> ALLOC_MINBITS;
280 
281  /*
282  * At this point we need to obtain log2(tsize)+1, ie, the number of
283  * not-all-zero bits at the right. We used to do this with a
284  * shift-and-count loop, but this function is enough of a hotspot to
285  * justify micro-optimization effort. The best approach seems to be
286  * to use a lookup table. Note that this code assumes that
287  * ALLOCSET_NUM_FREELISTS <= 17, since we only cope with two bytes of
288  * the tsize value.
289  */
290  t = tsize >> 8;
291  idx = t ? LogTable256[t] + 8 : LogTable256[tsize];
292 
294  }
295  else
296  idx = 0;
297 
298  return idx;
299 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:264
#define ALLOCSET_NUM_FREELISTS
Definition: aset.c:82
static const unsigned char LogTable256[256]
Definition: aset.c:239
#define Assert(condition)
Definition: c.h:670
#define ALLOC_MINBITS
Definition: aset.c:81

◆ AllocSetGetChunkSpace()

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

Definition at line 1114 of file aset.c.

References ALLOC_CHUNKHDRSZ, AllocPointerGetChunk, and AllocChunkData::size.

1115 {
1116  AllocChunk chunk = AllocPointerGetChunk(pointer);
1117 
1118  return chunk->size + ALLOC_CHUNKHDRSZ;
1119 }
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:100
Size size
Definition: aset.c:164
#define AllocPointerGetChunk(ptr)
Definition: aset.c:193

◆ AllocSetInit()

static void AllocSetInit ( MemoryContext  context)
static

Definition at line 440 of file aset.c.

441 {
442  /*
443  * Since MemoryContextCreate already zeroed the context node, we don't
444  * have to do anything here: it's already OK.
445  */
446 }

◆ AllocSetIsEmpty()

static bool AllocSetIsEmpty ( MemoryContext  context)
static

Definition at line 1126 of file aset.c.

References MemoryContextData::isReset.

1127 {
1128  /*
1129  * For now, we say "empty" only if the context is new or just reset. We
1130  * could examine the freelists to determine if all space has been freed,
1131  * but it's not really worth the trouble for present uses of this
1132  * functionality.
1133  */
1134  if (context->isReset)
1135  return true;
1136  return false;
1137 }

◆ AllocSetRealloc()

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

Definition at line 919 of file aset.c.

References ALLOC_BLOCKHDRSZ, ALLOC_CHUNKHDRSZ, AllocChunkGetPointer, AllocPointerGetChunk, AllocSetAlloc(), AllocSetFree(), AllocBlockData::aset, elog, AllocBlockData::endptr, ERROR, AllocBlockData::freeptr, MAXALIGN, realloc, AllocChunkData::size, VALGRIND_MAKE_MEM_DEFINED, VALGRIND_MAKE_MEM_NOACCESS, VALGRIND_MAKE_MEM_UNDEFINED, and WARNING.

920 {
921  AllocSet set = (AllocSet) context;
922  AllocChunk chunk = AllocPointerGetChunk(pointer);
923  Size oldsize = chunk->size;
924 
925 #ifdef MEMORY_CONTEXT_CHECKING
926  VALGRIND_MAKE_MEM_DEFINED(&chunk->requested_size,
927  sizeof(chunk->requested_size));
928  /* Test for someone scribbling on unused space in chunk */
929  if (chunk->requested_size < oldsize)
930  if (!sentinel_ok(pointer, chunk->requested_size))
931  elog(WARNING, "detected write past chunk end in %s %p",
932  set->header.name, chunk);
933 #endif
934 
935  /*
936  * Chunk sizes are aligned to power of 2 in AllocSetAlloc(). Maybe the
937  * allocated area already is >= the new size. (In particular, we always
938  * fall out here if the requested size is a decrease.)
939  */
940  if (oldsize >= size)
941  {
942 #ifdef MEMORY_CONTEXT_CHECKING
943  Size oldrequest = chunk->requested_size;
944 
945 #ifdef RANDOMIZE_ALLOCATED_MEMORY
946  /* We can only fill the extra space if we know the prior request */
947  if (size > oldrequest)
948  randomize_mem((char *) pointer + oldrequest,
949  size - oldrequest);
950 #endif
951 
952  chunk->requested_size = size;
953  VALGRIND_MAKE_MEM_NOACCESS(&chunk->requested_size,
954  sizeof(chunk->requested_size));
955 
956  /*
957  * If this is an increase, mark any newly-available part UNDEFINED.
958  * Otherwise, mark the obsolete part NOACCESS.
959  */
960  if (size > oldrequest)
961  VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + oldrequest,
962  size - oldrequest);
963  else
964  VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size,
965  oldsize - size);
966 
967  /* set mark to catch clobber of "unused" space */
968  if (size < oldsize)
969  set_sentinel(pointer, size);
970 #else /* !MEMORY_CONTEXT_CHECKING */
971 
972  /*
973  * We don't have the information to determine whether we're growing
974  * the old request or shrinking it, so we conservatively mark the
975  * entire new allocation DEFINED.
976  */
977  VALGRIND_MAKE_MEM_NOACCESS(pointer, oldsize);
978  VALGRIND_MAKE_MEM_DEFINED(pointer, size);
979 #endif
980 
981  return pointer;
982  }
983 
984  if (oldsize > set->allocChunkLimit)
985  {
986  /*
987  * The chunk must have been allocated as a single-chunk block. Use
988  * realloc() to make the containing block bigger with minimum space
989  * wastage.
990  */
991  AllocBlock block = (AllocBlock) (((char *) chunk) - ALLOC_BLOCKHDRSZ);
992  Size chksize;
993  Size blksize;
994 
995  /*
996  * Try to verify that we have a sane block pointer: it should
997  * reference the correct aset, and freeptr and endptr should point
998  * just past the chunk.
999  */
1000  if (block->aset != set ||
1001  block->freeptr != block->endptr ||
1002  block->freeptr != ((char *) block) +
1003  (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
1004  elog(ERROR, "could not find block containing chunk %p", chunk);
1005 
1006  /* Do the realloc */
1007  chksize = MAXALIGN(size);
1008  blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
1009  block = (AllocBlock) realloc(block, blksize);
1010  if (block == NULL)
1011  return NULL;
1012  block->freeptr = block->endptr = ((char *) block) + blksize;
1013 
1014  /* Update pointers since block has likely been moved */
1015  chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
1016  pointer = AllocChunkGetPointer(chunk);
1017  if (block->prev)
1018  block->prev->next = block;
1019  else
1020  set->blocks = block;
1021  if (block->next)
1022  block->next->prev = block;
1023  chunk->size = chksize;
1024 
1025 #ifdef MEMORY_CONTEXT_CHECKING
1026 #ifdef RANDOMIZE_ALLOCATED_MEMORY
1027  /* We can only fill the extra space if we know the prior request */
1028  randomize_mem((char *) pointer + chunk->requested_size,
1029  size - chunk->requested_size);
1030 #endif
1031 
1032  /*
1033  * realloc() (or randomize_mem()) will have left the newly-allocated
1034  * part UNDEFINED, but we may need to adjust trailing bytes from the
1035  * old allocation.
1036  */
1037  VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + chunk->requested_size,
1038  oldsize - chunk->requested_size);
1039 
1040  chunk->requested_size = size;
1041  VALGRIND_MAKE_MEM_NOACCESS(&chunk->requested_size,
1042  sizeof(chunk->requested_size));
1043 
1044  /* set mark to catch clobber of "unused" space */
1045  if (size < chunk->size)
1046  set_sentinel(pointer, size);
1047 #else /* !MEMORY_CONTEXT_CHECKING */
1048 
1049  /*
1050  * We don't know how much of the old chunk size was the actual
1051  * allocation; it could have been as small as one byte. We have to be
1052  * conservative and just mark the entire old portion DEFINED.
1053  */
1054  VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
1055 #endif
1056 
1057  /* Make any trailing alignment padding NOACCESS. */
1058  VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size, chksize - size);
1059 
1060  return pointer;
1061  }
1062  else
1063  {
1064  /*
1065  * Small-chunk case. We just do this by brute force, ie, allocate a
1066  * new chunk and copy the data. Since we know the existing data isn't
1067  * huge, this won't involve any great memcpy expense, so it's not
1068  * worth being smarter. (At one time we tried to avoid memcpy when it
1069  * was possible to enlarge the chunk in-place, but that turns out to
1070  * misbehave unpleasantly for repeated cycles of
1071  * palloc/repalloc/pfree: the eventually freed chunks go into the
1072  * wrong freelist for the next initial palloc request, and so we leak
1073  * memory indefinitely. See pgsql-hackers archives for 2007-08-11.)
1074  */
1075  AllocPointer newPointer;
1076 
1077  /* allocate new chunk */
1078  newPointer = AllocSetAlloc((MemoryContext) set, size);
1079 
1080  /* leave immediately if request was not completed */
1081  if (newPointer == NULL)
1082  return NULL;
1083 
1084  /*
1085  * AllocSetAlloc() just made the region NOACCESS. Change it to
1086  * UNDEFINED for the moment; memcpy() will then transfer definedness
1087  * from the old allocation to the new. If we know the old allocation,
1088  * copy just that much. Otherwise, make the entire old chunk defined
1089  * to avoid errors as we copy the currently-NOACCESS trailing bytes.
1090  */
1091  VALGRIND_MAKE_MEM_UNDEFINED(newPointer, size);
1092 #ifdef MEMORY_CONTEXT_CHECKING
1093  oldsize = chunk->requested_size;
1094 #else
1095  VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
1096 #endif
1097 
1098  /* transfer existing data (certain to fit) */
1099  memcpy(newPointer, pointer, oldsize);
1100 
1101  /* free old chunk */
1102  AllocSetFree((MemoryContext) set, pointer);
1103 
1104  return newPointer;
1105  }
1106 }
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
void * AllocPointer
Definition: aset.c:109
#define VALGRIND_MAKE_MEM_UNDEFINED(addr, size)
Definition: memdebug.h:28
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition: memdebug.h:27
#define AllocChunkGetPointer(chk)
Definition: aset.c:195
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:99
AllocSet aset
Definition: aset.c:150
char * freeptr
Definition: aset.c:153
#define ERROR
Definition: elog.h:43
char * endptr
Definition: aset.c:154
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:100
#define WARNING
Definition: elog.h:40
struct AllocBlockData * AllocBlock
Definition: aset.c:102
struct AllocChunkData * AllocChunk
Definition: aset.c:103
static void AllocSetFree(MemoryContext context, void *pointer)
Definition: aset.c:839
size_t Size
Definition: c.h:404
#define MAXALIGN(LEN)
Definition: c.h:623
#define realloc(a, b)
Definition: header.h:60
static void * AllocSetAlloc(MemoryContext context, Size size)
Definition: aset.c:562
AllocSetContext * AllocSet
Definition: aset.c:134
#define elog
Definition: elog.h:219
Size size
Definition: aset.c:164
#define AllocPointerGetChunk(ptr)
Definition: aset.c:193

◆ AllocSetReset()

static void AllocSetReset ( MemoryContext  context)
static

Definition at line 460 of file aset.c.

References ALLOC_BLOCKHDRSZ, AllocSetIsValid, AssertArg, free, AllocBlockData::freeptr, MemSetAligned, AllocBlockData::next, next, AllocBlockData::prev, and VALGRIND_MAKE_MEM_NOACCESS.

461 {
462  AllocSet set = (AllocSet) context;
463  AllocBlock block;
464 
466 
467 #ifdef MEMORY_CONTEXT_CHECKING
468  /* Check for corruption and leaks before freeing */
469  AllocSetCheck(context);
470 #endif
471 
472  /* Clear chunk freelists */
473  MemSetAligned(set->freelist, 0, sizeof(set->freelist));
474 
475  block = set->blocks;
476 
477  /* New blocks list is either empty or just the keeper block */
478  set->blocks = set->keeper;
479 
480  while (block != NULL)
481  {
482  AllocBlock next = block->next;
483 
484  if (block == set->keeper)
485  {
486  /* Reset the block, but don't return it to malloc */
487  char *datastart = ((char *) block) + ALLOC_BLOCKHDRSZ;
488 
489 #ifdef CLOBBER_FREED_MEMORY
490  wipe_mem(datastart, block->freeptr - datastart);
491 #else
492  /* wipe_mem() would have done this */
493  VALGRIND_MAKE_MEM_NOACCESS(datastart, block->freeptr - datastart);
494 #endif
495  block->freeptr = datastart;
496  block->prev = NULL;
497  block->next = NULL;
498  }
499  else
500  {
501  /* Normal case, release the block */
502 #ifdef CLOBBER_FREED_MEMORY
503  wipe_mem(block, block->freeptr - ((char *) block));
504 #endif
505  free(block);
506  }
507  block = next;
508  }
509 
510  /* Reset block size allocation sequence, too */
511  set->nextBlockSize = set->initBlockSize;
512 }
#define MemSetAligned(start, val, len)
Definition: c.h:886
static int32 next
Definition: blutils.c:210
#define AllocSetIsValid(set)
Definition: aset.c:191
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition: memdebug.h:27
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:99
char * freeptr
Definition: aset.c:153
AllocBlock next
Definition: aset.c:152
#define AssertArg(condition)
Definition: c.h:672
AllocBlock prev
Definition: aset.c:151
#define free(a)
Definition: header.h:65
AllocSetContext * AllocSet
Definition: aset.c:134

◆ AllocSetStats()

static void AllocSetStats ( MemoryContext  context,
int  level,
bool  print,
MemoryContextCounters totals 
)
static

Definition at line 1148 of file aset.c.

References ALLOC_BLOCKHDRSZ, ALLOC_CHUNKHDRSZ, ALLOC_MINBITS, ALLOCSET_NUM_FREELISTS, AllocBlockData::aset, AllocChunkData::aset, elog, AllocBlockData::endptr, MemoryContextCounters::freechunks, AllocBlockData::freeptr, MemoryContextCounters::freespace, i, name, MemoryContextCounters::nblocks, AllocBlockData::next, AllocBlockData::prev, AllocChunkData::size, MemoryContextCounters::totalspace, VALGRIND_MAKE_MEM_DEFINED, VALGRIND_MAKE_MEM_NOACCESS, and WARNING.

1150 {
1151  AllocSet set = (AllocSet) context;
1152  Size nblocks = 0;
1153  Size freechunks = 0;
1154  Size totalspace = 0;
1155  Size freespace = 0;
1156  AllocBlock block;
1157  int fidx;
1158 
1159  for (block = set->blocks; block != NULL; block = block->next)
1160  {
1161  nblocks++;
1162  totalspace += block->endptr - ((char *) block);
1163  freespace += block->endptr - block->freeptr;
1164  }
1165  for (fidx = 0; fidx < ALLOCSET_NUM_FREELISTS; fidx++)
1166  {
1167  AllocChunk chunk;
1168 
1169  for (chunk = set->freelist[fidx]; chunk != NULL;
1170  chunk = (AllocChunk) chunk->aset)
1171  {
1172  freechunks++;
1173  freespace += chunk->size + ALLOC_CHUNKHDRSZ;
1174  }
1175  }
1176 
1177  if (print)
1178  {
1179  int i;
1180 
1181  for (i = 0; i < level; i++)
1182  fprintf(stderr, " ");
1183  fprintf(stderr,
1184  "%s: %zu total in %zd blocks; %zu free (%zd chunks); %zu used\n",
1185  set->header.name, totalspace, nblocks, freespace, freechunks,
1186  totalspace - freespace);
1187  }
1188 
1189  if (totals)
1190  {
1191  totals->nblocks += nblocks;
1192  totals->freechunks += freechunks;
1193  totals->totalspace += totalspace;
1194  totals->freespace += freespace;
1195  }
1196 }
void print(const void *obj)
Definition: print.c:35
char * freeptr
Definition: aset.c:153
char * endptr
Definition: aset.c:154
#define ALLOCSET_NUM_FREELISTS
Definition: aset.c:82
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:100
AllocBlock next
Definition: aset.c:152
size_t Size
Definition: c.h:404
void * aset
Definition: aset.c:176
int i
AllocSetContext * AllocSet
Definition: aset.c:134
Size size
Definition: aset.c:164

Variable Documentation

◆ AllocSetMethods

MemoryContextMethods AllocSetMethods
static
Initial value:
= {
}
static void AllocSetInit(MemoryContext context)
Definition: aset.c:440
static Size AllocSetGetChunkSpace(MemoryContext context, void *pointer)
Definition: aset.c:1114
static void AllocSetReset(MemoryContext context)
Definition: aset.c:460
static void * AllocSetRealloc(MemoryContext context, void *pointer, Size size)
Definition: aset.c:919
static bool AllocSetIsEmpty(MemoryContext context)
Definition: aset.c:1126
static void AllocSetFree(MemoryContext context, void *pointer)
Definition: aset.c:839
static void AllocSetStats(MemoryContext context, int level, bool print, MemoryContextCounters *totals)
Definition: aset.c:1148
static void AllocSetDelete(MemoryContext context)
Definition: aset.c:523
static void * AllocSetAlloc(MemoryContext context, Size size)
Definition: aset.c:562

Definition at line 219 of file aset.c.

Referenced by AllocSetContextCreate().

◆ LogTable256

const unsigned char LogTable256[256]
static
Initial value:
=
{
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
LT16(5), LT16(6), LT16(6), LT16(7), LT16(7), LT16(7), LT16(7),
LT16(8), LT16(8), LT16(8), LT16(8), LT16(8), LT16(8), LT16(8), LT16(8)
}
#define LT16(n)
Definition: aset.c:237

Definition at line 239 of file aset.c.

Referenced by AllocSetFreeIndex().