PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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   MAXALIGN(sizeof(AllocChunkData))
 
#define ALLOC_CHUNK_PUBLIC   (offsetof(AllocChunkData, size) + sizeof(Size))
 
#define ALLOC_CHUNK_USED   (offsetof(AllocChunkData, size) + sizeof(Size))
 
#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

#define ALLOC_BLOCKHDRSZ   MAXALIGN(sizeof(AllocBlockData))
#define ALLOC_CHUNK_FRACTION   4

Definition at line 125 of file aset.c.

Referenced by AllocSetContextCreate().

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

Definition at line 123 of file aset.c.

Referenced by AllocSetContextCreate().

#define ALLOC_CHUNK_PUBLIC   (offsetof(AllocChunkData, size) + sizeof(Size))

Definition at line 143 of file aset.c.

Referenced by AllocSetAlloc().

#define ALLOC_CHUNK_USED   (offsetof(AllocChunkData, size) + sizeof(Size))

Definition at line 151 of file aset.c.

Referenced by AllocSetAlloc().

#define ALLOC_CHUNKHDRSZ   MAXALIGN(sizeof(AllocChunkData))
#define ALLOC_MINBITS   3 /* smallest chunk size is 8 bytes */

Definition at line 121 of file aset.c.

Referenced by AllocSetAlloc(), and AllocSetFreeIndex().

#define AllocAllocInfo (   _cxt,
  _chunk 
)

Definition at line 306 of file aset.c.

Referenced by AllocSetAlloc().

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

Definition at line 242 of file aset.c.

Referenced by AllocSetAlloc(), and AllocSetRealloc().

#define AllocFreeInfo (   _cxt,
  _chunk 
)

Definition at line 305 of file aset.c.

Referenced by AllocSetFree().

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

Definition at line 240 of file aset.c.

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

#define AllocPointerIsValid (   pointer)    PointerIsValid(pointer)

Definition at line 232 of file aset.c.

#define ALLOCSET_NUM_FREELISTS   11

Definition at line 122 of file aset.c.

Referenced by AllocSetFreeIndex(), and AllocSetStats().

#define AllocSetIsValid (   set)    PointerIsValid(set)

Definition at line 238 of file aset.c.

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

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

Definition at line 284 of file aset.c.

Typedef Documentation

Definition at line 155 of file aset.c.

Definition at line 156 of file aset.c.

Definition at line 162 of file aset.c.

Definition at line 187 of file aset.c.

Function Documentation

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

Definition at line 672 of file aset.c.

References ALLOC_BLOCKHDRSZ, ALLOC_CHUNK_PUBLIC, ALLOC_CHUNK_USED, ALLOC_CHUNKHDRSZ, ALLOC_MINBITS, AllocAllocInfo, AllocChunkGetPointer, AllocSetContext::allocChunkLimit, AllocSetFreeIndex(), AllocSetIsValid, AllocBlockData::aset, AllocChunkData::aset, Assert, AssertArg, AllocSetContext::blocks, AllocBlockData::endptr, AllocSetContext::freelist, AllocBlockData::freeptr, AllocSetContext::initBlockSize, AllocSetContext::keeper, malloc, MAXALIGN, AllocSetContext::maxBlockSize, AllocBlockData::next, AllocSetContext::nextBlockSize, NULL, AllocChunkData::size, VALGRIND_MAKE_MEM_NOACCESS, and VALGRIND_MAKE_MEM_UNDEFINED.

Referenced by AllocSetRealloc().

673 {
674  AllocSet set = (AllocSet) context;
675  AllocBlock block;
676  AllocChunk chunk;
677  int fidx;
678  Size chunk_size;
679  Size blksize;
680 
682 
683  /*
684  * If requested size exceeds maximum for chunks, allocate an entire block
685  * for this request.
686  */
687  if (size > set->allocChunkLimit)
688  {
689  chunk_size = MAXALIGN(size);
690  blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
691  block = (AllocBlock) malloc(blksize);
692  if (block == NULL)
693  return NULL;
694  block->aset = set;
695  block->freeptr = block->endptr = ((char *) block) + blksize;
696 
697  chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
698  chunk->aset = set;
699  chunk->size = chunk_size;
700 #ifdef MEMORY_CONTEXT_CHECKING
701  /* Valgrind: Will be made NOACCESS below. */
702  chunk->requested_size = size;
703  /* set mark to catch clobber of "unused" space */
704  if (size < chunk_size)
705  set_sentinel(AllocChunkGetPointer(chunk), size);
706 #endif
707 #ifdef RANDOMIZE_ALLOCATED_MEMORY
708  /* fill the allocated space with junk */
709  randomize_mem((char *) AllocChunkGetPointer(chunk), size);
710 #endif
711 
712  /*
713  * Stick the new block underneath the active allocation block, so that
714  * we don't lose the use of the space remaining therein.
715  */
716  if (set->blocks != NULL)
717  {
718  block->next = set->blocks->next;
719  set->blocks->next = block;
720  }
721  else
722  {
723  block->next = NULL;
724  set->blocks = block;
725  }
726 
727  AllocAllocInfo(set, chunk);
728 
729  /*
730  * Chunk header public fields remain DEFINED. The requested
731  * allocation itself can be NOACCESS or UNDEFINED; our caller will
732  * soon make it UNDEFINED. Make extra space at the end of the chunk,
733  * if any, NOACCESS.
734  */
736  chunk_size + ALLOC_CHUNKHDRSZ - ALLOC_CHUNK_PUBLIC);
737 
738  return AllocChunkGetPointer(chunk);
739  }
740 
741  /*
742  * Request is small enough to be treated as a chunk. Look in the
743  * corresponding free list to see if there is a free chunk we could reuse.
744  * If one is found, remove it from the free list, make it again a member
745  * of the alloc set and return its data address.
746  */
747  fidx = AllocSetFreeIndex(size);
748  chunk = set->freelist[fidx];
749  if (chunk != NULL)
750  {
751  Assert(chunk->size >= size);
752 
753  set->freelist[fidx] = (AllocChunk) chunk->aset;
754 
755  chunk->aset = (void *) set;
756 
757 #ifdef MEMORY_CONTEXT_CHECKING
758  /* Valgrind: Free list requested_size should be DEFINED. */
759  chunk->requested_size = size;
760  VALGRIND_MAKE_MEM_NOACCESS(&chunk->requested_size,
761  sizeof(chunk->requested_size));
762  /* set mark to catch clobber of "unused" space */
763  if (size < chunk->size)
764  set_sentinel(AllocChunkGetPointer(chunk), size);
765 #endif
766 #ifdef RANDOMIZE_ALLOCATED_MEMORY
767  /* fill the allocated space with junk */
768  randomize_mem((char *) AllocChunkGetPointer(chunk), size);
769 #endif
770 
771  AllocAllocInfo(set, chunk);
772  return AllocChunkGetPointer(chunk);
773  }
774 
775  /*
776  * Choose the actual chunk size to allocate.
777  */
778  chunk_size = (1 << ALLOC_MINBITS) << fidx;
779  Assert(chunk_size >= size);
780 
781  /*
782  * If there is enough room in the active allocation block, we will put the
783  * chunk into that block. Else must start a new one.
784  */
785  if ((block = set->blocks) != NULL)
786  {
787  Size availspace = block->endptr - block->freeptr;
788 
789  if (availspace < (chunk_size + ALLOC_CHUNKHDRSZ))
790  {
791  /*
792  * The existing active (top) block does not have enough room for
793  * the requested allocation, but it might still have a useful
794  * amount of space in it. Once we push it down in the block list,
795  * we'll never try to allocate more space from it. So, before we
796  * do that, carve up its free space into chunks that we can put on
797  * the set's freelists.
798  *
799  * Because we can only get here when there's less than
800  * ALLOC_CHUNK_LIMIT left in the block, this loop cannot iterate
801  * more than ALLOCSET_NUM_FREELISTS-1 times.
802  */
803  while (availspace >= ((1 << ALLOC_MINBITS) + ALLOC_CHUNKHDRSZ))
804  {
805  Size availchunk = availspace - ALLOC_CHUNKHDRSZ;
806  int a_fidx = AllocSetFreeIndex(availchunk);
807 
808  /*
809  * In most cases, we'll get back the index of the next larger
810  * freelist than the one we need to put this chunk on. The
811  * exception is when availchunk is exactly a power of 2.
812  */
813  if (availchunk != ((Size) 1 << (a_fidx + ALLOC_MINBITS)))
814  {
815  a_fidx--;
816  Assert(a_fidx >= 0);
817  availchunk = ((Size) 1 << (a_fidx + ALLOC_MINBITS));
818  }
819 
820  chunk = (AllocChunk) (block->freeptr);
821 
822  /* Prepare to initialize the chunk header. */
824 
825  block->freeptr += (availchunk + ALLOC_CHUNKHDRSZ);
826  availspace -= (availchunk + ALLOC_CHUNKHDRSZ);
827 
828  chunk->size = availchunk;
829 #ifdef MEMORY_CONTEXT_CHECKING
830  chunk->requested_size = 0; /* mark it free */
831 #endif
832  chunk->aset = (void *) set->freelist[a_fidx];
833  set->freelist[a_fidx] = chunk;
834  }
835 
836  /* Mark that we need to create a new block */
837  block = NULL;
838  }
839  }
840 
841  /*
842  * Time to create a new regular (multi-chunk) block?
843  */
844  if (block == NULL)
845  {
846  Size required_size;
847 
848  /*
849  * The first such block has size initBlockSize, and we double the
850  * space in each succeeding block, but not more than maxBlockSize.
851  */
852  blksize = set->nextBlockSize;
853  set->nextBlockSize <<= 1;
854  if (set->nextBlockSize > set->maxBlockSize)
855  set->nextBlockSize = set->maxBlockSize;
856 
857  /*
858  * If initBlockSize is less than ALLOC_CHUNK_LIMIT, we could need more
859  * space... but try to keep it a power of 2.
860  */
861  required_size = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
862  while (blksize < required_size)
863  blksize <<= 1;
864 
865  /* Try to allocate it */
866  block = (AllocBlock) malloc(blksize);
867 
868  /*
869  * We could be asking for pretty big blocks here, so cope if malloc
870  * fails. But give up if there's less than a meg or so available...
871  */
872  while (block == NULL && blksize > 1024 * 1024)
873  {
874  blksize >>= 1;
875  if (blksize < required_size)
876  break;
877  block = (AllocBlock) malloc(blksize);
878  }
879 
880  if (block == NULL)
881  return NULL;
882 
883  block->aset = set;
884  block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
885  block->endptr = ((char *) block) + blksize;
886 
887  /*
888  * If this is the first block of the set, make it the "keeper" block.
889  * Formerly, a keeper block could only be created during context
890  * creation, but allowing it to happen here lets us have fast reset
891  * cycling even for contexts created with minContextSize = 0; that way
892  * we don't have to force space to be allocated in contexts that might
893  * never need any space. Don't mark an oversize block as a keeper,
894  * however.
895  */
896  if (set->keeper == NULL && blksize == set->initBlockSize)
897  set->keeper = block;
898 
899  /* Mark unallocated space NOACCESS. */
901  blksize - ALLOC_BLOCKHDRSZ);
902 
903  block->next = set->blocks;
904  set->blocks = block;
905  }
906 
907  /*
908  * OK, do the allocation
909  */
910  chunk = (AllocChunk) (block->freeptr);
911 
912  /* Prepare to initialize the chunk header. */
914 
915  block->freeptr += (chunk_size + ALLOC_CHUNKHDRSZ);
916  Assert(block->freeptr <= block->endptr);
917 
918  chunk->aset = (void *) set;
919  chunk->size = chunk_size;
920 #ifdef MEMORY_CONTEXT_CHECKING
921  chunk->requested_size = size;
922  VALGRIND_MAKE_MEM_NOACCESS(&chunk->requested_size,
923  sizeof(chunk->requested_size));
924  /* set mark to catch clobber of "unused" space */
925  if (size < chunk->size)
926  set_sentinel(AllocChunkGetPointer(chunk), size);
927 #endif
928 #ifdef RANDOMIZE_ALLOCATED_MEMORY
929  /* fill the allocated space with junk */
930  randomize_mem((char *) AllocChunkGetPointer(chunk), size);
931 #endif
932 
933  AllocAllocInfo(set, chunk);
934  return AllocChunkGetPointer(chunk);
935 }
Size initBlockSize
Definition: aset.c:180
AllocBlock blocks
Definition: aset.c:177
#define ALLOC_CHUNK_PUBLIC
Definition: aset.c:143
#define AllocSetIsValid(set)
Definition: aset.c:238
#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:318
#define AllocChunkGetPointer(chk)
Definition: aset.c:242
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:139
AllocBlock keeper
Definition: aset.c:184
AllocSet aset
Definition: aset.c:203
char * freeptr
Definition: aset.c:205
#define ALLOC_CHUNK_USED
Definition: aset.c:151
#define malloc(a)
Definition: header.h:45
char * endptr
Definition: aset.c:206
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:140
AllocBlock next
Definition: aset.c:204
#define AssertArg(condition)
Definition: c.h:673
struct AllocBlockData * AllocBlock
Definition: aset.c:155
AllocChunk freelist[ALLOCSET_NUM_FREELISTS]
Definition: aset.c:178
Size nextBlockSize
Definition: aset.c:182
Size allocChunkLimit
Definition: aset.c:183
struct AllocChunkData * AllocChunk
Definition: aset.c:156
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
size_t Size
Definition: c.h:353
#define MAXALIGN(LEN)
Definition: c.h:584
void * aset
Definition: aset.c:218
AllocSetContext * AllocSet
Definition: aset.c:187
#define ALLOC_MINBITS
Definition: aset.c:121
Size maxBlockSize
Definition: aset.c:181
#define AllocAllocInfo(_cxt, _chunk)
Definition: aset.c:306
Size size
Definition: aset.c:220
MemoryContext AllocSetContextCreate ( MemoryContext  parent,
const char *  name,
Size  minContextSize,
Size  initBlockSize,
Size  maxBlockSize 
)

Definition at line 440 of file aset.c.

References ALLOC_BLOCKHDRSZ, ALLOC_CHUNK_FRACTION, ALLOC_CHUNK_LIMIT, ALLOC_CHUNKHDRSZ, AllocSetContext::allocChunkLimit, AllocHugeSizeIsValid, ALLOCSET_SEPARATE_THRESHOLD, AllocSetMethods, AllocBlockData::aset, AllocSetContext::blocks, elog, AllocBlockData::endptr, ereport, errcode(), errdetail(), errmsg(), ERROR, AllocBlockData::freeptr, AllocSetContext::initBlockSize, AllocSetContext::keeper, malloc, MAXALIGN, AllocSetContext::maxBlockSize, MemoryContextCreate(), MemoryContextStats(), name, AllocBlockData::next, AllocSetContext::nextBlockSize, NULL, 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(), ApplyLoop(), ApplyWorkerMain(), AtStart_Memory(), AtSubStart_Memory(), AutoVacLauncherMain(), BackgroundWriterMain(), begin_heap_rewrite(), BeginCopy(), blbuild(), blinsert(), brin_build_desc(), brin_new_memtuple(), bringetbitmap(), brininsert(), btvacuumscan(), BuildCachedPlan(), BuildEventTriggerCache(), CheckpointerMain(), cluster(), compile_plperl_function(), compile_pltcl_function(), CompleteCachedPlan(), compute_index_stats(), CopyCachedPlan(), CopyTo(), CreateCachedPlan(), CreateCacheMemoryContext(), CreateExecutorState(), CreateExprContext(), CreatePortal(), CreateStandaloneExprContext(), createTempGistContext(), createTrgmNFA(), 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(), ExecInitRecursiveUnion(), ExecInitSetOp(), ExecInitSubPlan(), ExecInitUnique(), ExecInitWindowAgg(), expand_array(), file_acquire_sample_rows(), fill_hba_view(), geqo_eval(), get_stmt_mcontext(), GetLocalBufferStorage(), 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(), load_domaintype_info(), load_hba(), load_ident(), load_relcache_init_file(), load_tzoffsets(), logicalrep_relmap_init(), lookup_ts_dictionary_cache(), materializeQueryResult(), mdinit(), MemoryContextInit(), mXactCachePut(), NIStartBuild(), ParallelWorkerMain(), PerformAuthentication(), pg_decode_startup(), pgoutput_startup(), pgstat_setup_memcxt(), plperl_return_next(), 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(), PLyObject_ToComposite(), PLyString_ToComposite(), 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(), tqueueReceiveSlot(), tuplesort_begin_common(), union_tuples(), vacuum(), WalWriterMain(), and XLOGShmemInit().

445 {
446  AllocSet set;
447 
448  /*
449  * First, validate allocation parameters. (If we're going to throw an
450  * error, we should do so before the context is created, not after.) We
451  * somewhat arbitrarily enforce a minimum 1K block size.
452  */
453  if (initBlockSize != MAXALIGN(initBlockSize) ||
454  initBlockSize < 1024)
455  elog(ERROR, "invalid initBlockSize for memory context: %zu",
456  initBlockSize);
457  if (maxBlockSize != MAXALIGN(maxBlockSize) ||
458  maxBlockSize < initBlockSize ||
459  !AllocHugeSizeIsValid(maxBlockSize)) /* must be safe to double */
460  elog(ERROR, "invalid maxBlockSize for memory context: %zu",
461  maxBlockSize);
462  if (minContextSize != 0 &&
463  (minContextSize != MAXALIGN(minContextSize) ||
464  minContextSize <= ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
465  elog(ERROR, "invalid minContextSize for memory context: %zu",
466  minContextSize);
467 
468  /* Do the type-independent part of context creation */
470  sizeof(AllocSetContext),
472  parent,
473  name);
474 
475  /* Save allocation parameters */
476  set->initBlockSize = initBlockSize;
477  set->maxBlockSize = maxBlockSize;
478  set->nextBlockSize = initBlockSize;
479 
480  /*
481  * Compute the allocation chunk size limit for this context. It can't be
482  * more than ALLOC_CHUNK_LIMIT because of the fixed number of freelists.
483  * If maxBlockSize is small then requests exceeding the maxBlockSize, or
484  * even a significant fraction of it, should be treated as large chunks
485  * too. For the typical case of maxBlockSize a power of 2, the chunk size
486  * limit will be at most 1/8th maxBlockSize, so that given a stream of
487  * requests that are all the maximum chunk size we will waste at most
488  * 1/8th of the allocated space.
489  *
490  * We have to have allocChunkLimit a power of two, because the requested
491  * and actually-allocated sizes of any chunk must be on the same side of
492  * the limit, else we get confused about whether the chunk is "big".
493  *
494  * Also, allocChunkLimit must not exceed ALLOCSET_SEPARATE_THRESHOLD.
495  */
497  "ALLOC_CHUNK_LIMIT != ALLOCSET_SEPARATE_THRESHOLD");
498 
500  while ((Size) (set->allocChunkLimit + ALLOC_CHUNKHDRSZ) >
501  (Size) ((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION))
502  set->allocChunkLimit >>= 1;
503 
504  /*
505  * Grab always-allocated space, if requested
506  */
507  if (minContextSize > 0)
508  {
509  Size blksize = minContextSize;
510  AllocBlock block;
511 
512  block = (AllocBlock) malloc(blksize);
513  if (block == NULL)
514  {
516  ereport(ERROR,
517  (errcode(ERRCODE_OUT_OF_MEMORY),
518  errmsg("out of memory"),
519  errdetail("Failed while creating memory context \"%s\".",
520  name)));
521  }
522  block->aset = set;
523  block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
524  block->endptr = ((char *) block) + blksize;
525  block->next = set->blocks;
526  set->blocks = block;
527  /* Mark block as not to be released at reset time */
528  set->keeper = block;
529 
530  /* Mark unallocated space NOACCESS; leave the block header alone. */
532  blksize - ALLOC_BLOCKHDRSZ);
533  }
534 
535  return (MemoryContext) set;
536 }
Size initBlockSize
Definition: aset.c:180
AllocBlock blocks
Definition: aset.c:177
#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:139
AllocBlock keeper
Definition: aset.c:184
AllocSet aset
Definition: aset.c:203
char * freeptr
Definition: aset.c:205
#define malloc(a)
Definition: header.h:45
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:753
#define ERROR
Definition: elog.h:43
#define ALLOC_CHUNK_LIMIT
Definition: aset.c:123
void MemoryContextStats(MemoryContext context)
Definition: mcxt.c:483
char * endptr
Definition: aset.c:206
#define ALLOCSET_SEPARATE_THRESHOLD
Definition: memutils.h:172
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:682
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:140
static MemoryContextMethods AllocSetMethods
Definition: aset.c:266
AllocBlock next
Definition: aset.c:204
#define ereport(elevel, rest)
Definition: elog.h:122
MemoryContext TopMemoryContext
Definition: mcxt.c:43
#define ALLOC_CHUNK_FRACTION
Definition: aset.c:125
struct AllocBlockData * AllocBlock
Definition: aset.c:155
Size nextBlockSize
Definition: aset.c:182
Size allocChunkLimit
Definition: aset.c:183
#define NULL
Definition: c.h:226
size_t Size
Definition: c.h:353
#define MAXALIGN(LEN)
Definition: c.h:584
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:187
#define elog
Definition: elog.h:219
Size maxBlockSize
Definition: aset.c:181
static void AllocSetDelete ( MemoryContext  context)
static

Definition at line 633 of file aset.c.

References AllocSetIsValid, AssertArg, AllocSetContext::blocks, free, AllocSetContext::freelist, AllocBlockData::freeptr, AllocSetContext::keeper, MemSetAligned, AllocBlockData::next, next, and NULL.

634 {
635  AllocSet set = (AllocSet) context;
636  AllocBlock block = set->blocks;
637 
639 
640 #ifdef MEMORY_CONTEXT_CHECKING
641  /* Check for corruption and leaks before freeing */
642  AllocSetCheck(context);
643 #endif
644 
645  /* Make it look empty, just in case... */
646  MemSetAligned(set->freelist, 0, sizeof(set->freelist));
647  set->blocks = NULL;
648  set->keeper = NULL;
649 
650  while (block != NULL)
651  {
652  AllocBlock next = block->next;
653 
654 #ifdef CLOBBER_FREED_MEMORY
655  wipe_mem(block, block->freeptr - ((char *) block));
656 #endif
657  free(block);
658  block = next;
659  }
660 }
#define MemSetAligned(start, val, len)
Definition: c.h:886
AllocBlock blocks
Definition: aset.c:177
static int32 next
Definition: blutils.c:210
#define AllocSetIsValid(set)
Definition: aset.c:238
AllocBlock keeper
Definition: aset.c:184
char * freeptr
Definition: aset.c:205
AllocBlock next
Definition: aset.c:204
#define AssertArg(condition)
Definition: c.h:673
AllocChunk freelist[ALLOCSET_NUM_FREELISTS]
Definition: aset.c:178
#define free(a)
Definition: header.h:60
#define NULL
Definition: c.h:226
AllocSetContext * AllocSet
Definition: aset.c:187
static void AllocSetFree ( MemoryContext  context,
void *  pointer 
)
static

Definition at line 942 of file aset.c.

References ALLOC_BLOCKHDRSZ, ALLOC_CHUNKHDRSZ, AllocSetContext::allocChunkLimit, AllocFreeInfo, AllocPointerGetChunk, AllocSetFreeIndex(), AllocChunkData::aset, Assert, AllocSetContext::blocks, elog, ERROR, free, AllocSetContext::freelist, AllocBlockData::freeptr, AllocSetContext::header, MemoryContextData::name, AllocBlockData::next, NULL, AllocChunkData::size, VALGRIND_MAKE_MEM_DEFINED, and WARNING.

Referenced by AllocSetRealloc().

943 {
944  AllocSet set = (AllocSet) context;
945  AllocChunk chunk = AllocPointerGetChunk(pointer);
946 
947  AllocFreeInfo(set, chunk);
948 
949 #ifdef MEMORY_CONTEXT_CHECKING
950  VALGRIND_MAKE_MEM_DEFINED(&chunk->requested_size,
951  sizeof(chunk->requested_size));
952  /* Test for someone scribbling on unused space in chunk */
953  if (chunk->requested_size < chunk->size)
954  if (!sentinel_ok(pointer, chunk->requested_size))
955  elog(WARNING, "detected write past chunk end in %s %p",
956  set->header.name, chunk);
957 #endif
958 
959  if (chunk->size > set->allocChunkLimit)
960  {
961  /*
962  * Big chunks are certain to have been allocated as single-chunk
963  * blocks. Find the containing block and return it to malloc().
964  */
965  AllocBlock block = set->blocks;
966  AllocBlock prevblock = NULL;
967 
968  while (block != NULL)
969  {
970  if (chunk == (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ))
971  break;
972  prevblock = block;
973  block = block->next;
974  }
975  if (block == NULL)
976  elog(ERROR, "could not find block containing chunk %p", chunk);
977  /* let's just make sure chunk is the only one in the block */
978  Assert(block->freeptr == ((char *) block) +
979  (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ));
980 
981  /* OK, remove block from aset's list and free it */
982  if (prevblock == NULL)
983  set->blocks = block->next;
984  else
985  prevblock->next = block->next;
986 #ifdef CLOBBER_FREED_MEMORY
987  wipe_mem(block, block->freeptr - ((char *) block));
988 #endif
989  free(block);
990  }
991  else
992  {
993  /* Normal case, put the chunk into appropriate freelist */
994  int fidx = AllocSetFreeIndex(chunk->size);
995 
996  chunk->aset = (void *) set->freelist[fidx];
997 
998 #ifdef CLOBBER_FREED_MEMORY
999  wipe_mem(pointer, chunk->size);
1000 #endif
1001 
1002 #ifdef MEMORY_CONTEXT_CHECKING
1003  /* Reset requested_size to 0 in chunks that are on freelist */
1004  chunk->requested_size = 0;
1005 #endif
1006  set->freelist[fidx] = chunk;
1007  }
1008 }
#define AllocFreeInfo(_cxt, _chunk)
Definition: aset.c:305
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
AllocBlock blocks
Definition: aset.c:177
MemoryContextData header
Definition: aset.c:175
static int AllocSetFreeIndex(Size size)
Definition: aset.c:318
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:139
char * freeptr
Definition: aset.c:205
#define ERROR
Definition: elog.h:43
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:140
AllocBlock next
Definition: aset.c:204
#define WARNING
Definition: elog.h:40
AllocChunk freelist[ALLOCSET_NUM_FREELISTS]
Definition: aset.c:178
#define free(a)
Definition: header.h:60
Size allocChunkLimit
Definition: aset.c:183
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
void * aset
Definition: aset.c:218
AllocSetContext * AllocSet
Definition: aset.c:187
#define elog
Definition: elog.h:219
Size size
Definition: aset.c:220
#define AllocPointerGetChunk(ptr)
Definition: aset.c:240
static int AllocSetFreeIndex ( Size  size)
inlinestatic

Definition at line 318 of file aset.c.

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

Referenced by AllocSetAlloc(), and AllocSetFree().

319 {
320  int idx;
321  unsigned int t,
322  tsize;
323 
324  if (size > (1 << ALLOC_MINBITS))
325  {
326  tsize = (size - 1) >> ALLOC_MINBITS;
327 
328  /*
329  * At this point we need to obtain log2(tsize)+1, ie, the number of
330  * not-all-zero bits at the right. We used to do this with a
331  * shift-and-count loop, but this function is enough of a hotspot to
332  * justify micro-optimization effort. The best approach seems to be
333  * to use a lookup table. Note that this code assumes that
334  * ALLOCSET_NUM_FREELISTS <= 17, since we only cope with two bytes of
335  * the tsize value.
336  */
337  t = tsize >> 8;
338  idx = t ? LogTable256[t] + 8 : LogTable256[tsize];
339 
341  }
342  else
343  idx = 0;
344 
345  return idx;
346 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:264
#define ALLOCSET_NUM_FREELISTS
Definition: aset.c:122
static const unsigned char LogTable256[256]
Definition: aset.c:286
#define Assert(condition)
Definition: c.h:671
#define ALLOC_MINBITS
Definition: aset.c:121
static Size AllocSetGetChunkSpace ( MemoryContext  context,
void *  pointer 
)
static

Definition at line 1218 of file aset.c.

References ALLOC_CHUNKHDRSZ, AllocPointerGetChunk, and AllocChunkData::size.

1219 {
1220  AllocChunk chunk = AllocPointerGetChunk(pointer);
1221 
1222  return chunk->size + ALLOC_CHUNKHDRSZ;
1223 }
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:140
Size size
Definition: aset.c:220
#define AllocPointerGetChunk(ptr)
Definition: aset.c:240
static void AllocSetInit ( MemoryContext  context)
static

Definition at line 551 of file aset.c.

552 {
553  /*
554  * Since MemoryContextCreate already zeroed the context node, we don't
555  * have to do anything here: it's already OK.
556  */
557 }
static bool AllocSetIsEmpty ( MemoryContext  context)
static

Definition at line 1230 of file aset.c.

References MemoryContextData::isReset.

1231 {
1232  /*
1233  * For now, we say "empty" only if the context is new or just reset. We
1234  * could examine the freelists to determine if all space has been freed,
1235  * but it's not really worth the trouble for present uses of this
1236  * functionality.
1237  */
1238  if (context->isReset)
1239  return true;
1240  return false;
1241 }
static void * AllocSetRealloc ( MemoryContext  context,
void *  pointer,
Size  size 
)
static

Definition at line 1023 of file aset.c.

References ALLOC_BLOCKHDRSZ, ALLOC_CHUNKHDRSZ, AllocChunkGetPointer, AllocSetContext::allocChunkLimit, AllocPointerGetChunk, AllocSetAlloc(), AllocSetFree(), Assert, AllocSetContext::blocks, elog, AllocBlockData::endptr, ERROR, AllocBlockData::freeptr, AllocSetContext::header, MAXALIGN, MemoryContextData::name, AllocBlockData::next, NULL, realloc, AllocChunkData::size, VALGRIND_MAKE_MEM_DEFINED, VALGRIND_MAKE_MEM_NOACCESS, VALGRIND_MAKE_MEM_UNDEFINED, and WARNING.

1024 {
1025  AllocSet set = (AllocSet) context;
1026  AllocChunk chunk = AllocPointerGetChunk(pointer);
1027  Size oldsize = chunk->size;
1028 
1029 #ifdef MEMORY_CONTEXT_CHECKING
1030  VALGRIND_MAKE_MEM_DEFINED(&chunk->requested_size,
1031  sizeof(chunk->requested_size));
1032  /* Test for someone scribbling on unused space in chunk */
1033  if (chunk->requested_size < oldsize)
1034  if (!sentinel_ok(pointer, chunk->requested_size))
1035  elog(WARNING, "detected write past chunk end in %s %p",
1036  set->header.name, chunk);
1037 #endif
1038 
1039  /*
1040  * Chunk sizes are aligned to power of 2 in AllocSetAlloc(). Maybe the
1041  * allocated area already is >= the new size. (In particular, we always
1042  * fall out here if the requested size is a decrease.)
1043  */
1044  if (oldsize >= size)
1045  {
1046 #ifdef MEMORY_CONTEXT_CHECKING
1047  Size oldrequest = chunk->requested_size;
1048 
1049 #ifdef RANDOMIZE_ALLOCATED_MEMORY
1050  /* We can only fill the extra space if we know the prior request */
1051  if (size > oldrequest)
1052  randomize_mem((char *) pointer + oldrequest,
1053  size - oldrequest);
1054 #endif
1055 
1056  chunk->requested_size = size;
1057  VALGRIND_MAKE_MEM_NOACCESS(&chunk->requested_size,
1058  sizeof(chunk->requested_size));
1059 
1060  /*
1061  * If this is an increase, mark any newly-available part UNDEFINED.
1062  * Otherwise, mark the obsolete part NOACCESS.
1063  */
1064  if (size > oldrequest)
1065  VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + oldrequest,
1066  size - oldrequest);
1067  else
1068  VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size,
1069  oldsize - size);
1070 
1071  /* set mark to catch clobber of "unused" space */
1072  if (size < oldsize)
1073  set_sentinel(pointer, size);
1074 #else /* !MEMORY_CONTEXT_CHECKING */
1075 
1076  /*
1077  * We don't have the information to determine whether we're growing
1078  * the old request or shrinking it, so we conservatively mark the
1079  * entire new allocation DEFINED.
1080  */
1081  VALGRIND_MAKE_MEM_NOACCESS(pointer, oldsize);
1082  VALGRIND_MAKE_MEM_DEFINED(pointer, size);
1083 #endif
1084 
1085  return pointer;
1086  }
1087 
1088  if (oldsize > set->allocChunkLimit)
1089  {
1090  /*
1091  * The chunk must have been allocated as a single-chunk block. Find
1092  * the containing block and use realloc() to make it bigger with
1093  * minimum space wastage.
1094  */
1095  AllocBlock block = set->blocks;
1096  AllocBlock prevblock = NULL;
1097  Size chksize;
1098  Size blksize;
1099 
1100  while (block != NULL)
1101  {
1102  if (chunk == (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ))
1103  break;
1104  prevblock = block;
1105  block = block->next;
1106  }
1107  if (block == NULL)
1108  elog(ERROR, "could not find block containing chunk %p", chunk);
1109  /* let's just make sure chunk is the only one in the block */
1110  Assert(block->freeptr == ((char *) block) +
1111  (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ));
1112 
1113  /* Do the realloc */
1114  chksize = MAXALIGN(size);
1115  blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
1116  block = (AllocBlock) realloc(block, blksize);
1117  if (block == NULL)
1118  return NULL;
1119  block->freeptr = block->endptr = ((char *) block) + blksize;
1120 
1121  /* Update pointers since block has likely been moved */
1122  chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
1123  pointer = AllocChunkGetPointer(chunk);
1124  if (prevblock == NULL)
1125  set->blocks = block;
1126  else
1127  prevblock->next = block;
1128  chunk->size = chksize;
1129 
1130 #ifdef MEMORY_CONTEXT_CHECKING
1131 #ifdef RANDOMIZE_ALLOCATED_MEMORY
1132  /* We can only fill the extra space if we know the prior request */
1133  randomize_mem((char *) pointer + chunk->requested_size,
1134  size - chunk->requested_size);
1135 #endif
1136 
1137  /*
1138  * realloc() (or randomize_mem()) will have left the newly-allocated
1139  * part UNDEFINED, but we may need to adjust trailing bytes from the
1140  * old allocation.
1141  */
1142  VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + chunk->requested_size,
1143  oldsize - chunk->requested_size);
1144 
1145  chunk->requested_size = size;
1146  VALGRIND_MAKE_MEM_NOACCESS(&chunk->requested_size,
1147  sizeof(chunk->requested_size));
1148 
1149  /* set mark to catch clobber of "unused" space */
1150  if (size < chunk->size)
1151  set_sentinel(AllocChunkGetPointer(chunk), size);
1152 #else /* !MEMORY_CONTEXT_CHECKING */
1153 
1154  /*
1155  * We don't know how much of the old chunk size was the actual
1156  * allocation; it could have been as small as one byte. We have to be
1157  * conservative and just mark the entire old portion DEFINED.
1158  */
1159  VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
1160 #endif
1161 
1162  /* Make any trailing alignment padding NOACCESS. */
1163  VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size, chksize - size);
1164  return AllocChunkGetPointer(chunk);
1165  }
1166  else
1167  {
1168  /*
1169  * Small-chunk case. We just do this by brute force, ie, allocate a
1170  * new chunk and copy the data. Since we know the existing data isn't
1171  * huge, this won't involve any great memcpy expense, so it's not
1172  * worth being smarter. (At one time we tried to avoid memcpy when it
1173  * was possible to enlarge the chunk in-place, but that turns out to
1174  * misbehave unpleasantly for repeated cycles of
1175  * palloc/repalloc/pfree: the eventually freed chunks go into the
1176  * wrong freelist for the next initial palloc request, and so we leak
1177  * memory indefinitely. See pgsql-hackers archives for 2007-08-11.)
1178  */
1179  AllocPointer newPointer;
1180 
1181  /* allocate new chunk */
1182  newPointer = AllocSetAlloc((MemoryContext) set, size);
1183 
1184  /* leave immediately if request was not completed */
1185  if (newPointer == NULL)
1186  return NULL;
1187 
1188  /*
1189  * AllocSetAlloc() just made the region NOACCESS. Change it to
1190  * UNDEFINED for the moment; memcpy() will then transfer definedness
1191  * from the old allocation to the new. If we know the old allocation,
1192  * copy just that much. Otherwise, make the entire old chunk defined
1193  * to avoid errors as we copy the currently-NOACCESS trailing bytes.
1194  */
1195  VALGRIND_MAKE_MEM_UNDEFINED(newPointer, size);
1196 #ifdef MEMORY_CONTEXT_CHECKING
1197  oldsize = chunk->requested_size;
1198 #else
1199  VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
1200 #endif
1201 
1202  /* transfer existing data (certain to fit) */
1203  memcpy(newPointer, pointer, oldsize);
1204 
1205  /* free old chunk */
1206  AllocSetFree((MemoryContext) set, pointer);
1207 
1208  return newPointer;
1209  }
1210 }
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
AllocBlock blocks
Definition: aset.c:177
MemoryContextData header
Definition: aset.c:175
void * AllocPointer
Definition: aset.c:162
#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:242
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:139
char * freeptr
Definition: aset.c:205
#define ERROR
Definition: elog.h:43
char * endptr
Definition: aset.c:206
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:140
AllocBlock next
Definition: aset.c:204
#define WARNING
Definition: elog.h:40
struct AllocBlockData * AllocBlock
Definition: aset.c:155
Size allocChunkLimit
Definition: aset.c:183
struct AllocChunkData * AllocChunk
Definition: aset.c:156
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
static void AllocSetFree(MemoryContext context, void *pointer)
Definition: aset.c:942
size_t Size
Definition: c.h:353
#define MAXALIGN(LEN)
Definition: c.h:584
#define realloc(a, b)
Definition: header.h:55
static void * AllocSetAlloc(MemoryContext context, Size size)
Definition: aset.c:672
AllocSetContext * AllocSet
Definition: aset.c:187
#define elog
Definition: elog.h:219
Size size
Definition: aset.c:220
#define AllocPointerGetChunk(ptr)
Definition: aset.c:240
static void AllocSetReset ( MemoryContext  context)
static

Definition at line 571 of file aset.c.

References ALLOC_BLOCKHDRSZ, AllocSetIsValid, AssertArg, AllocSetContext::blocks, free, AllocSetContext::freelist, AllocBlockData::freeptr, AllocSetContext::initBlockSize, AllocSetContext::keeper, MemSetAligned, AllocBlockData::next, next, AllocSetContext::nextBlockSize, NULL, and VALGRIND_MAKE_MEM_NOACCESS.

572 {
573  AllocSet set = (AllocSet) context;
574  AllocBlock block;
575 
577 
578 #ifdef MEMORY_CONTEXT_CHECKING
579  /* Check for corruption and leaks before freeing */
580  AllocSetCheck(context);
581 #endif
582 
583  /* Clear chunk freelists */
584  MemSetAligned(set->freelist, 0, sizeof(set->freelist));
585 
586  block = set->blocks;
587 
588  /* New blocks list is either empty or just the keeper block */
589  set->blocks = set->keeper;
590 
591  while (block != NULL)
592  {
593  AllocBlock next = block->next;
594 
595  if (block == set->keeper)
596  {
597  /* Reset the block, but don't return it to malloc */
598  char *datastart = ((char *) block) + ALLOC_BLOCKHDRSZ;
599 
600 #ifdef CLOBBER_FREED_MEMORY
601  wipe_mem(datastart, block->freeptr - datastart);
602 #else
603  /* wipe_mem() would have done this */
604  VALGRIND_MAKE_MEM_NOACCESS(datastart, block->freeptr - datastart);
605 #endif
606  block->freeptr = datastart;
607  block->next = NULL;
608  }
609  else
610  {
611  /* Normal case, release the block */
612 #ifdef CLOBBER_FREED_MEMORY
613  wipe_mem(block, block->freeptr - ((char *) block));
614 #endif
615  free(block);
616  }
617  block = next;
618  }
619 
620  /* Reset block size allocation sequence, too */
621  set->nextBlockSize = set->initBlockSize;
622 }
#define MemSetAligned(start, val, len)
Definition: c.h:886
Size initBlockSize
Definition: aset.c:180
AllocBlock blocks
Definition: aset.c:177
static int32 next
Definition: blutils.c:210
#define AllocSetIsValid(set)
Definition: aset.c:238
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition: memdebug.h:27
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:139
AllocBlock keeper
Definition: aset.c:184
char * freeptr
Definition: aset.c:205
AllocBlock next
Definition: aset.c:204
#define AssertArg(condition)
Definition: c.h:673
AllocChunk freelist[ALLOCSET_NUM_FREELISTS]
Definition: aset.c:178
Size nextBlockSize
Definition: aset.c:182
#define free(a)
Definition: header.h:60
#define NULL
Definition: c.h:226
AllocSetContext * AllocSet
Definition: aset.c:187
static void AllocSetStats ( MemoryContext  context,
int  level,
bool  print,
MemoryContextCounters totals 
)
static

Definition at line 1252 of file aset.c.

References ALLOC_CHUNKHDRSZ, ALLOCSET_NUM_FREELISTS, AllocChunkData::aset, AllocSetContext::blocks, AllocBlockData::endptr, MemoryContextCounters::freechunks, AllocSetContext::freelist, AllocBlockData::freeptr, MemoryContextCounters::freespace, AllocSetContext::header, i, MemoryContextData::name, MemoryContextCounters::nblocks, AllocBlockData::next, NULL, AllocChunkData::size, and MemoryContextCounters::totalspace.

1254 {
1255  AllocSet set = (AllocSet) context;
1256  Size nblocks = 0;
1257  Size freechunks = 0;
1258  Size totalspace = 0;
1259  Size freespace = 0;
1260  AllocBlock block;
1261  int fidx;
1262 
1263  for (block = set->blocks; block != NULL; block = block->next)
1264  {
1265  nblocks++;
1266  totalspace += block->endptr - ((char *) block);
1267  freespace += block->endptr - block->freeptr;
1268  }
1269  for (fidx = 0; fidx < ALLOCSET_NUM_FREELISTS; fidx++)
1270  {
1271  AllocChunk chunk;
1272 
1273  for (chunk = set->freelist[fidx]; chunk != NULL;
1274  chunk = (AllocChunk) chunk->aset)
1275  {
1276  freechunks++;
1277  freespace += chunk->size + ALLOC_CHUNKHDRSZ;
1278  }
1279  }
1280 
1281  if (print)
1282  {
1283  int i;
1284 
1285  for (i = 0; i < level; i++)
1286  fprintf(stderr, " ");
1287  fprintf(stderr,
1288  "%s: %zu total in %zd blocks; %zu free (%zd chunks); %zu used\n",
1289  set->header.name, totalspace, nblocks, freespace, freechunks,
1290  totalspace - freespace);
1291  }
1292 
1293  if (totals)
1294  {
1295  totals->nblocks += nblocks;
1296  totals->freechunks += freechunks;
1297  totals->totalspace += totalspace;
1298  totals->freespace += freespace;
1299  }
1300 }
AllocBlock blocks
Definition: aset.c:177
void print(const void *obj)
Definition: print.c:35
MemoryContextData header
Definition: aset.c:175
char * freeptr
Definition: aset.c:205
char * endptr
Definition: aset.c:206
#define ALLOCSET_NUM_FREELISTS
Definition: aset.c:122
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:140
AllocBlock next
Definition: aset.c:204
AllocChunk freelist[ALLOCSET_NUM_FREELISTS]
Definition: aset.c:178
#define NULL
Definition: c.h:226
size_t Size
Definition: c.h:353
void * aset
Definition: aset.c:218
int i
AllocSetContext * AllocSet
Definition: aset.c:187
Size size
Definition: aset.c:220

Variable Documentation

MemoryContextMethods AllocSetMethods
static
Initial value:
= {
}
static void AllocSetInit(MemoryContext context)
Definition: aset.c:551
static Size AllocSetGetChunkSpace(MemoryContext context, void *pointer)
Definition: aset.c:1218
static void AllocSetReset(MemoryContext context)
Definition: aset.c:571
static void * AllocSetRealloc(MemoryContext context, void *pointer, Size size)
Definition: aset.c:1023
static bool AllocSetIsEmpty(MemoryContext context)
Definition: aset.c:1230
static void AllocSetFree(MemoryContext context, void *pointer)
Definition: aset.c:942
static void AllocSetStats(MemoryContext context, int level, bool print, MemoryContextCounters *totals)
Definition: aset.c:1252
static void AllocSetDelete(MemoryContext context)
Definition: aset.c:633
static void * AllocSetAlloc(MemoryContext context, Size size)
Definition: aset.c:672

Definition at line 266 of file aset.c.

Referenced by AllocSetContextCreate().

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:284

Definition at line 286 of file aset.c.

Referenced by AllocSetFreeIndex().