⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aset.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * aset.c *	  Allocation set definitions. * * AllocSet is our standard implementation of the abstract MemoryContext * type. * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/mmgr/aset.c,v 1.64 2005/10/15 02:49:36 momjian Exp $ * * NOTE: *	This is a new (Feb. 05, 1999) implementation of the allocation set *	routines. AllocSet...() does not use OrderedSet...() any more. *	Instead it manages allocations in a block pool by itself, combining *	many small allocations in a few bigger blocks. AllocSetFree() normally *	doesn't free() memory really. It just add's the free'd area to some *	list for later reuse by AllocSetAlloc(). All memory blocks are free()'d *	at once on AllocSetReset(), which happens when the memory context gets *	destroyed. *				Jan Wieck * *	Performance improvement from Tom Lane, 8/99: for extremely large request *	sizes, we do want to be able to give the memory back to free() as soon *	as it is pfree()'d.  Otherwise we risk tying up a lot of memory in *	freelist entries that might never be usable.  This is specially needed *	when the caller is repeatedly repalloc()'ing a block bigger and bigger; *	the previous instances of the block were guaranteed to be wasted until *	AllocSetReset() under the old way. * *	Further improvement 12/00: as the code stood, request sizes in the *	midrange between "small" and "large" were handled very inefficiently, *	because any sufficiently large free chunk would be used to satisfy a *	request, even if it was much larger than necessary.  This led to more *	and more wasted space in allocated chunks over time.  To fix, get rid *	of the midrange behavior: we now handle only "small" power-of-2-size *	chunks as chunks.  Anything "large" is passed off to malloc().	Change *	the number of freelists to change the small/large boundary. * * *	About CLOBBER_FREED_MEMORY: * *	If this symbol is defined, all freed memory is overwritten with 0x7F's. *	This is useful for catching places that reference already-freed memory. * *	About MEMORY_CONTEXT_CHECKING: * *	Since we usually round request sizes up to the next power of 2, there *	is often some unused space immediately after a requested data area. *	Thus, if someone makes the common error of writing past what they've *	requested, the problem is likely to go unnoticed ... until the day when *	there *isn't* any wasted space, perhaps because of different memory *	alignment on a new platform, or some other effect.	To catch this sort *	of problem, the MEMORY_CONTEXT_CHECKING option stores 0x7E just beyond *	the requested space whenever the request is less than the actual chunk *	size, and verifies that the byte is undamaged when the chunk is freed. * *------------------------------------------------------------------------- */#include "postgres.h"#include "utils/memutils.h"/* Define this to detail debug alloc information *//* #define HAVE_ALLOCINFO *//*-------------------- * Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS), * for k = 0 .. ALLOCSET_NUM_FREELISTS-1. * * Note that all chunks in the freelists have power-of-2 sizes.  This * improves recyclability: we may waste some space, but the wasted space * should stay pretty constant as requests are made and released. * * A request too large for the last freelist is handled by allocating a * dedicated block from malloc().  The block still has a block header and * chunk header, but when the chunk is freed we'll return the whole block * to malloc(), not put it on our freelists. * * CAUTION: ALLOC_MINBITS must be large enough so that * 1<<ALLOC_MINBITS is at least MAXALIGN, * or we may fail to align the smallest chunks adequately. * 8-byte alignment is enough on all currently known machines. * * With the current parameters, request sizes up to 8K are treated as chunks, * larger requests go into dedicated blocks.  Change ALLOCSET_NUM_FREELISTS * to adjust the boundary point. *-------------------- */#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))/* Size of largest chunk that we use a fixed size for *//*-------------------- * The first block allocated for an allocset has size initBlockSize. * Each time we have to allocate another block, we double the block size * (if possible, and without exceeding maxBlockSize), so as to reduce * the bookkeeping load on malloc(). * * Blocks allocated to hold oversize chunks do not follow this rule, however; * they are just however big they need to be to hold that single chunk. *-------------------- */#define ALLOC_BLOCKHDRSZ	MAXALIGN(sizeof(AllocBlockData))#define ALLOC_CHUNKHDRSZ	MAXALIGN(sizeof(AllocChunkData))typedef struct AllocBlockData *AllocBlock;		/* forward reference */typedef struct AllocChunkData *AllocChunk;/* * AllocPointer *		Aligned pointer which may be a member of an allocation set. */typedef void *AllocPointer;/* * AllocSetContext is our standard implementation of MemoryContext. * * Note: isReset means there is nothing for AllocSetReset to do.  This is * different from the aset being physically empty (empty blocks list) because * we may still have a keeper block.  It's also different from the set being * logically empty, because we don't attempt to detect pfree'ing the last * active chunk. */typedef struct AllocSetContext{	MemoryContextData header;	/* Standard memory-context fields */	/* Info about storage allocated in this context: */	AllocBlock	blocks;			/* head of list of blocks in this set */	AllocChunk	freelist[ALLOCSET_NUM_FREELISTS];		/* free chunk lists */	bool		isReset;		/* T = no space alloced since last reset */	/* Allocation parameters for this context: */	Size		initBlockSize;	/* initial block size */	Size		maxBlockSize;	/* maximum block size */	AllocBlock	keeper;			/* if not NULL, keep this block over resets */} AllocSetContext;typedef AllocSetContext *AllocSet;/* * AllocBlock *		An AllocBlock is the unit of memory that is obtained by aset.c *		from malloc().	It contains one or more AllocChunks, which are *		the units requested by palloc() and freed by pfree().  AllocChunks *		cannot be returned to malloc() individually, instead they are put *		on freelists by pfree() and re-used by the next palloc() that has *		a matching request size. * *		AllocBlockData is the header data for a block --- the usable space *		within the block begins at the next alignment boundary. */typedef struct AllocBlockData{	AllocSet	aset;			/* aset that owns this block */	AllocBlock	next;			/* next block in aset's blocks list */	char	   *freeptr;		/* start of free space in this block */	char	   *endptr;			/* end of space in this block */} AllocBlockData;/* * AllocChunk *		The prefix of each piece of memory in an AllocBlock * * NB: this MUST match StandardChunkHeader as defined by utils/memutils.h. */typedef struct AllocChunkData{	/* aset is the owning aset if allocated, or the freelist link if free */	void	   *aset;	/* size is always the size of the usable space in the chunk */	Size		size;#ifdef MEMORY_CONTEXT_CHECKING	/* when debugging memory usage, also store actual requested size */	/* this is zero in a free chunk */	Size		requested_size;#endif} AllocChunkData;/* * AllocPointerIsValid *		True iff pointer is valid allocation pointer. */#define AllocPointerIsValid(pointer) PointerIsValid(pointer)/* * AllocSetIsValid *		True iff set is valid allocation set. */#define AllocSetIsValid(set) PointerIsValid(set)#define AllocPointerGetChunk(ptr)	\					((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ))#define AllocChunkGetPointer(chk)	\					((AllocPointer)(((char *)(chk)) + ALLOC_CHUNKHDRSZ))/* * These functions implement the MemoryContext API for AllocSet contexts. */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 AllocSetInit(MemoryContext context);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);#ifdef MEMORY_CONTEXT_CHECKINGstatic void AllocSetCheck(MemoryContext context);#endif/* * This is the virtual function table for AllocSet contexts. */static MemoryContextMethods AllocSetMethods = {	AllocSetAlloc,	AllocSetFree,	AllocSetRealloc,	AllocSetInit,	AllocSetReset,	AllocSetDelete,	AllocSetGetChunkSpace,	AllocSetIsEmpty,	AllocSetStats#ifdef MEMORY_CONTEXT_CHECKING	,AllocSetCheck#endif};/* ---------- * Debug macros * ---------- */#ifdef HAVE_ALLOCINFO#define AllocFreeInfo(_cxt, _chunk) \			fprintf(stderr, "AllocFree: %s: %p, %d\n", \				(_cxt)->header.name, (_chunk), (_chunk)->size)#define AllocAllocInfo(_cxt, _chunk) \			fprintf(stderr, "AllocAlloc: %s: %p, %d\n", \				(_cxt)->header.name, (_chunk), (_chunk)->size)#else#define AllocFreeInfo(_cxt, _chunk)#define AllocAllocInfo(_cxt, _chunk)#endif/* ---------- * AllocSetFreeIndex - * *		Depending on the size of an allocation compute which freechunk *		list of the alloc set it belongs to.  Caller must have verified *		that size <= ALLOC_CHUNK_LIMIT. * ---------- */static inline intAllocSetFreeIndex(Size size){	int			idx = 0;	if (size > 0)	{		size = (size - 1) >> ALLOC_MINBITS;		while (size != 0)		{			idx++;			size >>= 1;		}		Assert(idx < ALLOCSET_NUM_FREELISTS);	}	return idx;}/* * Public routines *//* * AllocSetContextCreate *		Create a new AllocSet context. * * parent: parent context, or NULL if top-level context * name: name of context (for debugging --- string will be copied) * minContextSize: minimum context size * initBlockSize: initial allocation block size * maxBlockSize: maximum allocation block size */MemoryContextAllocSetContextCreate(MemoryContext parent,					  const char *name,					  Size minContextSize,					  Size initBlockSize,					  Size maxBlockSize){	AllocSet	context;	/* Do the type-independent part of context creation */	context = (AllocSet) MemoryContextCreate(T_AllocSetContext,											 sizeof(AllocSetContext),											 &AllocSetMethods,											 parent,											 name);	/*	 * Make sure alloc parameters are reasonable, and save them.	 *	 * We somewhat arbitrarily enforce a minimum 1K block size.	 */	initBlockSize = MAXALIGN(initBlockSize);	if (initBlockSize < 1024)		initBlockSize = 1024;	maxBlockSize = MAXALIGN(maxBlockSize);	if (maxBlockSize < initBlockSize)		maxBlockSize = initBlockSize;	context->initBlockSize = initBlockSize;	context->maxBlockSize = maxBlockSize;	/*	 * Grab always-allocated space, if requested	 */	if (minContextSize > ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)	{		Size		blksize = MAXALIGN(minContextSize);		AllocBlock	block;		block = (AllocBlock) malloc(blksize);		if (block == NULL)		{			MemoryContextStats(TopMemoryContext);			ereport(ERROR,					(errcode(ERRCODE_OUT_OF_MEMORY),					 errmsg("out of memory"),					 errdetail("Failed while creating memory context \"%s\".",							   name)));		}		block->aset = context;		block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;		block->endptr = ((char *) block) + blksize;		block->next = context->blocks;		context->blocks = block;		/* Mark block as not to be released at reset time */		context->keeper = block;	}	context->isReset = true;	return (MemoryContext) context;}/* * AllocSetInit *		Context-type-specific initialization routine. * * This is called by MemoryContextCreate() after setting up the * generic MemoryContext fields and before linking the new context * into the context tree.  We must do whatever is needed to make the * new context minimally valid for deletion.  We must *not* risk * failure --- thus, for example, allocating more memory is not cool. * (AllocSetContextCreate can allocate memory when it gets control * back, however.) */static voidAllocSetInit(MemoryContext context){	/*	 * Since MemoryContextCreate already zeroed the context node, we don't	 * have to do anything here: it's already OK.	 */}/* * AllocSetReset *		Frees all memory which is allocated in the given set. * * Actually, this routine has some discretion about what to do. * It should mark all allocated chunks freed, but it need not necessarily * give back all the resources the set owns.  Our actual implementation is * that we hang onto any "keeper" block specified for the set.	In this way, * we don't thrash malloc() when a context is repeatedly reset after small * allocations, which is typical behavior for per-tuple contexts.

⌨️ 快捷键说明

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