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

Go to the source code of this file.

Data Structures

struct  AllocSetContext
 
struct  AllocBlockData
 
struct  AllocChunkData
 
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 */
 
#define LT16(n)   n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
 
#define AllocFreeInfo(_cxt, _chunk)
 
#define AllocAllocInfo(_cxt, _chunk)
 

Typedefs

typedef struct AllocBlockDataAllocBlock
 
typedef struct AllocChunkDataAllocChunk
 
typedef void * AllocPointer
 
typedef struct AllocSetContext AllocSetContext
 
typedef AllocSetContextAllocSet
 
typedef struct AllocBlockData AllocBlockData
 
typedef struct AllocChunkData AllocChunkData
 
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
 
static const unsigned char LogTable256 [256]
 

Macro Definition Documentation

◆ ALLOC_BLOCKHDRSZ

#define ALLOC_BLOCKHDRSZ   MAXALIGN(sizeof(AllocBlockData))

◆ ALLOC_CHUNK_FRACTION

#define ALLOC_CHUNK_FRACTION   4

Definition at line 85 of file aset.c.

Referenced by AllocSetContextCreateInternal().

◆ ALLOC_CHUNK_LIMIT

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

Definition at line 83 of file aset.c.

Referenced by AllocSetContextCreateInternal().

◆ ALLOC_CHUNKHDRSZ

#define ALLOC_CHUNKHDRSZ   sizeof(struct AllocChunkData)

◆ ALLOC_MINBITS

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

Definition at line 81 of file aset.c.

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

◆ AllocAllocInfo

#define AllocAllocInfo (   _cxt,
  _chunk 
)

Definition at line 325 of file aset.c.

Referenced by AllocSetAlloc().

◆ ALLOCCHUNK_PRIVATE_LEN

#define ALLOCCHUNK_PRIVATE_LEN   offsetof(AllocChunkData, aset)

◆ ALLOCCHUNK_RAWSIZE

#define ALLOCCHUNK_RAWSIZE   (SIZEOF_SIZE_T + SIZEOF_VOID_P)

Definition at line 185 of file aset.c.

◆ AllocChunkGetPointer

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

Definition at line 220 of file aset.c.

Referenced by AllocSetAlloc(), and AllocSetRealloc().

◆ AllocFreeInfo

#define AllocFreeInfo (   _cxt,
  _chunk 
)

Definition at line 324 of file aset.c.

Referenced by AllocSetFree().

◆ AllocPointerGetChunk

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

Definition at line 218 of file aset.c.

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

◆ AllocPointerIsValid

#define AllocPointerIsValid (   pointer)    PointerIsValid(pointer)

Definition at line 210 of file aset.c.

◆ ALLOCSET_NUM_FREELISTS

#define ALLOCSET_NUM_FREELISTS   11

Definition at line 82 of file aset.c.

Referenced by AllocSetFreeIndex(), and AllocSetStats().

◆ AllocSetIsValid

#define AllocSetIsValid (   set)    PointerIsValid(set)

Definition at line 216 of file aset.c.

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

◆ LT16

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

Definition at line 303 of file aset.c.

◆ MAX_FREE_CONTEXTS

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

Definition at line 246 of file aset.c.

Referenced by AllocSetDelete().

Typedef Documentation

◆ AllocBlock

typedef struct AllocBlockData* AllocBlock

Definition at line 105 of file aset.c.

◆ AllocBlockData

◆ AllocChunk

typedef struct AllocChunkData* AllocChunk

Definition at line 106 of file aset.c.

◆ AllocChunkData

◆ AllocPointer

typedef void* AllocPointer

Definition at line 112 of file aset.c.

◆ AllocSet

Definition at line 139 of file aset.c.

◆ AllocSetContext

◆ AllocSetFreeList

Function Documentation

◆ AllocSetAlloc()

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

Definition at line 732 of file aset.c.

References ALLOC_BLOCKHDRSZ, ALLOC_CHUNKHDRSZ, ALLOC_MINBITS, AllocAllocInfo, 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().

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

◆ AllocSetContextCreateInternal()

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

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

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

◆ AllocSetDelete()

static void AllocSetDelete ( MemoryContext  context)
static

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

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

◆ AllocSetFree()

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

Definition at line 1010 of file aset.c.

References ALLOC_BLOCKHDRSZ, ALLOC_CHUNKHDRSZ, ALLOCCHUNK_PRIVATE_LEN, AllocFreeInfo, 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().

1011 {
1012  AllocSet set = (AllocSet) context;
1013  AllocChunk chunk = AllocPointerGetChunk(pointer);
1014 
1015  /* Allow access to private part of chunk header. */
1017 
1018  AllocFreeInfo(set, chunk);
1019 
1020 #ifdef MEMORY_CONTEXT_CHECKING
1021  /* Test for someone scribbling on unused space in chunk */
1022  if (chunk->requested_size < chunk->size)
1023  if (!sentinel_ok(pointer, chunk->requested_size))
1024  elog(WARNING, "detected write past chunk end in %s %p",
1025  set->header.name, chunk);
1026 #endif
1027 
1028  if (chunk->size > set->allocChunkLimit)
1029  {
1030  /*
1031  * Big chunks are certain to have been allocated as single-chunk
1032  * blocks. Just unlink that block and return it to malloc().
1033  */
1034  AllocBlock block = (AllocBlock) (((char *) chunk) - ALLOC_BLOCKHDRSZ);
1035 
1036  /*
1037  * Try to verify that we have a sane block pointer: it should
1038  * reference the correct aset, and freeptr and endptr should point
1039  * just past the chunk.
1040  */
1041  if (block->aset != set ||
1042  block->freeptr != block->endptr ||
1043  block->freeptr != ((char *) block) +
1044  (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
1045  elog(ERROR, "could not find block containing chunk %p", chunk);
1046 
1047  /* OK, remove block from aset's list and free it */
1048  if (block->prev)
1049  block->prev->next = block->next;
1050  else
1051  set->blocks = block->next;
1052  if (block->next)
1053  block->next->prev = block->prev;
1054 
1055  context->mem_allocated -= block->endptr - ((char*) block);
1056 
1057 #ifdef CLOBBER_FREED_MEMORY
1058  wipe_mem(block, block->freeptr - ((char *) block));
1059 #endif
1060  free(block);
1061  }
1062  else
1063  {
1064  /* Normal case, put the chunk into appropriate freelist */
1065  int fidx = AllocSetFreeIndex(chunk->size);
1066 
1067  chunk->aset = (void *) set->freelist[fidx];
1068 
1069 #ifdef CLOBBER_FREED_MEMORY
1070  wipe_mem(pointer, chunk->size);
1071 #endif
1072 
1073 #ifdef MEMORY_CONTEXT_CHECKING
1074  /* Reset requested_size to 0 in chunks that are on freelist */
1075  chunk->requested_size = 0;
1076 #endif
1077  set->freelist[fidx] = chunk;
1078  }
1079 }
#define AllocFreeInfo(_cxt, _chunk)
Definition: aset.c:324
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
static int AllocSetFreeIndex(Size size)
Definition: aset.c:337
#define ALLOCCHUNK_PRIVATE_LEN
Definition: aset.c:204
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:102
AllocSet aset
Definition: aset.c:155
char * freeptr
Definition: aset.c:158
#define ERROR
Definition: elog.h:43
char * endptr
Definition: aset.c:159
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:103
#define WARNING
Definition: elog.h:40
struct AllocBlockData * AllocBlock
Definition: aset.c:105
#define free(a)
Definition: header.h:65
Size mem_allocated
Definition: memnodes.h:82
#define elog(elevel,...)
Definition: elog.h:228
AllocSetContext * AllocSet
Definition: aset.c:139
Size size
Definition: aset.c:177
#define AllocPointerGetChunk(ptr)
Definition: aset.c:218

◆ AllocSetFreeIndex()

static int AllocSetFreeIndex ( Size  size)
inlinestatic

Definition at line 337 of file aset.c.

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

Referenced by AllocSetAlloc(), and AllocSetFree().

338 {
339  int idx;
340  unsigned int t,
341  tsize;
342 
343  if (size > (1 << ALLOC_MINBITS))
344  {
345  tsize = (size - 1) >> ALLOC_MINBITS;
346 
347  /*
348  * At this point we need to obtain log2(tsize)+1, ie, the number of
349  * not-all-zero bits at the right. We used to do this with a
350  * shift-and-count loop, but this function is enough of a hotspot to
351  * justify micro-optimization effort. The best approach seems to be
352  * to use a lookup table. Note that this code assumes that
353  * ALLOCSET_NUM_FREELISTS <= 17, since we only cope with two bytes of
354  * the tsize value.
355  */
356  t = tsize >> 8;
357  idx = t ? LogTable256[t] + 8 : LogTable256[tsize];
358 
360  }
361  else
362  idx = 0;
363 
364  return idx;
365 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:263
#define ALLOCSET_NUM_FREELISTS
Definition: aset.c:82
static const unsigned char LogTable256[256]
Definition: aset.c:305
#define Assert(condition)
Definition: c.h:733
#define ALLOC_MINBITS
Definition: aset.c:81

◆ AllocSetGetChunkSpace()

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

Definition at line 1323 of file aset.c.

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

1324 {
1325  AllocChunk chunk = AllocPointerGetChunk(pointer);
1326  Size result;
1327 
1329  result = chunk->size + ALLOC_CHUNKHDRSZ;
1331  return result;
1332 }
#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:204
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:103
size_t Size
Definition: c.h:467
Size size
Definition: aset.c:177
#define AllocPointerGetChunk(ptr)
Definition: aset.c:218

◆ AllocSetIsEmpty()

static bool AllocSetIsEmpty ( MemoryContext  context)
static

Definition at line 1339 of file aset.c.

References MemoryContextData::isReset.

1340 {
1341  /*
1342  * For now, we say "empty" only if the context is new or just reset. We
1343  * could examine the freelists to determine if all space has been freed,
1344  * but it's not really worth the trouble for present uses of this
1345  * functionality.
1346  */
1347  if (context->isReset)
1348  return true;
1349  return false;
1350 }

◆ AllocSetRealloc()

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

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

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

◆ AllocSetReset()

static void AllocSetReset ( MemoryContext  context)
static

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

571 {
572  AllocSet set = (AllocSet) context;
573  AllocBlock block;
574  Size keepersize PG_USED_FOR_ASSERTS_ONLY
575  = set->keeper->endptr - ((char *) set);
576 
578 
579 #ifdef MEMORY_CONTEXT_CHECKING
580  /* Check for corruption and leaks before freeing */
581  AllocSetCheck(context);
582 #endif
583 
584  /* Clear chunk freelists */
585  MemSetAligned(set->freelist, 0, sizeof(set->freelist));
586 
587  block = set->blocks;
588 
589  /* New blocks list will be just the keeper block */
590  set->blocks = set->keeper;
591 
592  while (block != NULL)
593  {
594  AllocBlock next = block->next;
595 
596  if (block == set->keeper)
597  {
598  /* Reset the block, but don't return it to malloc */
599  char *datastart = ((char *) block) + ALLOC_BLOCKHDRSZ;
600 
601 #ifdef CLOBBER_FREED_MEMORY
602  wipe_mem(datastart, block->freeptr - datastart);
603 #else
604  /* wipe_mem() would have done this */
605  VALGRIND_MAKE_MEM_NOACCESS(datastart, block->freeptr - datastart);
606 #endif
607  block->freeptr = datastart;
608  block->prev = NULL;
609  block->next = NULL;
610  }
611  else
612  {
613  /* Normal case, release the block */
614  context->mem_allocated -= block->endptr - ((char*) block);
615 
616 #ifdef CLOBBER_FREED_MEMORY
617  wipe_mem(block, block->freeptr - ((char *) block));
618 #endif
619  free(block);
620  }
621  block = next;
622  }
623 
624  Assert(context->mem_allocated == keepersize);
625 
626  /* Reset block size allocation sequence, too */
627  set->nextBlockSize = set->initBlockSize;
628 }
#define MemSetAligned(start, val, len)
Definition: c.h:989
static int32 next
Definition: blutils.c:213
#define AllocSetIsValid(set)
Definition: aset.c:216
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition: memdebug.h:27
#define ALLOC_BLOCKHDRSZ
Definition: aset.c:102
char * freeptr
Definition: aset.c:158
char * endptr
Definition: aset.c:159
AllocBlock next
Definition: aset.c:157
#define AssertArg(condition)
Definition: c.h:735
AllocBlock prev
Definition: aset.c:156
#define free(a)
Definition: header.h:65
#define Assert(condition)
Definition: c.h:733
size_t Size
Definition: c.h:467
Size mem_allocated
Definition: memnodes.h:82
AllocSetContext * AllocSet
Definition: aset.c:139
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:123

◆ AllocSetStats()

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

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

1364 {
1365  AllocSet set = (AllocSet) context;
1366  Size nblocks = 0;
1367  Size freechunks = 0;
1368  Size totalspace;
1369  Size freespace = 0;
1370  AllocBlock block;
1371  int fidx;
1372 
1373  /* Include context header in totalspace */
1374  totalspace = MAXALIGN(sizeof(AllocSetContext));
1375 
1376  for (block = set->blocks; block != NULL; block = block->next)
1377  {
1378  nblocks++;
1379  totalspace += block->endptr - ((char *) block);
1380  freespace += block->endptr - block->freeptr;
1381  }
1382  for (fidx = 0; fidx < ALLOCSET_NUM_FREELISTS; fidx++)
1383  {
1384  AllocChunk chunk;
1385 
1386  for (chunk = set->freelist[fidx]; chunk != NULL;
1387  chunk = (AllocChunk) chunk->aset)
1388  {
1389  freechunks++;
1390  freespace += chunk->size + ALLOC_CHUNKHDRSZ;
1391  }
1392  }
1393 
1394  if (printfunc)
1395  {
1396  char stats_string[200];
1397 
1398  snprintf(stats_string, sizeof(stats_string),
1399  "%zu total in %zd blocks; %zu free (%zd chunks); %zu used",
1400  totalspace, nblocks, freespace, freechunks,
1401  totalspace - freespace);
1402  printfunc(context, passthru, stats_string);
1403  }
1404 
1405  if (totals)
1406  {
1407  totals->nblocks += nblocks;
1408  totals->freechunks += freechunks;
1409  totals->totalspace += totalspace;
1410  totals->freespace += freespace;
1411  }
1412 }
char * freeptr
Definition: aset.c:158
char * endptr
Definition: aset.c:159
#define ALLOCSET_NUM_FREELISTS
Definition: aset.c:82
#define ALLOC_CHUNKHDRSZ
Definition: aset.c:103
AllocBlock next
Definition: aset.c:157
size_t Size
Definition: c.h:467
#define MAXALIGN(LEN)
Definition: c.h:686
void * aset
Definition: aset.c:194
AllocSetContext * AllocSet
Definition: aset.c:139
#define snprintf
Definition: port.h:192
Size size
Definition: aset.c:177

Variable Documentation

◆ AllocSetMethods

const MemoryContextMethods AllocSetMethods
static
Initial value:
= {
}
static Size AllocSetGetChunkSpace(MemoryContext context, void *pointer)
Definition: aset.c:1323
static void AllocSetReset(MemoryContext context)
Definition: aset.c:570
static void * AllocSetRealloc(MemoryContext context, void *pointer, Size size)
Definition: aset.c:1094
static void AllocSetStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals)
Definition: aset.c:1361
static bool AllocSetIsEmpty(MemoryContext context)
Definition: aset.c:1339
static void AllocSetFree(MemoryContext context, void *pointer)
Definition: aset.c:1010
static void AllocSetDelete(MemoryContext context)
Definition: aset.c:638
static void * AllocSetAlloc(MemoryContext context, Size size)
Definition: aset.c:732

Definition at line 286 of file aset.c.

Referenced by AllocSetContextCreateInternal().

◆ context_freelists

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

Definition at line 255 of file aset.c.

◆ LogTable256

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

Definition at line 305 of file aset.c.

Referenced by AllocSetFreeIndex().