src/backend/utils/mmgr/slab.c
static void *
SlabAlloc(MemoryContext context, Size size)
{
	SlabContext *slab = castNode(SlabContext, context);
	SlabBlock  *block;
	SlabChunk  *chunk;
	int			idx;

	Assert(slab);

	Assert((slab->minFreeChunks >= 0) &&
		   (slab->minFreeChunks < slab->chunksPerBlock));

	/* make sure we only allow correct request size */
	if (size != slab->chunkSize)
		elog(ERROR, "unexpected alloc chunk size %zu (expected %zu)",
			 size, slab->chunkSize);

	/*
	 * If there are no free chunks in any existing block, create a new block
	 * and put it to the last freelist bucket.
	 *
	 * slab->minFreeChunks == 0 means there are no blocks with free chunks,
	 * thanks to how minFreeChunks is updated at the end of SlabAlloc().
	 */
	if (slab->minFreeChunks == 0)
	{
		block = (SlabBlock *) malloc(slab->blockSize);

		if (block == NULL)
			return NULL;

		block->nfree = slab->chunksPerBlock;
		block->firstFreeChunk = 0;

		/*
		 * Put all the chunks on a freelist. Walk the chunks and point each
		 * one to the next one.
		 */
		for (idx = 0; idx < slab->chunksPerBlock; idx++)
		{
			chunk = SlabBlockGetChunk(slab, block, idx);
			*(int32 *) SlabChunkGetPointer(chunk) = (idx + 1);
		}

		/*
		 * And add it to the last freelist with all chunks empty.
		 *
		 * We know there are no blocks in the freelist, otherwise we wouldn't
		 * need a new block.
		 */
		Assert(dlist_is_empty(&slab->freelist[slab->chunksPerBlock]));

		dlist_push_head(&slab->freelist[slab->chunksPerBlock], &block->node);

		slab->minFreeChunks = slab->chunksPerBlock;
		slab->nblocks += 1;
		context->mem_allocated += slab->blockSize;
	}

	/* grab the block from the freelist (even the new block is there) */
	block = dlist_head_element(SlabBlock, node,
							   &slab->freelist[slab->minFreeChunks]);

	/* make sure we actually got a valid block, with matching nfree */
	Assert(block != NULL);
	Assert(slab->minFreeChunks == block->nfree);
	Assert(block->nfree > 0);

	/* we know index of the first free chunk in the block */
	idx = block->firstFreeChunk;

	/* make sure the chunk index is valid, and that it's marked as empty */
	Assert((idx >= 0) && (idx < slab->chunksPerBlock));

	/* compute the chunk location block start (after the block header) */
	chunk = SlabBlockGetChunk(slab, block, idx);

	/*
	 * Update the block nfree count, and also the minFreeChunks as we've
	 * decreased nfree for a block with the minimum number of free chunks
	 * (because that's how we chose the block).
	 */
	block->nfree--;
	slab->minFreeChunks = block->nfree;

	/*
	 * Remove the chunk from the freelist head. The index of the next free
	 * chunk is stored in the chunk itself.
	 */
	VALGRIND_MAKE_MEM_DEFINED(SlabChunkGetPointer(chunk), sizeof(int32));
	block->firstFreeChunk = *(int32 *) SlabChunkGetPointer(chunk);

	Assert(block->firstFreeChunk >= 0);
	Assert(block->firstFreeChunk <= slab->chunksPerBlock);

	Assert((block->nfree != 0 &&
			block->firstFreeChunk < slab->chunksPerBlock) ||
		   (block->nfree == 0 &&
			block->firstFreeChunk == slab->chunksPerBlock));

	/* move the whole block to the right place in the freelist */
	dlist_delete(&block->node);
	dlist_push_head(&slab->freelist[block->nfree], &block->node);

	/*
	 * And finally update minFreeChunks, i.e. the index to the block with the
	 * lowest number of free chunks. We only need to do that when the block
	 * got full (otherwise we know the current block is the right one). We'll
	 * simply walk the freelist until we find a non-empty entry.
	 */
	if (slab->minFreeChunks == 0)
	{
		for (idx = 1; idx <= slab->chunksPerBlock; idx++)
		{
			if (dlist_is_empty(&slab->freelist[idx]))
				continue;

			/* found a non-empty freelist */
			slab->minFreeChunks = idx;
			break;
		}
	}

	if (slab->minFreeChunks == slab->chunksPerBlock)
		slab->minFreeChunks = 0;

	/* Prepare to initialize the chunk header. */
	VALGRIND_MAKE_MEM_UNDEFINED(chunk, sizeof(SlabChunk));

	chunk->block = block;
	chunk->slab = slab;

#ifdef MEMORY_CONTEXT_CHECKING
	/* slab mark to catch clobber of "unused" space */
	if (slab->chunkSize < (slab->fullChunkSize - sizeof(SlabChunk)))
	{
		set_sentinel(SlabChunkGetPointer(chunk), size);
		VALGRIND_MAKE_MEM_NOACCESS(((char *) chunk) +
								   sizeof(SlabChunk) + slab->chunkSize,
								   slab->fullChunkSize -
								   (slab->chunkSize + sizeof(SlabChunk)));
	}
#endif
#ifdef RANDOMIZE_ALLOCATED_MEMORY
	/* fill the allocated space with junk */
	randomize_mem((char *) SlabChunkGetPointer(chunk), size);
#endif

	Assert(slab->nblocks * slab->blockSize == context->mem_allocated);

	return SlabChunkGetPointer(chunk);
}
/*
 * SlabAlloc
 *		Returns pointer to allocated memory of given size or NULL if
 *		request could not be completed; memory is added to the slab.
 */
SlabAlloc
Returns pointer to allocated memory of given size or NULL if
request could not be completed; memory is added to the slab.
SlabAlloc Returns pointer to allocated memory of given size or NULL if request could not be completed ; memory is added to the slab .
static void *
SlabAlloc(MemoryContext context, Size size)
{
	SlabContext *slab = castNode(SlabContext, context);
	SlabBlock  *block;
	SlabChunk  *chunk;
	int			idx;
	Assert(slab);
	Assert((slab->minFreeChunks >= 0) &&
		   (slab->minFreeChunks < slab->chunksPerBlock));
	if (size != slab->chunkSize)
		elog(ERROR, "unexpected alloc chunk size %zu (expected %zu)",
			 size, slab->chunkSize);
	if (slab->minFreeChunks == 0)
	{
		block = (SlabBlock *) malloc(slab->blockSize);
		if (block == NULL)
			return NULL;
		block->nfree = slab->chunksPerBlock;
		block->firstFreeChunk = 0;
		for (idx = 0; idx < slab->chunksPerBlock; idx++)
		{
			chunk = SlabBlockGetChunk(slab, block, idx);
			*(int32 *) SlabChunkGetPointer(chunk) = (idx + 1);
		}
		Assert(dlist_is_empty(&slab->freelist[slab->chunksPerBlock]));
		dlist_push_head(&slab->freelist[slab->chunksPerBlock], &block->node);
		slab->minFreeChunks = slab->chunksPerBlock;
		slab->nblocks += 1;
		context->mem_allocated += slab->blockSize;
	}
	block = dlist_head_element(SlabBlock, node,
							   &slab->freelist[slab->minFreeChunks]);
	Assert(block != NULL);
	Assert(slab->minFreeChunks == block->nfree);
	Assert(block->nfree > 0);
	idx = block->firstFreeChunk;
	Assert((idx >= 0) && (idx < slab->chunksPerBlock));
	chunk = SlabBlockGetChunk(slab, block, idx);
	block->nfree--;
	slab->minFreeChunks = block->nfree;
	VALGRIND_MAKE_MEM_DEFINED(SlabChunkGetPointer(chunk), sizeof(int32));
	block->firstFreeChunk = *(int32 *) SlabChunkGetPointer(chunk);
	Assert(block->firstFreeChunk >= 0);
	Assert(block->firstFreeChunk <= slab->chunksPerBlock);
	Assert((block->nfree != 0 &&
			block->firstFreeChunk < slab->chunksPerBlock) ||
		   (block->nfree == 0 &&
			block->firstFreeChunk == slab->chunksPerBlock));
	dlist_delete(&block->node);
	dlist_push_head(&slab->freelist[block->nfree], &block->node);
	if (slab->minFreeChunks == 0)
	{
		for (idx = 1; idx <= slab->chunksPerBlock; idx++)
		{
			if (dlist_is_empty(&slab->freelist[idx]))
				continue;
			slab->minFreeChunks = idx;
			break;
		}
	}
	if (slab->minFreeChunks == slab->chunksPerBlock)
		slab->minFreeChunks = 0;
	VALGRIND_MAKE_MEM_UNDEFINED(chunk, sizeof(SlabChunk));
	chunk->block = block;
	chunk->slab = slab;
#ifdef MEMORY_CONTEXT_CHECKING
	if (slab->chunkSize < (slab->fullChunkSize - sizeof(SlabChunk)))
	{
		set_sentinel(SlabChunkGetPointer(chunk), size);
		VALGRIND_MAKE_MEM_NOACCESS(((char *) chunk) +
								   sizeof(SlabChunk) + slab->chunkSize,
								   slab->fullChunkSize -
								   (slab->chunkSize + sizeof(SlabChunk)));
	}
#endif
#ifdef RANDOMIZE_ALLOCATED_MEMORY
	randomize_mem((char *) SlabChunkGetPointer(chunk), size);
#endif
	Assert(slab->nblocks * slab->blockSize == context->mem_allocated);
	return SlabChunkGetPointer(chunk);
}
static void * SlabAlloc ( MemoryContext context , Size size ) { SlabContext * slab = castNode ( SlabContext , context ) ; SlabBlock * block ; SlabChunk * chunk ; int idx ; Assert ( slab ) ; Assert ( ( slab -> minFreeChunks >= 0 ) && ( slab -> minFreeChunks < slab -> chunksPerBlock ) ) ; if ( size != slab -> chunkSize ) elog ( ERROR , " " , size , slab -> chunkSize ) ; if ( slab -> minFreeChunks == 0 ) { block = ( SlabBlock * ) malloc ( slab -> blockSize ) ; if ( block == NULL ) return NULL ; block -> nfree = slab -> chunksPerBlock ; block -> firstFreeChunk = 0 ; for ( idx = 0 ; idx < slab -> chunksPerBlock ; idx ++ ) { chunk = SlabBlockGetChunk ( slab , block , idx ) ; * ( int32 * ) SlabChunkGetPointer ( chunk ) = ( idx + 1 ) ; } Assert ( dlist_is_empty ( & slab -> freelist [ slab -> chunksPerBlock ] ) ) ; dlist_push_head ( & slab -> freelist [ slab -> chunksPerBlock ] , & block -> node ) ; slab -> minFreeChunks = slab -> chunksPerBlock ; slab -> nblocks += 1 ; context -> mem_allocated += slab -> blockSize ; } block = dlist_head_element ( SlabBlock , node , & slab -> freelist [ slab -> minFreeChunks ] ) ; Assert ( block != NULL ) ; Assert ( slab -> minFreeChunks == block -> nfree ) ; Assert ( block -> nfree > 0 ) ; idx = block -> firstFreeChunk ; Assert ( ( idx >= 0 ) && ( idx < slab -> chunksPerBlock ) ) ; chunk = SlabBlockGetChunk ( slab , block , idx ) ; block -> nfree -- ; slab -> minFreeChunks = block -> nfree ; VALGRIND_MAKE_MEM_DEFINED ( SlabChunkGetPointer ( chunk ) , sizeof ( int32 ) ) ; block -> firstFreeChunk = * ( int32 * ) SlabChunkGetPointer ( chunk ) ; Assert ( block -> firstFreeChunk >= 0 ) ; Assert ( block -> firstFreeChunk <= slab -> chunksPerBlock ) ; Assert ( ( block -> nfree != 0 && block -> firstFreeChunk < slab -> chunksPerBlock ) || ( block -> nfree == 0 && block -> firstFreeChunk == slab -> chunksPerBlock ) ) ; dlist_delete ( & block -> node ) ; dlist_push_head ( & slab -> freelist [ block -> nfree ] , & block -> node ) ; if ( slab -> minFreeChunks == 0 ) { for ( idx = 1 ; idx <= slab -> chunksPerBlock ; idx ++ ) { if ( dlist_is_empty ( & slab -> freelist [ idx ] ) ) continue ; slab -> minFreeChunks = idx ; break ; } } if ( slab -> minFreeChunks == slab -> chunksPerBlock ) slab -> minFreeChunks = 0 ; VALGRIND_MAKE_MEM_UNDEFINED ( chunk , sizeof ( SlabChunk ) ) ; chunk -> block = block ; chunk -> slab = slab ; #ifdef MEMORY_CONTEXT_CHECKING if ( slab -> chunkSize < ( slab -> fullChunkSize - sizeof ( SlabChunk ) ) ) { set_sentinel ( SlabChunkGetPointer ( chunk ) , size ) ; VALGRIND_MAKE_MEM_NOACCESS ( ( ( char * ) chunk ) + sizeof ( SlabChunk ) + slab -> chunkSize , slab -> fullChunkSize - ( slab -> chunkSize + sizeof ( SlabChunk ) ) ) ; } #endif #ifdef RANDOMIZE_ALLOCATED_MEMORY randomize_mem ( ( char * ) SlabChunkGetPointer ( chunk ) , size ) ; #endif Assert ( slab -> nblocks * slab -> blockSize == context -> mem_allocated ) ; return SlabChunkGetPointer ( chunk ) ; }
SlabAlloc
              Returns pointer to allocated memory of given size or NULL if
              request could not be completed; memory is added to the slab.
SlabAlloc Returns pointer to allocated memory of given size or NULL if request could not be completed ; memory is added to the slab .
/* make sure we only allow correct request size */ /*
	 * If there are no free chunks in any existing block, create a new block
	 * and put it to the last freelist bucket.
	 *
	 * slab->minFreeChunks == 0 means there are no blocks with free chunks,
	 * thanks to how minFreeChunks is updated at the end of SlabAlloc().
	 */ /*
		 * Put all the chunks on a freelist. Walk the chunks and point each
		 * one to the next one.
		 */ /*
		 * And add it to the last freelist with all chunks empty.
		 *
		 * We know there are no blocks in the freelist, otherwise we wouldn't
		 * need a new block.
		 */ /* grab the block from the freelist (even the new block is there) */ /* make sure we actually got a valid block, with matching nfree */ /* we know index of the first free chunk in the block */ /* make sure the chunk index is valid, and that it's marked as empty */ /* compute the chunk location block start (after the block header) */ /*
	 * Update the block nfree count, and also the minFreeChunks as we've
	 * decreased nfree for a block with the minimum number of free chunks
	 * (because that's how we chose the block).
	 */ /*
	 * Remove the chunk from the freelist head. The index of the next free
	 * chunk is stored in the chunk itself.
	 */ /* move the whole block to the right place in the freelist */ /*
	 * And finally update minFreeChunks, i.e. the index to the block with the
	 * lowest number of free chunks. We only need to do that when the block
	 * got full (otherwise we know the current block is the right one). We'll
	 * simply walk the freelist until we find a non-empty entry.
	 */ /* found a non-empty freelist */ /* Prepare to initialize the chunk header. */ /* slab mark to catch clobber of "unused" space */ /* fill the allocated space with junk */