PostgreSQL Source Code  git master
aset.c File Reference
#include "postgres.h"
#include "port/pg_bitutils.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
 
struct  AllocSetFreeList
 

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 ALLOCCHUNK_RAWSIZE   (SIZEOF_SIZE_T + SIZEOF_VOID_P)
 
#define ALLOCCHUNK_PRIVATE_LEN   offsetof(AllocChunkData, aset)
 
#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 MAX_FREE_CONTEXTS   100 /* arbitrary limit on freelist length */
 

Typedefs

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

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 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, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals)
 
static int AllocSetFreeIndex (Size size)
 
MemoryContext AllocSetContextCreateInternal (MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
 

Variables

static AllocSetFreeList context_freelists [2]
 
static const MemoryContextMethods AllocSetMethods
 

Macro Definition Documentation

◆ ALLOC_BLOCKHDRSZ

#define ALLOC_BLOCKHDRSZ   MAXALIGN(sizeof(AllocBlockData))

◆ ALLOC_CHUNK_FRACTION

#define ALLOC_CHUNK_FRACTION   4

Definition at line 83 of file aset.c.

Referenced by AllocSetContextCreateInternal().

◆ ALLOC_CHUNK_LIMIT

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

Definition at line 81 of file aset.c.

Referenced by AllocSetContextCreateInternal(), and AllocSetFreeIndex().

◆ ALLOC_CHUNKHDRSZ

#define ALLOC_CHUNKHDRSZ   sizeof(struct AllocChunkData)

◆ ALLOC_MINBITS

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

Definition at line 79 of file aset.c.

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

◆ ALLOCCHUNK_PRIVATE_LEN

#define ALLOCCHUNK_PRIVATE_LEN   offsetof(AllocChunkData, aset)

◆ ALLOCCHUNK_RAWSIZE

#define ALLOCCHUNK_RAWSIZE   (SIZEOF_SIZE_T + SIZEOF_VOID_P)

Definition at line 183 of file aset.c.

◆ AllocChunkGetPointer

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

Definition at line 218 of file aset.c.

Referenced by AllocSetAlloc(), and AllocSetRealloc().

◆ AllocPointerGetChunk

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

Definition at line 216 of file aset.c.

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

◆ AllocPointerIsValid

#define AllocPointerIsValid (   pointer)    PointerIsValid(pointer)

Definition at line 208 of file aset.c.

◆ ALLOCSET_NUM_FREELISTS

#define ALLOCSET_NUM_FREELISTS   11

Definition at line 80 of file aset.c.

Referenced by AllocSetFreeIndex(), and AllocSetStats().

◆ AllocSetIsValid

#define AllocSetIsValid (   set)    PointerIsValid(set)

Definition at line 214 of file aset.c.

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

◆ MAX_FREE_CONTEXTS

#define MAX_FREE_CONTEXTS   100 /* arbitrary limit on freelist length */

Definition at line 244 of file aset.c.

Referenced by AllocSetDelete().

Typedef Documentation

◆ AllocBlock

typedef struct AllocBlockData* AllocBlock

Definition at line 103 of file aset.c.

◆ AllocBlockData

◆ AllocChunk

typedef struct AllocChunkData* AllocChunk

Definition at line 104 of file aset.c.

◆ AllocChunkData

◆ AllocPointer

typedef void* AllocPointer

Definition at line 110 of file aset.c.

◆ AllocSet

Definition at line 137 of file aset.c.

◆ AllocSetContext

◆ AllocSetFreeList

Function Documentation

◆ AllocSetAlloc()

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

Definition at line 720 of file aset.c.

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

Referenced by AllocSetRealloc().

721 {
722  AllocSet set = (AllocSet) context;
723  AllocBlock block;
724  AllocChunk chunk;
725  int fidx;
726  Size chunk_size;
727  Size blksize;
728 
730 
731  /*
732  * If requested size exceeds maximum for chunks, allocate an entire block
733  * for this request.
734  */
735  if (size > set->allocChunkLimit)
736  {
737  chunk_size = MAXALIGN(size);
738  blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
739  block = (AllocBlock) malloc(blksize);
740  if (block == NULL)
741  return NULL;
742 
743  context->mem_allocated += blksize;
744 
745  block->aset = set;
746  block->freeptr = block->endptr = ((char *) block) + blksize;
747 
748  chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
749  chunk->aset = set;
750  chunk->size = chunk_size;
751 #ifdef MEMORY_CONTEXT_CHECKING
752  chunk->requested_size = size;
753  /* set mark to catch clobber of "unused" space */
754  if (size < chunk_size)
755  set_sentinel(AllocChunkGetPointer(chunk), size);
756 #endif
757 #ifdef RANDOMIZE_ALLOCATED_MEMORY
758  /* fill the allocated space with junk */
759  randomize_mem((char *) AllocChunkGetPointer(chunk), size);
760 #endif
761 
762  /*
763  * Stick the new block underneath the active allocation block, if any,
764  * so that we don't lose the use of the space remaining therein.
765  */
766  if (set->blocks != NULL)
767  {
768  block->prev = set->blocks;
769  block->next = set->blocks->next;
770  if (block->next)
771  block->next->prev = block;
772  set->blocks->next = block;
773  }
774  else
775  {
776  block->prev = NULL;
777  block->next = NULL;
778  set->blocks = block;
779  }
780 
781  /* Ensure any padding bytes are marked NOACCESS. */
782  VALGRIND_MAKE_MEM_NOACCESS((char *) AllocChunkGetPointer(chunk) + size,
783  chunk_size - size);
784 
785  /* Disallow external access to private part of chunk header. */
787 
788  return AllocChunkGetPointer(chunk);
789  }
790 
791  /*
792  * Request is small enough to be treated as a chunk. Look in the
793  * corresponding free list to see if there is a free chunk we could reuse.
794  * If one is found, remove it from the free list, make it again a member
795  * of the alloc set and return its data address.
796  */
797  fidx = AllocSetFreeIndex(size);
798  chunk = set->freelist[fidx];
799  if (chunk != NULL)
800  {
801  Assert(chunk->size >= size);
802 
803  set->freelist[fidx] = (AllocChunk) chunk->aset;
804 
805  chunk->aset = (void *) set;
806 
807 #ifdef MEMORY_CONTEXT_CHECKING
808  chunk->requested_size = size;
809  /* set mark to catch clobber of "unused" space */
810  if (size < chunk->size)
811  set_sentinel(AllocChunkGetPointer(chunk), size);
812 #endif
813 #ifdef RANDOMIZE_ALLOCATED_MEMORY
814  /* fill the allocated space with junk */
815  randomize_mem((char *) AllocChunkGetPointer(chunk), size);
816 #endif
817 
818  /* Ensure any padding bytes are marked NOACCESS. */
819  VALGRIND_MAKE_MEM_NOACCESS((char *) AllocChunkGetPointer(chunk) + size,
820  chunk->size - size);
821 
822  /* Disallow external access to private part of chunk header. */
824 
825  return AllocChunkGetPointer(chunk);
826  }
827 
828  /*
829  * Choose the actual chunk size to allocate.
830  */
831  chunk_size = (1 << ALLOC_MINBITS) << fidx;
832  Assert(chunk_size >= size);
833 
834  /*
835  * If there is enough room in the active allocation block, we will put the
836  * chunk into that block. Else must start a new one.
837  */
838  if ((block = set->blocks) != NULL)
839  {
840  Size availspace = block->endptr - block->freeptr;
841 
842  if (availspace < (chunk_size + ALLOC_CHUNKHDRSZ))
843  {
844  /*
845  * The existing active (top) block does not have enough room for
846  * the requested allocation, but it might still have a useful
847  * amount of space in it. Once we push it down in the block list,
848  * we'll never try to allocate more space from it. So, before we
849  * do that, carve up its free space into chunks that we can put on
850  * the set's freelists.
851  *
852  * Because we can only get here when there's less than
853  * ALLOC_CHUNK_LIMIT left in the block, this loop cannot iterate
854  * more than ALLOCSET_NUM_FREELISTS-1 times.
855  */
856  while (availspace >= ((1 << ALLOC_MINBITS) + ALLOC_CHUNKHDRSZ))
857  {
858  Size availchunk = availspace - ALLOC_CHUNKHDRSZ;
859  int a_fidx = AllocSetFreeIndex(availchunk);
860 
861  /*
862  * In most cases, we'll get back the index of the next larger
863  * freelist than the one we need to put this chunk on. The
864  * exception is when availchunk is exactly a power of 2.
865  */
866  if (availchunk != ((Size) 1 << (a_fidx + ALLOC_MINBITS)))
867  {
868  a_fidx--;
869  Assert(a_fidx >= 0);
870  availchunk = ((Size) 1 << (a_fidx + ALLOC_MINBITS));
871  }
872 
873  chunk = (AllocChunk) (block->freeptr);
874 
875  /* Prepare to initialize the chunk header. */
876  VALGRIND_MAKE_MEM_UNDEFINED(chunk, ALLOC_CHUNKHDRSZ);
877 
878  block->freeptr += (availchunk + ALLOC_CHUNKHDRSZ);
879  availspace -= (availchunk + ALLOC_CHUNKHDRSZ);
880 
881  chunk->size = availchunk;
882 #ifdef MEMORY_CONTEXT_CHECKING
883  chunk->requested_size = 0; /* mark it free */
884 #endif
885  chunk->aset = (void *) set->freelist[a_fidx];
886  set->freelist[a_fidx] = chunk;
887  }
888 
889  /* Mark that we need to create a new block */
890  block = NULL;
891  }
892  }
893 
894  /*
895  * Time to create a new regular (multi-chunk) block?
896  */
897  if (block == NULL)
898  {
899  Size required_size;
900 
901  /*
902  * The first such block has size initBlockSize, and we double the
903  * space in each succeeding block, but not more than maxBlockSize.
904  */
905  blksize = set->nextBlockSize;
906  set->nextBlockSize <<= 1;
907  if (set->nextBlockSize > set->maxBlockSize)
908  set->nextBlockSize = set->maxBlockSize;
909 
910  /*
911  * If initBlockSize is less than ALLOC_CHUNK_LIMIT, we could need more
912  * space... but try to keep it a power of 2.
913  */
914  required_size = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
915  while (blksize < required_size)
916  blksize <<= 1;
917 
918  /* Try to allocate it */
919  block = (AllocBlock) malloc(blksize);
920 
921  /*
922  * We could be asking for pretty big blocks here, so cope if malloc
923  * fails. But give up if there's less than 1 MB or so available...
924  */
925  while (block == NULL && blksize > 1024 * 1024)
926  {
927  blksize >>= 1;
928  if (blksize < required_size)
929  break;
930  block = (AllocBlock) malloc(blksize);
931  }
932 
933  if (block == NULL)
934  return NULL;
935 
936  context->mem_allocated += blksize;
937 
938  block->aset = set;
939  block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
940  block->endptr = ((char *) block) + blksize;
941 
942  /* Mark unallocated space NOACCESS. */
944  blksize - ALLOC_BLOCKHDRSZ);
945 
946  block->prev = NULL;
947  block->next = set->blocks;
948  if (block->next)
949  block->next->prev = block;
950  set->blocks = block;
951  }
952 
953  /*
954  * OK, do the allocation
955  */
956  chunk = (AllocChunk) (block->freeptr);
957 
958  /* Prepare to initialize the chunk header. */
959  VALGRIND_MAKE_MEM_UNDEFINED(chunk, ALLOC_CHUNKHDRSZ);
960 
961  block->freeptr += (chunk_size + ALLOC_CHUNKHDRSZ);
962  Assert(block->freeptr <= block->endptr);
963 
964  chunk->aset = (void *) set;
965  chunk->size = chunk_size;
966 #ifdef MEMORY_CONTEXT_CHECKING
967  chunk->requested_size = size;
968  /* set mark to catch clobber of "unused" space */
969  if (size < chunk->size)
970  set_sentinel(AllocChunkGetPointer(chunk), size);
971 #endif
972 #ifdef RANDOMIZE_ALLOCATED_MEMORY
973  /* fill the allocated space with junk */
974  randomize_mem((char *) AllocChunkGetPointer(chunk), size);
975 #endif
976 
977  /* Ensure any padding bytes are marked NOACCESS. */
978  VALGRIND_MAKE_MEM_NOACCESS((char *) AllocChunkGetPointer(chunk) + size,
979  chunk_size - size);
980 
981  /* Disallow external access to private part of chunk header. */
983 
984  return AllocChunkGetPointer(chunk);
985 }
#define AllocSetIsValid(set)
Definition: aset.c:214
#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:308
#define AllocChunkGetPointer(chk)
Definition: aset.c:218
#define ALLOCCHUNK_PRIVATE_LEN
Definition: aset.c:202
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:100
AllocSet aset
Definition: aset.c:153
char * freeptr
Definition: aset.c:156
#define malloc(a)
Definition: header.h:50
char * endptr
Definition: aset.c:157
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:101
AllocBlock next
Definition: aset.c:155
#define AssertArg(condition)
Definition: c.h:748
struct AllocBlockData * AllocBlock
Definition: aset.c:103
AllocBlock prev
Definition: aset.c:154
struct AllocChunkData * AllocChunk
Definition: aset.c:104
#define Assert(condition)
Definition: c.h:746
size_t Size
Definition: c.h:474
#define MAXALIGN(LEN)
Definition: c.h:699
Size mem_allocated
Definition: memnodes.h:82
void * aset
Definition: aset.c:192
AllocSetContext * AllocSet
Definition: aset.c:137
#define ALLOC_MINBITS
Definition: aset.c:79
Size size
Definition: aset.c:175

◆ AllocSetContextCreateInternal()

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

Definition at line 378 of file aset.c.

References ALLOC_BLOCKHDRSZ, ALLOC_CHUNK_FRACTION, ALLOC_CHUNK_LIMIT, ALLOC_CHUNKHDRSZ, AllocHugeSizeIsValid, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_SEPARATE_THRESHOLD, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetMethods, AllocBlockData::aset, Assert, AllocBlockData::endptr, ereport, errcode(), errdetail(), errmsg(), ERROR, AllocSetFreeList::first_free, AllocSetContext::freelist, AllocSetContext::freeListIndex, AllocBlockData::freeptr, AllocSetContext::header, AllocSetContext::initBlockSize, malloc, Max, MAXALIGN, AllocSetContext::maxBlockSize, MemoryContextCreate(), MemoryContextStats(), MemSetAligned, name, AllocBlockData::next, MemoryContextData::nextchild, AllocSetFreeList::num_free, offsetof, AllocBlockData::prev, StaticAssertStmt, T_AllocSetContext, TopMemoryContext, and VALGRIND_MAKE_MEM_NOACCESS.

Referenced by GetMemoryChunkContext().

383 {
384  int freeListIndex;
385  Size firstBlockSize;
386  AllocSet set;
387  AllocBlock block;
388 
389  /* Assert we padded AllocChunkData properly */
391  "sizeof(AllocChunkData) is not maxaligned");
394  "padding calculation in AllocChunkData is wrong");
395 
396  /*
397  * First, validate allocation parameters. Once these were regular runtime
398  * test and elog's, but in practice Asserts seem sufficient because nobody
399  * varies their parameters at runtime. We somewhat arbitrarily enforce a
400  * minimum 1K block size.
401  */
402  Assert(initBlockSize == MAXALIGN(initBlockSize) &&
403  initBlockSize >= 1024);
404  Assert(maxBlockSize == MAXALIGN(maxBlockSize) &&
405  maxBlockSize >= initBlockSize &&
406  AllocHugeSizeIsValid(maxBlockSize)); /* must be safe to double */
407  Assert(minContextSize == 0 ||
408  (minContextSize == MAXALIGN(minContextSize) &&
409  minContextSize >= 1024 &&
410  minContextSize <= maxBlockSize));
411 
412  /*
413  * Check whether the parameters match either available freelist. We do
414  * not need to demand a match of maxBlockSize.
415  */
416  if (minContextSize == ALLOCSET_DEFAULT_MINSIZE &&
417  initBlockSize == ALLOCSET_DEFAULT_INITSIZE)
418  freeListIndex = 0;
419  else if (minContextSize == ALLOCSET_SMALL_MINSIZE &&
420  initBlockSize == ALLOCSET_SMALL_INITSIZE)
421  freeListIndex = 1;
422  else
423  freeListIndex = -1;
424 
425  /*
426  * If a suitable freelist entry exists, just recycle that context.
427  */
428  if (freeListIndex >= 0)
429  {
430  AllocSetFreeList *freelist = &context_freelists[freeListIndex];
431 
432  if (freelist->first_free != NULL)
433  {
434  /* Remove entry from freelist */
435  set = freelist->first_free;
436  freelist->first_free = (AllocSet) set->header.nextchild;
437  freelist->num_free--;
438 
439  /* Update its maxBlockSize; everything else should be OK */
440  set->maxBlockSize = maxBlockSize;
441 
442  /* Reinitialize its header, installing correct name and parent */
446  parent,
447  name);
448 
449  ((MemoryContext) set)->mem_allocated =
450  set->keeper->endptr - ((char *) set);
451 
452  return (MemoryContext) set;
453  }
454  }
455 
456  /* Determine size of initial block */
457  firstBlockSize = MAXALIGN(sizeof(AllocSetContext)) +
459  if (minContextSize != 0)
460  firstBlockSize = Max(firstBlockSize, minContextSize);
461  else
462  firstBlockSize = Max(firstBlockSize, initBlockSize);
463 
464  /*
465  * Allocate the initial block. Unlike other aset.c blocks, it starts with
466  * the context header and its block header follows that.
467  */
468  set = (AllocSet) malloc(firstBlockSize);
469  if (set == NULL)
470  {
471  if (TopMemoryContext)
473  ereport(ERROR,
474  (errcode(ERRCODE_OUT_OF_MEMORY),
475  errmsg("out of memory"),
476  errdetail("Failed while creating memory context \"%s\".",
477  name)));
478  }
479 
480  /*
481  * Avoid writing code that can fail between here and MemoryContextCreate;
482  * we'd leak the header/initial block if we ereport in this stretch.
483  */
484 
485  /* Fill in the initial block's block header */
486  block = (AllocBlock) (((char *) set) + MAXALIGN(sizeof(AllocSetContext)));
487  block->aset = set;
488  block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
489  block->endptr = ((char *) set) + firstBlockSize;
490  block->prev = NULL;
491  block->next = NULL;
492 
493  /* Mark unallocated space NOACCESS; leave the block header alone. */
494  VALGRIND_MAKE_MEM_NOACCESS(block->freeptr, block->endptr - block->freeptr);
495 
496  /* Remember block as part of block list */
497  set->blocks = block;
498  /* Mark block as not to be released at reset time */
499  set->keeper = block;
500 
501  /* Finish filling in aset-specific parts of the context header */
502  MemSetAligned(set->freelist, 0, sizeof(set->freelist));
503 
504  set->initBlockSize = initBlockSize;
505  set->maxBlockSize = maxBlockSize;
506  set->nextBlockSize = initBlockSize;
507  set->freeListIndex = freeListIndex;
508 
509  /*
510  * Compute the allocation chunk size limit for this context. It can't be
511  * more than ALLOC_CHUNK_LIMIT because of the fixed number of freelists.
512  * If maxBlockSize is small then requests exceeding the maxBlockSize, or
513  * even a significant fraction of it, should be treated as large chunks
514  * too. For the typical case of maxBlockSize a power of 2, the chunk size
515  * limit will be at most 1/8th maxBlockSize, so that given a stream of
516  * requests that are all the maximum chunk size we will waste at most
517  * 1/8th of the allocated space.
518  *
519  * We have to have allocChunkLimit a power of two, because the requested
520  * and actually-allocated sizes of any chunk must be on the same side of
521  * the limit, else we get confused about whether the chunk is "big".
522  *
523  * Also, allocChunkLimit must not exceed ALLOCSET_SEPARATE_THRESHOLD.
524  */
526  "ALLOC_CHUNK_LIMIT != ALLOCSET_SEPARATE_THRESHOLD");
527 
528  set->allocChunkLimit = ALLOC_CHUNK_LIMIT;
529  while ((Size) (set->allocChunkLimit + ALLOC_CHUNKHDRSZ) >
530  (Size) ((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION))
531  set->allocChunkLimit >>= 1;
532 
533  /* Finally, do the type-independent part of context creation */
537  parent,
538  name);
539 
540  ((MemoryContext) set)->mem_allocated = firstBlockSize;
541 
542  return (MemoryContext) set;
543 }
#define MemSetAligned(start, val, len)
Definition: c.h:983
MemoryContextData header
Definition: aset.c:123
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition: memdebug.h:27
int num_free
Definition: aset.c:248
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:100
AllocSet aset
Definition: aset.c:153
char * freeptr
Definition: aset.c:156
#define ALLOCSET_DEFAULT_MINSIZE
Definition: memutils.h:189
#define ALLOCSET_SMALL_MINSIZE
Definition: memutils.h:199
AllocSetContext * first_free
Definition: aset.c:249
#define malloc(a)
Definition: header.h:50
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:860
static AllocSetFreeList context_freelists[2]
Definition: aset.c:253
#define ERROR
Definition: elog.h:43
#define ALLOC_CHUNK_LIMIT
Definition: aset.c:81
void MemoryContextStats(MemoryContext context)
Definition: mcxt.c:499
char * endptr
Definition: aset.c:157
#define ALLOCSET_SEPARATE_THRESHOLD
Definition: memutils.h:219
int errdetail(const char *fmt,...)
Definition: elog.c:954
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:101
AllocBlock next
Definition: aset.c:155
void MemoryContextCreate(MemoryContext node, NodeTag tag, const MemoryContextMethods *methods, MemoryContext parent, const char *name)
Definition: mcxt.c:749
MemoryContext TopMemoryContext
Definition: mcxt.c:44
struct MemoryContextData * MemoryContext
Definition: palloc.h:36
#define ALLOCSET_SMALL_INITSIZE
Definition: memutils.h:200
#define ALLOC_CHUNK_FRACTION
Definition: aset.c:83
struct AllocBlockData * AllocBlock
Definition: aset.c:103
#define ereport(elevel,...)
Definition: elog.h:144
AllocBlock prev
Definition: aset.c:154
#define Max(x, y)
Definition: c.h:922
#define Assert(condition)
Definition: c.h:746
size_t Size
Definition: c.h:474
#define MAXALIGN(LEN)
Definition: c.h:699
const char * name
Definition: encode.c:561
#define AllocHugeSizeIsValid(size)
Definition: memutils.h:46
int errmsg(const char *fmt,...)
Definition: elog.c:821
#define ALLOCSET_DEFAULT_INITSIZE
Definition: memutils.h:190
static const MemoryContextMethods AllocSetMethods
Definition: aset.c:284
AllocSetContext * AllocSet
Definition: aset.c:137
#define offsetof(type, field)
Definition: c.h:669
MemoryContext nextchild
Definition: memnodes.h:87

◆ AllocSetDelete()

static void AllocSetDelete ( MemoryContext  context)
static

Definition at line 626 of file aset.c.

References AllocSetIsValid, Assert, AssertArg, AllocBlockData::endptr, AllocSetFreeList::first_free, free, AllocSetContext::freelist, AllocBlockData::freeptr, AllocSetContext::header, MemoryContextData::isReset, MAX_FREE_CONTEXTS, MemoryContextData::mem_allocated, MemoryContextResetOnly(), AllocBlockData::next, next, MemoryContextData::nextchild, AllocSetFreeList::num_free, and PG_USED_FOR_ASSERTS_ONLY.

627 {
628  AllocSet set = (AllocSet) context;
629  AllocBlock block = set->blocks;
630  Size keepersize PG_USED_FOR_ASSERTS_ONLY
631  = set->keeper->endptr - ((char *) set);
632 
634 
635 #ifdef MEMORY_CONTEXT_CHECKING
636  /* Check for corruption and leaks before freeing */
637  AllocSetCheck(context);
638 #endif
639 
640  /*
641  * If the context is a candidate for a freelist, put it into that freelist
642  * instead of destroying it.
643  */
644  if (set->freeListIndex >= 0)
645  {
646  AllocSetFreeList *freelist = &context_freelists[set->freeListIndex];
647 
648  /*
649  * Reset the context, if it needs it, so that we aren't hanging on to
650  * more than the initial malloc chunk.
651  */
652  if (!context->isReset)
653  MemoryContextResetOnly(context);
654 
655  /*
656  * If the freelist is full, just discard what's already in it. See
657  * comments with context_freelists[].
658  */
659  if (freelist->num_free >= MAX_FREE_CONTEXTS)
660  {
661  while (freelist->first_free != NULL)
662  {
663  AllocSetContext *oldset = freelist->first_free;
664 
665  freelist->first_free = (AllocSetContext *) oldset->header.nextchild;
666  freelist->num_free--;
667 
668  /* All that remains is to free the header/initial block */
669  free(oldset);
670  }
671  Assert(freelist->num_free == 0);
672  }
673 
674  /* Now add the just-deleted context to the freelist. */
675  set->header.nextchild = (MemoryContext) freelist->first_free;
676  freelist->first_free = set;
677  freelist->num_free++;
678 
679  return;
680  }
681 
682  /* Free all blocks, except the keeper which is part of context header */
683  while (block != NULL)
684  {
685  AllocBlock next = block->next;
686 
687  if (block != set->keeper)
688  context->mem_allocated -= block->endptr - ((char *) block);
689 
690 #ifdef CLOBBER_FREED_MEMORY
691  wipe_mem(block, block->freeptr - ((char *) block));
692 #endif
693 
694  if (block != set->keeper)
695  free(block);
696 
697  block = next;
698  }
699 
700  Assert(context->mem_allocated == keepersize);
701 
702  /* Finally, free the context header, including the keeper block */
703  free(set);
704 }
static int32 next
Definition: blutils.c:219
MemoryContextData header
Definition: aset.c:123
#define AllocSetIsValid(set)
Definition: aset.c:214
int num_free
Definition: aset.c:248
char * freeptr
Definition: aset.c:156
void MemoryContextResetOnly(MemoryContext context)
Definition: mcxt.c:156
AllocSetContext * first_free
Definition: aset.c:249
static AllocSetFreeList context_freelists[2]
Definition: aset.c:253
char * endptr
Definition: aset.c:157
AllocBlock next
Definition: aset.c:155
#define AssertArg(condition)
Definition: c.h:748
struct MemoryContextData * MemoryContext
Definition: palloc.h:36
#define MAX_FREE_CONTEXTS
Definition: aset.c:244
#define free(a)
Definition: header.h:65
#define Assert(condition)
Definition: c.h:746
size_t Size
Definition: c.h:474
Size mem_allocated
Definition: memnodes.h:82
AllocSetContext * AllocSet
Definition: aset.c:137
MemoryContext nextchild
Definition: memnodes.h:87
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:122

◆ AllocSetFree()

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

Definition at line 992 of file aset.c.

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

Referenced by AllocSetRealloc().

993 {
994  AllocSet set = (AllocSet) context;
995  AllocChunk chunk = AllocPointerGetChunk(pointer);
996 
997  /* Allow access to private part of chunk header. */
999 
1000 #ifdef MEMORY_CONTEXT_CHECKING
1001  /* Test for someone scribbling on unused space in chunk */
1002  if (chunk->requested_size < chunk->size)
1003  if (!sentinel_ok(pointer, chunk->requested_size))
1004  elog(WARNING, "detected write past chunk end in %s %p",
1005  set->header.name, chunk);
1006 #endif
1007 
1008  if (chunk->size > set->allocChunkLimit)
1009  {
1010  /*
1011  * Big chunks are certain to have been allocated as single-chunk
1012  * blocks. Just unlink that block and return it to malloc().
1013  */
1014  AllocBlock block = (AllocBlock) (((char *) chunk) - ALLOC_BLOCKHDRSZ);
1015 
1016  /*
1017  * Try to verify that we have a sane block pointer: it should
1018  * reference the correct aset, and freeptr and endptr should point
1019  * just past the chunk.
1020  */
1021  if (block->aset != set ||
1022  block->freeptr != block->endptr ||
1023  block->freeptr != ((char *) block) +
1024  (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
1025  elog(ERROR, "could not find block containing chunk %p", chunk);
1026 
1027  /* OK, remove block from aset's list and free it */
1028  if (block->prev)
1029  block->prev->next = block->next;
1030  else
1031  set->blocks = block->next;
1032  if (block->next)
1033  block->next->prev = block->prev;
1034 
1035  context->mem_allocated -= block->endptr - ((char *) block);
1036 
1037 #ifdef CLOBBER_FREED_MEMORY
1038  wipe_mem(block, block->freeptr - ((char *) block));
1039 #endif
1040  free(block);
1041  }
1042  else
1043  {
1044  /* Normal case, put the chunk into appropriate freelist */
1045  int fidx = AllocSetFreeIndex(chunk->size);
1046 
1047  chunk->aset = (void *) set->freelist[fidx];
1048 
1049 #ifdef CLOBBER_FREED_MEMORY
1050  wipe_mem(pointer, chunk->size);
1051 #endif
1052 
1053 #ifdef MEMORY_CONTEXT_CHECKING
1054  /* Reset requested_size to 0 in chunks that are on freelist */
1055  chunk->requested_size = 0;
1056 #endif
1057  set->freelist[fidx] = chunk;
1058  }
1059 }
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
static int AllocSetFreeIndex(Size size)
Definition: aset.c:308
#define ALLOCCHUNK_PRIVATE_LEN
Definition: aset.c:202
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:100
AllocSet aset
Definition: aset.c:153
char * freeptr
Definition: aset.c:156
#define ERROR
Definition: elog.h:43
char * endptr
Definition: aset.c:157
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:101
#define WARNING
Definition: elog.h:40
struct AllocBlockData * AllocBlock
Definition: aset.c:103
#define free(a)
Definition: header.h:65
Size mem_allocated
Definition: memnodes.h:82
#define elog(elevel,...)
Definition: elog.h:214
AllocSetContext * AllocSet
Definition: aset.c:137
Size size
Definition: aset.c:175
#define AllocPointerGetChunk(ptr)
Definition: aset.c:216

◆ AllocSetFreeIndex()

static int AllocSetFreeIndex ( Size  size)
inlinestatic

Definition at line 308 of file aset.c.

References ALLOC_CHUNK_LIMIT, ALLOC_MINBITS, ALLOCSET_NUM_FREELISTS, Assert, idx(), pg_leftmost_one_pos, and StaticAssertStmt.

Referenced by AllocSetAlloc(), and AllocSetFree().

309 {
310  int idx;
311 
312  if (size > (1 << ALLOC_MINBITS))
313  {
314  /*----------
315  * At this point we must compute ceil(log2(size >> ALLOC_MINBITS)).
316  * This is the same as
317  * pg_leftmost_one_pos32((size - 1) >> ALLOC_MINBITS) + 1
318  * or equivalently
319  * pg_leftmost_one_pos32(size - 1) - ALLOC_MINBITS + 1
320  *
321  * However, rather than just calling that function, we duplicate the
322  * logic here, allowing an additional optimization. It's reasonable
323  * to assume that ALLOC_CHUNK_LIMIT fits in 16 bits, so we can unroll
324  * the byte-at-a-time loop in pg_leftmost_one_pos32 and just handle
325  * the last two bytes.
326  *
327  * Yes, this function is enough of a hot-spot to make it worth this
328  * much trouble.
329  *----------
330  */
331 #ifdef HAVE__BUILTIN_CLZ
332  idx = 31 - __builtin_clz((uint32) size - 1) - ALLOC_MINBITS + 1;
333 #else
334  uint32 t,
335  tsize;
336 
337  /* Statically assert that we only have a 16-bit input value. */
339  "ALLOC_CHUNK_LIMIT must be less than 64kB");
340 
341  tsize = size - 1;
342  t = tsize >> 8;
343  idx = t ? pg_leftmost_one_pos[t] + 8 : pg_leftmost_one_pos[tsize];
344  idx -= ALLOC_MINBITS - 1;
345 #endif
346 
348  }
349  else
350  idx = 0;
351 
352  return idx;
353 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:860
#define ALLOC_CHUNK_LIMIT
Definition: aset.c:81
PGDLLIMPORT const uint8 pg_leftmost_one_pos[256]
Definition: pg_bitutils.c:34
#define ALLOCSET_NUM_FREELISTS
Definition: aset.c:80
unsigned int uint32
Definition: c.h:375
#define Assert(condition)
Definition: c.h:746
#define ALLOC_MINBITS
Definition: aset.c:79

◆ AllocSetGetChunkSpace()

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

Definition at line 1303 of file aset.c.

References ALLOC_CHUNKHDRSZ, ALLOCCHUNK_PRIVATE_LEN, AllocPointerGetChunk, AllocChunkData::size, VALGRIND_MAKE_MEM_DEFINED, and VALGRIND_MAKE_MEM_NOACCESS.

1304 {
1305  AllocChunk chunk = AllocPointerGetChunk(pointer);
1306  Size result;
1307 
1309  result = chunk->size + ALLOC_CHUNKHDRSZ;
1311  return result;
1312 }
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition: memdebug.h:27
#define ALLOCCHUNK_PRIVATE_LEN
Definition: aset.c:202
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:101
size_t Size
Definition: c.h:474
Size size
Definition: aset.c:175
#define AllocPointerGetChunk(ptr)
Definition: aset.c:216

◆ AllocSetIsEmpty()

static bool AllocSetIsEmpty ( MemoryContext  context)
static

Definition at line 1319 of file aset.c.

References MemoryContextData::isReset.

1320 {
1321  /*
1322  * For now, we say "empty" only if the context is new or just reset. We
1323  * could examine the freelists to determine if all space has been freed,
1324  * but it's not really worth the trouble for present uses of this
1325  * functionality.
1326  */
1327  if (context->isReset)
1328  return true;
1329  return false;
1330 }

◆ AllocSetRealloc()

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

Definition at line 1074 of file aset.c.

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

1075 {
1076  AllocSet set = (AllocSet) context;
1077  AllocChunk chunk = AllocPointerGetChunk(pointer);
1078  Size oldsize;
1079 
1080  /* Allow access to private part of chunk header. */
1082 
1083  oldsize = chunk->size;
1084 
1085 #ifdef MEMORY_CONTEXT_CHECKING
1086  /* Test for someone scribbling on unused space in chunk */
1087  if (chunk->requested_size < oldsize)
1088  if (!sentinel_ok(pointer, chunk->requested_size))
1089  elog(WARNING, "detected write past chunk end in %s %p",
1090  set->header.name, chunk);
1091 #endif
1092 
1093  if (oldsize > set->allocChunkLimit)
1094  {
1095  /*
1096  * The chunk must have been allocated as a single-chunk block. Use
1097  * realloc() to make the containing block bigger, or smaller, with
1098  * minimum space wastage.
1099  */
1100  AllocBlock block = (AllocBlock) (((char *) chunk) - ALLOC_BLOCKHDRSZ);
1101  Size chksize;
1102  Size blksize;
1103  Size oldblksize;
1104 
1105  /*
1106  * Try to verify that we have a sane block pointer: it should
1107  * reference the correct aset, and freeptr and endptr should point
1108  * just past the chunk.
1109  */
1110  if (block->aset != set ||
1111  block->freeptr != block->endptr ||
1112  block->freeptr != ((char *) block) +
1113  (oldsize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
1114  elog(ERROR, "could not find block containing chunk %p", chunk);
1115 
1116  /*
1117  * Even if the new request is less than set->allocChunkLimit, we stick
1118  * with the single-chunk block approach. Therefore we need
1119  * chunk->size to be bigger than set->allocChunkLimit, so we don't get
1120  * confused about the chunk's status in future calls.
1121  */
1122  chksize = Max(size, set->allocChunkLimit + 1);
1123  chksize = MAXALIGN(chksize);
1124 
1125  /* Do the realloc */
1126  blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
1127  oldblksize = block->endptr - ((char *) block);
1128 
1129  block = (AllocBlock) realloc(block, blksize);
1130  if (block == NULL)
1131  {
1132  /* Disallow external access to private part of chunk header. */
1134  return NULL;
1135  }
1136 
1137  /* updated separately, not to underflow when (oldblksize > blksize) */
1138  context->mem_allocated -= oldblksize;
1139  context->mem_allocated += blksize;
1140 
1141  block->freeptr = block->endptr = ((char *) block) + blksize;
1142 
1143  /* Update pointers since block has likely been moved */
1144  chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
1145  pointer = AllocChunkGetPointer(chunk);
1146  if (block->prev)
1147  block->prev->next = block;
1148  else
1149  set->blocks = block;
1150  if (block->next)
1151  block->next->prev = block;
1152  chunk->size = chksize;
1153 
1154 #ifdef MEMORY_CONTEXT_CHECKING
1155 #ifdef RANDOMIZE_ALLOCATED_MEMORY
1156  /* We can only fill the extra space if we know the prior request */
1157  if (size > chunk->requested_size)
1158  randomize_mem((char *) pointer + chunk->requested_size,
1159  size - chunk->requested_size);
1160 #endif
1161 
1162  /*
1163  * realloc() (or randomize_mem()) will have left any newly-allocated
1164  * part UNDEFINED, but we may need to adjust trailing bytes from the
1165  * old allocation.
1166  */
1167 #ifdef USE_VALGRIND
1168  if (oldsize > chunk->requested_size)
1169  VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + chunk->requested_size,
1170  oldsize - chunk->requested_size);
1171 #endif
1172 
1173  chunk->requested_size = size;
1174 
1175  /* set mark to catch clobber of "unused" space */
1176  if (size < chunk->size)
1177  set_sentinel(pointer, size);
1178 #else /* !MEMORY_CONTEXT_CHECKING */
1179 
1180  /*
1181  * We don't know how much of the old chunk size was the actual
1182  * allocation; it could have been as small as one byte. We have to be
1183  * conservative and just mark the entire old portion DEFINED.
1184  */
1185  VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
1186 #endif
1187 
1188  /* Ensure any padding bytes are marked NOACCESS. */
1189  VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size, chksize - size);
1190 
1191  /* Disallow external access to private part of chunk header. */
1193 
1194  return pointer;
1195  }
1196 
1197  /*
1198  * Chunk sizes are aligned to power of 2 in AllocSetAlloc(). Maybe the
1199  * allocated area already is >= the new size. (In particular, we will
1200  * fall out here if the requested size is a decrease.)
1201  */
1202  else if (oldsize >= size)
1203  {
1204 #ifdef MEMORY_CONTEXT_CHECKING
1205  Size oldrequest = chunk->requested_size;
1206 
1207 #ifdef RANDOMIZE_ALLOCATED_MEMORY
1208  /* We can only fill the extra space if we know the prior request */
1209  if (size > oldrequest)
1210  randomize_mem((char *) pointer + oldrequest,
1211  size - oldrequest);
1212 #endif
1213 
1214  chunk->requested_size = size;
1215 
1216  /*
1217  * If this is an increase, mark any newly-available part UNDEFINED.
1218  * Otherwise, mark the obsolete part NOACCESS.
1219  */
1220  if (size > oldrequest)
1221  VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + oldrequest,
1222  size - oldrequest);
1223  else
1224  VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size,
1225  oldsize - size);
1226 
1227  /* set mark to catch clobber of "unused" space */
1228  if (size < oldsize)
1229  set_sentinel(pointer, size);
1230 #else /* !MEMORY_CONTEXT_CHECKING */
1231 
1232  /*
1233  * We don't have the information to determine whether we're growing
1234  * the old request or shrinking it, so we conservatively mark the
1235  * entire new allocation DEFINED.
1236  */
1237  VALGRIND_MAKE_MEM_NOACCESS(pointer, oldsize);
1238  VALGRIND_MAKE_MEM_DEFINED(pointer, size);
1239 #endif
1240 
1241  /* Disallow external access to private part of chunk header. */
1243 
1244  return pointer;
1245  }
1246  else
1247  {
1248  /*
1249  * Enlarge-a-small-chunk case. We just do this by brute force, ie,
1250  * allocate a new chunk and copy the data. Since we know the existing
1251  * data isn't huge, this won't involve any great memcpy expense, so
1252  * it's not worth being smarter. (At one time we tried to avoid
1253  * memcpy when it was possible to enlarge the chunk in-place, but that
1254  * turns out to misbehave unpleasantly for repeated cycles of
1255  * palloc/repalloc/pfree: the eventually freed chunks go into the
1256  * wrong freelist for the next initial palloc request, and so we leak
1257  * memory indefinitely. See pgsql-hackers archives for 2007-08-11.)
1258  */
1259  AllocPointer newPointer;
1260 
1261  /* allocate new chunk */
1262  newPointer = AllocSetAlloc((MemoryContext) set, size);
1263 
1264  /* leave immediately if request was not completed */
1265  if (newPointer == NULL)
1266  {
1267  /* Disallow external access to private part of chunk header. */
1269  return NULL;
1270  }
1271 
1272  /*
1273  * AllocSetAlloc() may have returned a region that is still NOACCESS.
1274  * Change it to UNDEFINED for the moment; memcpy() will then transfer
1275  * definedness from the old allocation to the new. If we know the old
1276  * allocation, copy just that much. Otherwise, make the entire old
1277  * chunk defined to avoid errors as we copy the currently-NOACCESS
1278  * trailing bytes.
1279  */
1280  VALGRIND_MAKE_MEM_UNDEFINED(newPointer, size);
1281 #ifdef MEMORY_CONTEXT_CHECKING
1282  oldsize = chunk->requested_size;
1283 #else
1284  VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
1285 #endif
1286 
1287  /* transfer existing data (certain to fit) */
1288  memcpy(newPointer, pointer, oldsize);
1289 
1290  /* free old chunk */
1291  AllocSetFree((MemoryContext) set, pointer);
1292 
1293  return newPointer;
1294  }
1295 }
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
void * AllocPointer
Definition: aset.c:110
#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:218
#define ALLOCCHUNK_PRIVATE_LEN
Definition: aset.c:202
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:100
AllocSet aset
Definition: aset.c:153
char * freeptr
Definition: aset.c:156
#define ERROR
Definition: elog.h:43
char * endptr
Definition: aset.c:157
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:101
#define WARNING
Definition: elog.h:40
struct AllocBlockData * AllocBlock
Definition: aset.c:103
#define Max(x, y)
Definition: c.h:922
struct AllocChunkData * AllocChunk
Definition: aset.c:104
static void AllocSetFree(MemoryContext context, void *pointer)
Definition: aset.c:992
size_t Size
Definition: c.h:474
#define MAXALIGN(LEN)
Definition: c.h:699
#define realloc(a, b)
Definition: header.h:60
Size mem_allocated
Definition: memnodes.h:82
#define elog(elevel,...)
Definition: elog.h:214
static void * AllocSetAlloc(MemoryContext context, Size size)
Definition: aset.c:720
AllocSetContext * AllocSet
Definition: aset.c:137
Size size
Definition: aset.c:175
#define AllocPointerGetChunk(ptr)
Definition: aset.c:216

◆ AllocSetReset()

static void AllocSetReset ( MemoryContext  context)
static

Definition at line 558 of file aset.c.

References ALLOC_BLOCKHDRSZ, AllocSetIsValid, Assert, AssertArg, AllocBlockData::endptr, free, AllocBlockData::freeptr, MemoryContextData::mem_allocated, MemSetAligned, AllocBlockData::next, next, PG_USED_FOR_ASSERTS_ONLY, AllocBlockData::prev, and VALGRIND_MAKE_MEM_NOACCESS.

559 {
560  AllocSet set = (AllocSet) context;
561  AllocBlock block;
562  Size keepersize PG_USED_FOR_ASSERTS_ONLY
563  = set->keeper->endptr - ((char *) set);
564 
566 
567 #ifdef MEMORY_CONTEXT_CHECKING
568  /* Check for corruption and leaks before freeing */
569  AllocSetCheck(context);
570 #endif
571 
572  /* Clear chunk freelists */
573  MemSetAligned(set->freelist, 0, sizeof(set->freelist));
574 
575  block = set->blocks;
576 
577  /* New blocks list will be just the keeper block */
578  set->blocks = set->keeper;
579 
580  while (block != NULL)
581  {
582  AllocBlock next = block->next;
583 
584  if (block == set->keeper)
585  {
586  /* Reset the block, but don't return it to malloc */
587  char *datastart = ((char *) block) + ALLOC_BLOCKHDRSZ;
588 
589 #ifdef CLOBBER_FREED_MEMORY
590  wipe_mem(datastart, block->freeptr - datastart);
591 #else
592  /* wipe_mem() would have done this */
593  VALGRIND_MAKE_MEM_NOACCESS(datastart, block->freeptr - datastart);
594 #endif
595  block->freeptr = datastart;
596  block->prev = NULL;
597  block->next = NULL;
598  }
599  else
600  {
601  /* Normal case, release the block */
602  context->mem_allocated -= block->endptr - ((char *) block);
603 
604 #ifdef CLOBBER_FREED_MEMORY
605  wipe_mem(block, block->freeptr - ((char *) block));
606 #endif
607  free(block);
608  }
609  block = next;
610  }
611 
612  Assert(context->mem_allocated == keepersize);
613 
614  /* Reset block size allocation sequence, too */
615  set->nextBlockSize = set->initBlockSize;
616 }
#define MemSetAligned(start, val, len)
Definition: c.h:983
static int32 next
Definition: blutils.c:219
#define AllocSetIsValid(set)
Definition: aset.c:214
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition: memdebug.h:27
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:100
char * freeptr
Definition: aset.c:156
char * endptr
Definition: aset.c:157
AllocBlock next
Definition: aset.c:155
#define AssertArg(condition)
Definition: c.h:748
AllocBlock prev
Definition: aset.c:154
#define free(a)
Definition: header.h:65
#define Assert(condition)
Definition: c.h:746
size_t Size
Definition: c.h:474
Size mem_allocated
Definition: memnodes.h:82
AllocSetContext * AllocSet
Definition: aset.c:137
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:122

◆ AllocSetStats()

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

Definition at line 1341 of file aset.c.

References ALLOC_BLOCKHDRSZ, ALLOC_CHUNKHDRSZ, ALLOC_MINBITS, ALLOCCHUNK_PRIVATE_LEN, ALLOCSET_NUM_FREELISTS, AllocBlockData::aset, AllocChunkData::aset, Assert, elog, AllocBlockData::endptr, MemoryContextCounters::freechunks, AllocBlockData::freeptr, MemoryContextCounters::freespace, MAXALIGN, MemoryContextData::mem_allocated, name, MemoryContextCounters::nblocks, AllocBlockData::next, AllocBlockData::prev, AllocChunkData::size, snprintf, MemoryContextCounters::totalspace, VALGRIND_MAKE_MEM_DEFINED, VALGRIND_MAKE_MEM_NOACCESS, and WARNING.

1344 {
1345  AllocSet set = (AllocSet) context;
1346  Size nblocks = 0;
1347  Size freechunks = 0;
1348  Size totalspace;
1349  Size freespace = 0;
1350  AllocBlock block;
1351  int fidx;
1352 
1353  /* Include context header in totalspace */
1354  totalspace = MAXALIGN(sizeof(AllocSetContext));
1355 
1356  for (block = set->blocks; block != NULL; block = block->next)
1357  {
1358  nblocks++;
1359  totalspace += block->endptr - ((char *) block);
1360  freespace += block->endptr - block->freeptr;
1361  }
1362  for (fidx = 0; fidx < ALLOCSET_NUM_FREELISTS; fidx++)
1363  {
1364  AllocChunk chunk;
1365 
1366  for (chunk = set->freelist[fidx]; chunk != NULL;
1367  chunk = (AllocChunk) chunk->aset)
1368  {
1369  freechunks++;
1370  freespace += chunk->size + ALLOC_CHUNKHDRSZ;
1371  }
1372  }
1373 
1374  if (printfunc)
1375  {
1376  char stats_string[200];
1377 
1378  snprintf(stats_string, sizeof(stats_string),
1379  "%zu total in %zd blocks; %zu free (%zd chunks); %zu used",
1380  totalspace, nblocks, freespace, freechunks,
1381  totalspace - freespace);
1382  printfunc(context, passthru, stats_string);
1383  }
1384 
1385  if (totals)
1386  {
1387  totals->nblocks += nblocks;
1388  totals->freechunks += freechunks;
1389  totals->totalspace += totalspace;
1390  totals->freespace += freespace;
1391  }
1392 }
char * freeptr
Definition: aset.c:156
char * endptr
Definition: aset.c:157
#define ALLOCSET_NUM_FREELISTS
Definition: aset.c:80
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:101
AllocBlock next
Definition: aset.c:155
size_t Size
Definition: c.h:474
#define MAXALIGN(LEN)
Definition: c.h:699
void * aset
Definition: aset.c:192
AllocSetContext * AllocSet
Definition: aset.c:137
#define snprintf
Definition: port.h:215
Size size
Definition: aset.c:175

Variable Documentation

◆ AllocSetMethods

const MemoryContextMethods AllocSetMethods
static
Initial value:
= {
}
static Size AllocSetGetChunkSpace(MemoryContext context, void *pointer)
Definition: aset.c:1303
static void AllocSetReset(MemoryContext context)
Definition: aset.c:558
static void * AllocSetRealloc(MemoryContext context, void *pointer, Size size)
Definition: aset.c:1074
static void AllocSetStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals)
Definition: aset.c:1341
static bool AllocSetIsEmpty(MemoryContext context)
Definition: aset.c:1319
static void AllocSetFree(MemoryContext context, void *pointer)
Definition: aset.c:992
static void AllocSetDelete(MemoryContext context)
Definition: aset.c:626
static void * AllocSetAlloc(MemoryContext context, Size size)
Definition: aset.c:720

Definition at line 284 of file aset.c.

Referenced by AllocSetContextCreateInternal().

◆ context_freelists

AllocSetFreeList context_freelists[2]
static
Initial value:
=
{
{
0, NULL
},
{
0, NULL
}
}

Definition at line 253 of file aset.c.