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, bool print_to_stderr)
 
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 721 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().

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

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

◆ AllocSetDelete()

static void AllocSetDelete ( MemoryContext  context)
static

Definition at line 627 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.

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

◆ AllocSetFree()

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

Definition at line 993 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().

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

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

◆ AllocSetGetChunkSpace()

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

Definition at line 1304 of file aset.c.

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

1305 {
1306  AllocChunk chunk = AllocPointerGetChunk(pointer);
1307  Size result;
1308 
1310  result = chunk->size + ALLOC_CHUNKHDRSZ;
1312  return result;
1313 }
#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:540
Size size
Definition: aset.c:175
#define AllocPointerGetChunk(ptr)
Definition: aset.c:216

◆ AllocSetIsEmpty()

static bool AllocSetIsEmpty ( MemoryContext  context)
static

Definition at line 1320 of file aset.c.

References MemoryContextData::isReset.

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

◆ AllocSetRealloc()

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

Definition at line 1075 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.

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

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

◆ AllocSetStats()

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

Definition at line 1343 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.

1346 {
1347  AllocSet set = (AllocSet) context;
1348  Size nblocks = 0;
1349  Size freechunks = 0;
1350  Size totalspace;
1351  Size freespace = 0;
1352  AllocBlock block;
1353  int fidx;
1354 
1355  /* Include context header in totalspace */
1356  totalspace = MAXALIGN(sizeof(AllocSetContext));
1357 
1358  for (block = set->blocks; block != NULL; block = block->next)
1359  {
1360  nblocks++;
1361  totalspace += block->endptr - ((char *) block);
1362  freespace += block->endptr - block->freeptr;
1363  }
1364  for (fidx = 0; fidx < ALLOCSET_NUM_FREELISTS; fidx++)
1365  {
1366  AllocChunk chunk;
1367 
1368  for (chunk = set->freelist[fidx]; chunk != NULL;
1369  chunk = (AllocChunk) chunk->aset)
1370  {
1371  freechunks++;
1372  freespace += chunk->size + ALLOC_CHUNKHDRSZ;
1373  }
1374  }
1375 
1376  if (printfunc)
1377  {
1378  char stats_string[200];
1379 
1380  snprintf(stats_string, sizeof(stats_string),
1381  "%zu total in %zd blocks; %zu free (%zd chunks); %zu used",
1382  totalspace, nblocks, freespace, freechunks,
1383  totalspace - freespace);
1384  printfunc(context, passthru, stats_string, print_to_stderr);
1385  }
1386 
1387  if (totals)
1388  {
1389  totals->nblocks += nblocks;
1390  totals->freechunks += freechunks;
1391  totals->totalspace += totalspace;
1392  totals->freespace += freespace;
1393  }
1394 }
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:540
#define MAXALIGN(LEN)
Definition: c.h:757
void * aset
Definition: aset.c:192
AllocSetContext * AllocSet
Definition: aset.c:137
#define snprintf
Definition: port.h:217
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:1304
static void AllocSetReset(MemoryContext context)
Definition: aset.c:559
static void AllocSetStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
Definition: aset.c:1343
static void * AllocSetRealloc(MemoryContext context, void *pointer, Size size)
Definition: aset.c:1075
static bool AllocSetIsEmpty(MemoryContext context)
Definition: aset.c:1320
static void AllocSetFree(MemoryContext context, void *pointer)
Definition: aset.c:993
static void AllocSetDelete(MemoryContext context)
Definition: aset.c:627
static void * AllocSetAlloc(MemoryContext context, Size size)
Definition: aset.c:721

Definition at line 285 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.