aset.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,129 行 · 第 1/3 页

C
1,129
字号
	set->isReset = false;	AllocAllocInfo(set, chunk);	return AllocChunkGetPointer(chunk);}/* * AllocSetFree *		Frees allocated memory; memory is removed from the set. */static voidAllocSetFree(MemoryContext context, void *pointer){	AllocSet	set = (AllocSet) context;	AllocChunk	chunk = AllocPointerGetChunk(pointer);	AllocFreeInfo(set, chunk);#ifdef MEMORY_CONTEXT_CHECKING	/* Test for someone scribbling on unused space in chunk */	if (chunk->requested_size < chunk->size)		if (((char *) pointer)[chunk->requested_size] != 0x7E)			elog(WARNING, "detected write past chunk end in %s %p",				 set->header.name, chunk);#endif	if (chunk->size > set->allocChunkLimit)	{		/*		 * Big chunks are certain to have been allocated as single-chunk		 * blocks.	Find the containing block and return it to malloc().		 */		AllocBlock	block = set->blocks;		AllocBlock	prevblock = NULL;		while (block != NULL)		{			if (chunk == (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ))				break;			prevblock = block;			block = block->next;		}		if (block == NULL)			elog(ERROR, "could not find block containing chunk %p", chunk);		/* let's just make sure chunk is the only one in the block */		Assert(block->freeptr == ((char *) block) +			   (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ));		/* OK, remove block from aset's list and free it */		if (prevblock == NULL)			set->blocks = block->next;		else			prevblock->next = block->next;#ifdef CLOBBER_FREED_MEMORY		/* Wipe freed memory for debugging purposes */		memset(block, 0x7F, block->freeptr - ((char *) block));#endif		free(block);	}	else	{		/* Normal case, put the chunk into appropriate freelist */		int			fidx = AllocSetFreeIndex(chunk->size);		chunk->aset = (void *) set->freelist[fidx];#ifdef CLOBBER_FREED_MEMORY		/* Wipe freed memory for debugging purposes */		memset(pointer, 0x7F, chunk->size);#endif#ifdef MEMORY_CONTEXT_CHECKING		/* Reset requested_size to 0 in chunks that are on freelist */		chunk->requested_size = 0;#endif		set->freelist[fidx] = chunk;	}}/* * AllocSetRealloc *		Returns new pointer to allocated memory of given size; this memory *		is added to the set.  Memory associated with given pointer is copied *		into the new memory, and the old memory is freed. */static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size){	AllocSet	set = (AllocSet) context;	AllocChunk	chunk = AllocPointerGetChunk(pointer);	Size		oldsize = chunk->size;#ifdef MEMORY_CONTEXT_CHECKING	/* Test for someone scribbling on unused space in chunk */	if (chunk->requested_size < oldsize)		if (((char *) pointer)[chunk->requested_size] != 0x7E)			elog(WARNING, "detected write past chunk end in %s %p",				 set->header.name, chunk);#endif	/* isReset must be false already */	Assert(!set->isReset);	/*	 * Chunk sizes are aligned to power of 2 in AllocSetAlloc(). Maybe the	 * allocated area already is >= the new size.  (In particular, we always	 * fall out here if the requested size is a decrease.)	 */	if (oldsize >= size)	{#ifdef MEMORY_CONTEXT_CHECKING		chunk->requested_size = size;		/* set mark to catch clobber of "unused" space */		if (size < oldsize)			((char *) pointer)[size] = 0x7E;#endif		return pointer;	}	if (oldsize > set->allocChunkLimit)	{		/*		 * The chunk must have been allocated as a single-chunk block.	Find		 * the containing block and use realloc() to make it bigger with		 * minimum space wastage.		 */		AllocBlock	block = set->blocks;		AllocBlock	prevblock = NULL;		Size		chksize;		Size		blksize;		while (block != NULL)		{			if (chunk == (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ))				break;			prevblock = block;			block = block->next;		}		if (block == NULL)			elog(ERROR, "could not find block containing chunk %p", chunk);		/* let's just make sure chunk is the only one in the block */		Assert(block->freeptr == ((char *) block) +			   (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ));		/* Do the realloc */		chksize = MAXALIGN(size);		blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;		block = (AllocBlock) realloc(block, blksize);		if (block == NULL)		{			MemoryContextStats(TopMemoryContext);			ereport(ERROR,					(errcode(ERRCODE_OUT_OF_MEMORY),					 errmsg("out of memory"),					 errdetail("Failed on request of size %lu.",							   (unsigned long) size)));		}		block->freeptr = block->endptr = ((char *) block) + blksize;		/* Update pointers since block has likely been moved */		chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);		if (prevblock == NULL)			set->blocks = block;		else			prevblock->next = block;		chunk->size = chksize;#ifdef MEMORY_CONTEXT_CHECKING		chunk->requested_size = size;		/* set mark to catch clobber of "unused" space */		if (size < chunk->size)			((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;#endif		return AllocChunkGetPointer(chunk);	}	else	{		/*		 * Small-chunk case.  We just do this by brute force, ie, allocate a		 * new chunk and copy the data.  Since we know the existing data isn't		 * huge, this won't involve any great memcpy expense, so it's not		 * worth being smarter.  (At one time we tried to avoid memcpy when it		 * was possible to enlarge the chunk in-place, but that turns out to		 * misbehave unpleasantly for repeated cycles of		 * palloc/repalloc/pfree: the eventually freed chunks go into the		 * wrong freelist for the next initial palloc request, and so we leak		 * memory indefinitely.  See pgsql-hackers archives for 2007-08-11.)		 */		AllocPointer newPointer;		/* allocate new chunk */		newPointer = AllocSetAlloc((MemoryContext) set, size);		/* transfer existing data (certain to fit) */		memcpy(newPointer, pointer, oldsize);		/* free old chunk */		AllocSetFree((MemoryContext) set, pointer);		return newPointer;	}}/* * AllocSetGetChunkSpace *		Given a currently-allocated chunk, determine the total space *		it occupies (including all memory-allocation overhead). */static SizeAllocSetGetChunkSpace(MemoryContext context, void *pointer){	AllocChunk	chunk = AllocPointerGetChunk(pointer);	return chunk->size + ALLOC_CHUNKHDRSZ;}/* * AllocSetIsEmpty *		Is an allocset empty of any allocated space? */static boolAllocSetIsEmpty(MemoryContext context){	AllocSet	set = (AllocSet) context;	/*	 * For now, we say "empty" only if the context is new or just reset. We	 * could examine the freelists to determine if all space has been freed,	 * but it's not really worth the trouble for present uses of this	 * functionality.	 */	if (set->isReset)		return true;	return false;}/* * AllocSetStats *		Displays stats about memory consumption of an allocset. */static voidAllocSetStats(MemoryContext context, int level){	AllocSet	set = (AllocSet) context;	long		nblocks = 0;	long		nchunks = 0;	long		totalspace = 0;	long		freespace = 0;	AllocBlock	block;	AllocChunk	chunk;	int			fidx;	int			i;	for (block = set->blocks; block != NULL; block = block->next)	{		nblocks++;		totalspace += block->endptr - ((char *) block);		freespace += block->endptr - block->freeptr;	}	for (fidx = 0; fidx < ALLOCSET_NUM_FREELISTS; fidx++)	{		for (chunk = set->freelist[fidx]; chunk != NULL;			 chunk = (AllocChunk) chunk->aset)		{			nchunks++;			freespace += chunk->size + ALLOC_CHUNKHDRSZ;		}	}	for (i = 0; i < level; i++)		fprintf(stderr, "  ");	fprintf(stderr,			"%s: %lu total in %ld blocks; %lu free (%ld chunks); %lu used\n",			set->header.name, totalspace, nblocks, freespace, nchunks,			totalspace - freespace);}#ifdef MEMORY_CONTEXT_CHECKING/* * AllocSetCheck *		Walk through chunks and check consistency of memory. * * NOTE: report errors as WARNING, *not* ERROR or FATAL.  Otherwise you'll * find yourself in an infinite loop when trouble occurs, because this * routine will be entered again when elog cleanup tries to release memory! */static voidAllocSetCheck(MemoryContext context){	AllocSet	set = (AllocSet) context;	char	   *name = set->header.name;	AllocBlock	block;	for (block = set->blocks; block != NULL; block = block->next)	{		char	   *bpoz = ((char *) block) + ALLOC_BLOCKHDRSZ;		long		blk_used = block->freeptr - bpoz;		long		blk_data = 0;		long		nchunks = 0;		/*		 * Empty block - empty can be keeper-block only		 */		if (!blk_used)		{			if (set->keeper != block)				elog(WARNING, "problem in alloc set %s: empty block %p",					 name, block);		}		/*		 * Chunk walker		 */		while (bpoz < block->freeptr)		{			AllocChunk	chunk = (AllocChunk) bpoz;			Size		chsize,						dsize;			char	   *chdata_end;			chsize = chunk->size;		/* aligned chunk size */			dsize = chunk->requested_size;		/* real data */			chdata_end = ((char *) chunk) + (ALLOC_CHUNKHDRSZ + dsize);			/*			 * Check chunk size			 */			if (dsize > chsize)				elog(WARNING, "problem in alloc set %s: req size > alloc size for chunk %p in block %p",					 name, chunk, block);			if (chsize < (1 << ALLOC_MINBITS))				elog(WARNING, "problem in alloc set %s: bad size %lu for chunk %p in block %p",					 name, (unsigned long) chsize, chunk, block);			/* single-chunk block? */			if (chsize > set->allocChunkLimit &&				chsize + ALLOC_CHUNKHDRSZ != blk_used)				elog(WARNING, "problem in alloc set %s: bad single-chunk %p in block %p",					 name, chunk, block);			/*			 * If chunk is allocated, check for correct aset pointer. (If it's			 * free, the aset is the freelist pointer, which we can't check as			 * easily...)			 */			if (dsize > 0 && chunk->aset != (void *) set)				elog(WARNING, "problem in alloc set %s: bogus aset link in block %p, chunk %p",					 name, block, chunk);			/*			 * Check for overwrite of "unallocated" space in chunk			 */			if (dsize > 0 && dsize < chsize && *chdata_end != 0x7E)				elog(WARNING, "problem in alloc set %s: detected write past chunk end in block %p, chunk %p",					 name, block, chunk);			blk_data += chsize;			nchunks++;			bpoz += ALLOC_CHUNKHDRSZ + chsize;		}		if ((blk_data + (nchunks * ALLOC_CHUNKHDRSZ)) != blk_used)			elog(WARNING, "problem in alloc set %s: found inconsistent memory block %p",				 name, block);	}}#endif   /* MEMORY_CONTEXT_CHECKING */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?