src/backend/utils/mmgr/aset.c
MemoryContext
AllocSetContextCreateInternal(MemoryContext parent,
							  const char *name,
							  Size minContextSize,
							  Size initBlockSize,
							  Size maxBlockSize)
{
	int			freeListIndex;
	Size		firstBlockSize;
	AllocSet	set;
	AllocBlock	block;

	/* Assert we padded AllocChunkData properly */
	StaticAssertStmt(ALLOC_CHUNKHDRSZ == MAXALIGN(ALLOC_CHUNKHDRSZ),
					 "sizeof(AllocChunkData) is not maxaligned");
	StaticAssertStmt(offsetof(AllocChunkData, aset) + sizeof(MemoryContext) ==
					 ALLOC_CHUNKHDRSZ,
					 "padding calculation in AllocChunkData is wrong");

	/*
	 * First, validate allocation parameters.  Once these were regular runtime
	 * test and elog's, but in practice Asserts seem sufficient because nobody
	 * varies their parameters at runtime.  We somewhat arbitrarily enforce a
	 * minimum 1K block size.
	 */
	Assert(initBlockSize == MAXALIGN(initBlockSize) &&
		   initBlockSize >= 1024);
	Assert(maxBlockSize == MAXALIGN(maxBlockSize) &&
		   maxBlockSize >= initBlockSize &&
		   AllocHugeSizeIsValid(maxBlockSize)); /* must be safe to double */
	Assert(minContextSize == 0 ||
		   (minContextSize == MAXALIGN(minContextSize) &&
			minContextSize >= 1024 &&
			minContextSize <= maxBlockSize));

	/*
	 * Check whether the parameters match either available freelist.  We do
	 * not need to demand a match of maxBlockSize.
	 */
	if (minContextSize == ALLOCSET_DEFAULT_MINSIZE &&
		initBlockSize == ALLOCSET_DEFAULT_INITSIZE)
		freeListIndex = 0;
	else if (minContextSize == ALLOCSET_SMALL_MINSIZE &&
			 initBlockSize == ALLOCSET_SMALL_INITSIZE)
		freeListIndex = 1;
	else
		freeListIndex = -1;

	/*
	 * If a suitable freelist entry exists, just recycle that context.
	 */
	if (freeListIndex >= 0)
	{
		AllocSetFreeList *freelist = &context_freelists[freeListIndex];

		if (freelist->first_free != NULL)
		{
			/* Remove entry from freelist */
			set = freelist->first_free;
			freelist->first_free = (AllocSet) set->header.nextchild;
			freelist->num_free--;

			/* Update its maxBlockSize; everything else should be OK */
			set->maxBlockSize = maxBlockSize;

			/* Reinitialize its header, installing correct name and parent */
			MemoryContextCreate((MemoryContext) set,
								T_AllocSetContext,
								&AllocSetMethods,
								parent,
								name);

			((MemoryContext) set)->mem_allocated =
				set->keeper->endptr - ((char *) set);

			return (MemoryContext) set;
		}
	}

	/* Determine size of initial block */
	firstBlockSize = MAXALIGN(sizeof(AllocSetContext)) +
		ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
	if (minContextSize != 0)
		firstBlockSize = Max(firstBlockSize, minContextSize);
	else
		firstBlockSize = Max(firstBlockSize, initBlockSize);

	/*
	 * Allocate the initial block.  Unlike other aset.c blocks, it starts with
	 * the context header and its block header follows that.
	 */
	set = (AllocSet) malloc(firstBlockSize);
	if (set == NULL)
	{
		if (TopMemoryContext)
			MemoryContextStats(TopMemoryContext);
		ereport(ERROR,
				(errcode(ERRCODE_OUT_OF_MEMORY),
				 errmsg("out of memory"),
				 errdetail("Failed while creating memory context \"%s\".",
						   name)));
	}

	/*
	 * Avoid writing code that can fail between here and MemoryContextCreate;
	 * we'd leak the header/initial block if we ereport in this stretch.
	 */

	/* Fill in the initial block's block header */
	block = (AllocBlock) (((char *) set) + MAXALIGN(sizeof(AllocSetContext)));
	block->aset = set;
	block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
	block->endptr = ((char *) set) + firstBlockSize;
	block->prev = NULL;
	block->next = NULL;

	/* Mark unallocated space NOACCESS; leave the block header alone. */
	VALGRIND_MAKE_MEM_NOACCESS(block->freeptr, block->endptr - block->freeptr);

	/* Remember block as part of block list */
	set->blocks = block;
	/* Mark block as not to be released at reset time */
	set->keeper = block;

	/* Finish filling in aset-specific parts of the context header */
	MemSetAligned(set->freelist, 0, sizeof(set->freelist));

	set->initBlockSize = initBlockSize;
	set->maxBlockSize = maxBlockSize;
	set->nextBlockSize = initBlockSize;
	set->freeListIndex = freeListIndex;

	/*
	 * Compute the allocation chunk size limit for this context.  It can't be
	 * more than ALLOC_CHUNK_LIMIT because of the fixed number of freelists.
	 * If maxBlockSize is small then requests exceeding the maxBlockSize, or
	 * even a significant fraction of it, should be treated as large chunks
	 * too.  For the typical case of maxBlockSize a power of 2, the chunk size
	 * limit will be at most 1/8th maxBlockSize, so that given a stream of
	 * requests that are all the maximum chunk size we will waste at most
	 * 1/8th of the allocated space.
	 *
	 * We have to have allocChunkLimit a power of two, because the requested
	 * and actually-allocated sizes of any chunk must be on the same side of
	 * the limit, else we get confused about whether the chunk is "big".
	 *
	 * Also, allocChunkLimit must not exceed ALLOCSET_SEPARATE_THRESHOLD.
	 */
	StaticAssertStmt(ALLOC_CHUNK_LIMIT == ALLOCSET_SEPARATE_THRESHOLD,
					 "ALLOC_CHUNK_LIMIT != ALLOCSET_SEPARATE_THRESHOLD");

	set->allocChunkLimit = ALLOC_CHUNK_LIMIT;
	while ((Size) (set->allocChunkLimit + ALLOC_CHUNKHDRSZ) >
		   (Size) ((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION))
		set->allocChunkLimit >>= 1;

	/* Finally, do the type-independent part of context creation */
	MemoryContextCreate((MemoryContext) set,
						T_AllocSetContext,
						&AllocSetMethods,
						parent,
						name);

	((MemoryContext) set)->mem_allocated = firstBlockSize;

	return (MemoryContext) set;
}
/*
 * AllocSetContextCreateInternal
 *		Create a new AllocSet context.
 *
 * parent: parent context, or NULL if top-level context
 * name: name of context (must be statically allocated)
 * minContextSize: minimum context size
 * initBlockSize: initial allocation block size
 * maxBlockSize: maximum allocation block size
 *
 * Most callers should abstract the context size parameters using a macro
 * such as ALLOCSET_DEFAULT_SIZES.
 *
 * Note: don't call this directly; go through the wrapper macro
 * AllocSetContextCreate.
 */


parent context, or NULL if top-level context
name: name of context (must be statically allocated)
minContextSize: minimum context size
initBlockSize: initial allocation block size
maxBlockSize: maximum allocation block size

Most callers should abstract the context size parameters using a macro
such as ALLOCSET_DEFAULT_SIZES.

don't call this directly; go through the wrapper macro
AllocSetContextCreate.
parent context or NULL if top - level context name : name of context ( must be statically allocated ) minContextSize : minimum context size initBlockSize : initial allocation block size maxBlockSize : maximum allocation block size Most callers should abstract the context size parameters using a macro such as ALLOCSET_DEFAULT_SIZES . don ' t call this directly ; go through the wrapper macro AllocSetContextCreate .
MemoryContext
AllocSetContextCreateInternal(MemoryContext parent,
							  const char *name,
							  Size minContextSize,
							  Size initBlockSize,
							  Size maxBlockSize)
{
	int			freeListIndex;
	Size		firstBlockSize;
	AllocSet	set;
	AllocBlock	block;
	StaticAssertStmt(ALLOC_CHUNKHDRSZ == MAXALIGN(ALLOC_CHUNKHDRSZ),
					 "sizeof(AllocChunkData) is not maxaligned");
	StaticAssertStmt(offsetof(AllocChunkData, aset) + sizeof(MemoryContext) ==
					 ALLOC_CHUNKHDRSZ,
					 "padding calculation in AllocChunkData is wrong");
	Assert(initBlockSize == MAXALIGN(initBlockSize) &&
		   initBlockSize >= 1024);
	Assert(maxBlockSize == MAXALIGN(maxBlockSize) &&
		   maxBlockSize >= initBlockSize &&
		   AllocHugeSizeIsValid(maxBlockSize)); 
	Assert(minContextSize == 0 ||
		   (minContextSize == MAXALIGN(minContextSize) &&
			minContextSize >= 1024 &&
			minContextSize <= maxBlockSize));
	if (minContextSize == ALLOCSET_DEFAULT_MINSIZE &&
		initBlockSize == ALLOCSET_DEFAULT_INITSIZE)
		freeListIndex = 0;
	else if (minContextSize == ALLOCSET_SMALL_MINSIZE &&
			 initBlockSize == ALLOCSET_SMALL_INITSIZE)
		freeListIndex = 1;
	else
		freeListIndex = -1;
	if (freeListIndex >= 0)
	{
		AllocSetFreeList *freelist = &context_freelists[freeListIndex];
		if (freelist->first_free != NULL)
		{
			set = freelist->first_free;
			freelist->first_free = (AllocSet) set->header.nextchild;
			freelist->num_free--;
			set->maxBlockSize = maxBlockSize;
			MemoryContextCreate((MemoryContext) set,
								T_AllocSetContext,
								&AllocSetMethods,
								parent,
								name);
			((MemoryContext) set)->mem_allocated =
				set->keeper->endptr - ((char *) set);
			return (MemoryContext) set;
		}
	}
	firstBlockSize = MAXALIGN(sizeof(AllocSetContext)) +
		ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
	if (minContextSize != 0)
		firstBlockSize = Max(firstBlockSize, minContextSize);
	else
		firstBlockSize = Max(firstBlockSize, initBlockSize);
	set = (AllocSet) malloc(firstBlockSize);
	if (set == NULL)
	{
		if (TopMemoryContext)
			MemoryContextStats(TopMemoryContext);
		ereport(ERROR,
				(errcode(ERRCODE_OUT_OF_MEMORY),
				 errmsg("out of memory"),
				 errdetail("Failed while creating memory context \"%s\".",
						   name)));
	}
	block = (AllocBlock) (((char *) set) + MAXALIGN(sizeof(AllocSetContext)));
	block->aset = set;
	block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
	block->endptr = ((char *) set) + firstBlockSize;
	block->prev = NULL;
	block->next = NULL;
	VALGRIND_MAKE_MEM_NOACCESS(block->freeptr, block->endptr - block->freeptr);
	set->blocks = block;
	set->keeper = block;
	MemSetAligned(set->freelist, 0, sizeof(set->freelist));
	set->initBlockSize = initBlockSize;
	set->maxBlockSize = maxBlockSize;
	set->nextBlockSize = initBlockSize;
	set->freeListIndex = freeListIndex;
	StaticAssertStmt(ALLOC_CHUNK_LIMIT == ALLOCSET_SEPARATE_THRESHOLD,
					 "ALLOC_CHUNK_LIMIT != ALLOCSET_SEPARATE_THRESHOLD");
	set->allocChunkLimit = ALLOC_CHUNK_LIMIT;
	while ((Size) (set->allocChunkLimit + ALLOC_CHUNKHDRSZ) >
		   (Size) ((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION))
		set->allocChunkLimit >>= 1;
	MemoryContextCreate((MemoryContext) set,
						T_AllocSetContext,
						&AllocSetMethods,
						parent,
						name);
	((MemoryContext) set)->mem_allocated = firstBlockSize;
	return (MemoryContext) set;
}
MemoryContext AllocSetContextCreateInternal ( MemoryContext parent , const char * name , Size minContextSize , Size initBlockSize , Size maxBlockSize ) { int freeListIndex ; Size firstBlockSize ; AllocSet set ; AllocBlock block ; StaticAssertStmt ( ALLOC_CHUNKHDRSZ == MAXALIGN ( ALLOC_CHUNKHDRSZ ) , " " ) ; StaticAssertStmt ( offsetof ( AllocChunkData , aset ) + sizeof ( MemoryContext ) == ALLOC_CHUNKHDRSZ , " " ) ; Assert ( initBlockSize == MAXALIGN ( initBlockSize ) && initBlockSize >= 1024 ) ; Assert ( maxBlockSize == MAXALIGN ( maxBlockSize ) && maxBlockSize >= initBlockSize && AllocHugeSizeIsValid ( maxBlockSize ) ) ; Assert ( minContextSize == 0 || ( minContextSize == MAXALIGN ( minContextSize ) && minContextSize >= 1024 && minContextSize <= maxBlockSize ) ) ; if ( minContextSize == ALLOCSET_DEFAULT_MINSIZE && initBlockSize == ALLOCSET_DEFAULT_INITSIZE ) freeListIndex = 0 ; else if ( minContextSize == ALLOCSET_SMALL_MINSIZE && initBlockSize == ALLOCSET_SMALL_INITSIZE ) freeListIndex = 1 ; else freeListIndex = -1 ; if ( freeListIndex >= 0 ) { AllocSetFreeList * freelist = & context_freelists [ freeListIndex ] ; if ( freelist -> first_free != NULL ) { set = freelist -> first_free ; freelist -> first_free = ( AllocSet ) set -> header . nextchild ; freelist -> num_free -- ; set -> maxBlockSize = maxBlockSize ; MemoryContextCreate ( ( MemoryContext ) set , T_AllocSetContext , & AllocSetMethods , parent , name ) ; ( ( MemoryContext ) set ) -> mem_allocated = set -> keeper -> endptr - ( ( char * ) set ) ; return ( MemoryContext ) set ; } } firstBlockSize = MAXALIGN ( sizeof ( AllocSetContext ) ) + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ ; if ( minContextSize != 0 ) firstBlockSize = Max ( firstBlockSize , minContextSize ) ; else firstBlockSize = Max ( firstBlockSize , initBlockSize ) ; set = ( AllocSet ) malloc ( firstBlockSize ) ; if ( set == NULL ) { if ( TopMemoryContext ) MemoryContextStats ( TopMemoryContext ) ; ereport ( ERROR , ( errcode ( ERRCODE_OUT_OF_MEMORY ) , errmsg ( " " ) , errdetail ( " \" \" " , name ) ) ) ; } block = ( AllocBlock ) ( ( ( char * ) set ) + MAXALIGN ( sizeof ( AllocSetContext ) ) ) ; block -> aset = set ; block -> freeptr = ( ( char * ) block ) + ALLOC_BLOCKHDRSZ ; block -> endptr = ( ( char * ) set ) + firstBlockSize ; block -> prev = NULL ; block -> next = NULL ; VALGRIND_MAKE_MEM_NOACCESS ( block -> freeptr , block -> endptr - block -> freeptr ) ; set -> blocks = block ; set -> keeper = block ; MemSetAligned ( set -> freelist , 0 , sizeof ( set -> freelist ) ) ; set -> initBlockSize = initBlockSize ; set -> maxBlockSize = maxBlockSize ; set -> nextBlockSize = initBlockSize ; set -> freeListIndex = freeListIndex ; StaticAssertStmt ( ALLOC_CHUNK_LIMIT == ALLOCSET_SEPARATE_THRESHOLD , " " ) ; set -> allocChunkLimit = ALLOC_CHUNK_LIMIT ; while ( ( Size ) ( set -> allocChunkLimit + ALLOC_CHUNKHDRSZ ) > ( Size ) ( ( maxBlockSize - ALLOC_BLOCKHDRSZ ) / ALLOC_CHUNK_FRACTION ) ) set -> allocChunkLimit >>= 1 ; MemoryContextCreate ( ( MemoryContext ) set , T_AllocSetContext , & AllocSetMethods , parent , name ) ; ( ( MemoryContext ) set ) -> mem_allocated = firstBlockSize ; return ( MemoryContext ) set ; }
AllocSetContextCreateInternal
              Create a new AllocSet context.
AllocSetContextCreateInternal Create a new AllocSet context .
/* Assert we padded AllocChunkData properly */ /*
	 * First, validate allocation parameters.  Once these were regular runtime
	 * test and elog's, but in practice Asserts seem sufficient because nobody
	 * varies their parameters at runtime.  We somewhat arbitrarily enforce a
	 * minimum 1K block size.
	 */ /* must be safe to double */ /*
	 * Check whether the parameters match either available freelist.  We do
	 * not need to demand a match of maxBlockSize.
	 */ /*
	 * If a suitable freelist entry exists, just recycle that context.
	 */ /* Remove entry from freelist */ /* Update its maxBlockSize; everything else should be OK */ /* Reinitialize its header, installing correct name and parent */ /* Determine size of initial block */ /*
	 * Allocate the initial block.  Unlike other aset.c blocks, it starts with
	 * the context header and its block header follows that.
	 */ /*
	 * Avoid writing code that can fail between here and MemoryContextCreate;
	 * we'd leak the header/initial block if we ereport in this stretch.
	 */ /* Fill in the initial block's block header */ /* Mark unallocated space NOACCESS; leave the block header alone. */ /* Remember block as part of block list */ /* Mark block as not to be released at reset time */ /* Finish filling in aset-specific parts of the context header */ /*
	 * Compute the allocation chunk size limit for this context.  It can't be
	 * more than ALLOC_CHUNK_LIMIT because of the fixed number of freelists.
	 * If maxBlockSize is small then requests exceeding the maxBlockSize, or
	 * even a significant fraction of it, should be treated as large chunks
	 * too.  For the typical case of maxBlockSize a power of 2, the chunk size
	 * limit will be at most 1/8th maxBlockSize, so that given a stream of
	 * requests that are all the maximum chunk size we will waste at most
	 * 1/8th of the allocated space.
	 *
	 * We have to have allocChunkLimit a power of two, because the requested
	 * and actually-allocated sizes of any chunk must be on the same side of
	 * the limit, else we get confused about whether the chunk is "big".
	 *
	 * Also, allocChunkLimit must not exceed ALLOCSET_SEPARATE_THRESHOLD.
	 */ /* Finally, do the type-independent part of context creation */