diff options
Diffstat (limited to 'src/backend/utils/mmgr')
| -rw-r--r-- | src/backend/utils/mmgr/aset.c | 367 | ||||
| -rw-r--r-- | src/backend/utils/mmgr/mcxt.c | 11 | ||||
| -rw-r--r-- | src/backend/utils/mmgr/palloc.c | 90 | ||||
| -rw-r--r-- | src/backend/utils/mmgr/portalmem.c | 21 |
4 files changed, 204 insertions, 285 deletions
diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index 008c629e5c..15b5094881 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -7,12 +7,18 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.11 1998/09/01 04:33:34 momjian Exp $ - * - * NOTE - * XXX This is a preliminary implementation which lacks fail-fast - * XXX validity checking of arguments. + * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.12 1999/02/06 16:50:25 wieck 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() does + * never 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 + * on AllocSetReset() at once, what happens when the memory context gets + * destroyed. + * Jan Wieck *------------------------------------------------------------------------- */ #include <stdio.h> @@ -25,56 +31,59 @@ #include <string.h> #endif -static void AllocPointerDump(AllocPointer pointer); -static int AllocSetIterate(AllocSet set, - void (*function) (AllocPointer pointer)); #undef AllocSetReset #undef malloc #undef free +#undef realloc -/* - * Internal type definitions - */ /* - * AllocElem -- - * Allocation element. +#define ALLOC_BLOCK_SIZE 8192 +#define ALLOC_CHUNK_LIMIT 512 + * + * The above settings for block size and chunk limit gain better + * performance. But the ones below force a bug that I didn't found + * up to now letting the portals_p2 regression test fail. + * */ -typedef struct AllocElemData -{ - OrderedElemData elemData; /* elem in AllocSet */ - Size size; -} AllocElemData; +#define ALLOC_BLOCK_SIZE 16384 +#define ALLOC_CHUNK_LIMIT 256 -typedef AllocElemData *AllocElem; +#define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData)) +#define ALLOC_CHUNKHDRSZ MAXALIGN(sizeof(AllocChunkData)) +#define AllocPointerGetChunk(ptr) \ + ((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ)) +#define AllocChunkGetPointer(chk) \ + ((AllocPointer)(((char *)(chk)) + ALLOC_CHUNKHDRSZ)) +#define AllocPointerGetAset(ptr) ((AllocSet)(AllocPointerGetChunk(ptr)->aset)) +#define AllocPointerGetSize(ptr) (AllocPointerGetChunk(ptr)->size) -/* - * Private method definitions - */ -/* - * AllocPointerGetAllocElem -- - * Returns allocation (internal) elem given (external) pointer. - */ -#define AllocPointerGetAllocElem(pointer) (&((AllocElem)(pointer))[-1]) -/* - * AllocElemGetAllocPointer -- - * Returns allocation (external) pointer given (internal) elem. +/* ---------- + * AllocSetFreeIndex - + * + * Depending on the size of an allocation compute which freechunk + * list of the alloc set it belongs to. + * ---------- */ -#define AllocElemGetAllocPointer(alloc) ((AllocPointer)&(alloc)[1]) +static inline int +AllocSetFreeIndex(Size size) +{ + int idx = 0; -/* - * AllocElemIsValid -- - * True iff alloc is valid. - */ -#define AllocElemIsValid(alloc) PointerIsValid(alloc) + size = (size - 1) >> 4; + while (size != 0 && idx < 7) + { + idx++; + size >>= 1; + } -/* non-export function prototypes */ -static AllocPointer AllocSetGetFirst(AllocSet set); -static AllocPointer AllocPointerGetNext(AllocPointer pointer); + return idx; +} + /* * Public routines @@ -111,9 +120,10 @@ AllocSetInit(AllocSet set, AllocMode mode, Size limit) * limit is also ignored. This affects this whole file. */ - OrderedSetInit(&set->setData, offsetof(AllocElemData, elemData)); + memset(set, 0, sizeof(AllocSetData)); } + /* * AllocSetReset -- * Frees memory which is allocated in the given set. @@ -124,28 +134,21 @@ AllocSetInit(AllocSet set, AllocMode mode, Size limit) void AllocSetReset(AllocSet set) { - AllocPointer pointer; + AllocBlock block = set->blocks; + AllocBlock next; AssertArg(AllocSetIsValid(set)); - while (AllocPointerIsValid(pointer = AllocSetGetFirst(set))) - AllocSetFree(set, pointer); -} - -#ifdef NOT_USED -void -AllocSetReset_debug(char *file, int line, AllocSet set) -{ - AllocPointer pointer; - - AssertArg(AllocSetIsValid(set)); + while (block != NULL) + { + next = block->next; + free(block); + block = next; + } - while (AllocPointerIsValid(pointer = AllocSetGetFirst(set))) - AllocSetFree(set, pointer); + memset(set, 0, sizeof(AllocSetData)); } -#endif - /* * AllocSetContains -- * True iff allocation set contains given allocation element. @@ -160,8 +163,7 @@ AllocSetContains(AllocSet set, AllocPointer pointer) AssertArg(AllocSetIsValid(set)); AssertArg(AllocPointerIsValid(pointer)); - return (OrderedSetContains(&set->setData, - &AllocPointerGetAllocElem(pointer)->elemData)); + return (AllocPointerGetAset(pointer) == set); } /* @@ -176,23 +178,107 @@ AllocSetContains(AllocSet set, AllocPointer pointer) AllocPointer AllocSetAlloc(AllocSet set, Size size) { - AllocElem alloc; + AllocBlock block; + AllocChunk chunk; + AllocChunk freeref = NULL; + int fidx; + Size chunk_size; AssertArg(AllocSetIsValid(set)); - /* allocate */ - alloc = (AllocElem) malloc(sizeof(*alloc) + size); + /* + * Lookup in the corresponding free list if there is a + * free chunk we could reuse + * + */ + fidx = AllocSetFreeIndex(size); + for (chunk = set->freelist[fidx]; chunk; chunk = (AllocChunk)chunk->aset) + { + if (chunk->size >= size) + break; + freeref = chunk; + } + + /* + * If found, remove it from the free list, make it again + * a member of the alloc set and return it's data address. + * + */ + if (chunk != NULL) + { + if (freeref == NULL) + set->freelist[fidx] = (AllocChunk)chunk->aset; + else + freeref->aset = chunk->aset; - if (!PointerIsValid(alloc)) - elog(FATAL, "palloc failure: memory exhausted"); + chunk->aset = (void *)set; + return AllocChunkGetPointer(chunk); + } - /* add to allocation list */ - OrderedElemPushInto(&alloc->elemData, &set->setData); + /* + * If requested size exceeds smallchunk limit, allocate a separate, + * entire used block for this allocation + * + */ + if (size > ALLOC_CHUNK_LIMIT) + { + Size blksize; + + chunk_size = MAXALIGN(size); + blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ; + block = (AllocBlock) malloc(blksize); + if (block == NULL) + elog(FATAL, "Memory exhausted in AllocSetAlloc()"); + block->aset = set; + block->freeptr = block->endptr = ((char *)block) + ALLOC_BLOCKHDRSZ; + + chunk = (AllocChunk) (((char *)block) + ALLOC_BLOCKHDRSZ); + chunk->aset = set; + chunk->size = chunk_size; + + if (set->blocks != NULL) + { + block->next = set->blocks->next; + set->blocks->next = block; + } + else + { + block->next = NULL; + set->blocks = block; + } + + return AllocChunkGetPointer(chunk); + } - /* set size */ - alloc->size = size; + chunk_size = 16 << fidx; - return AllocElemGetAllocPointer(alloc); + if ((block = set->blocks) != NULL) + { + Size have_free = block->endptr - block->freeptr; + + if (have_free < (chunk_size + ALLOC_CHUNKHDRSZ)) + block = NULL; + } + + if (block == NULL) + { + block = (AllocBlock) malloc(ALLOC_BLOCK_SIZE); + if (block == NULL) + elog(FATAL, "Memory exhausted in AllocSetAlloc()"); + block->aset = set; + block->next = set->blocks; + block->freeptr = ((char *)block) + ALLOC_BLOCKHDRSZ; + block->endptr = ((char *)block) + ALLOC_BLOCK_SIZE; + + set->blocks = block; + } + + chunk = (AllocChunk)(block->freeptr); + chunk->aset = (void *)set; + chunk->size = chunk_size; + block->freeptr += (chunk_size + ALLOC_CHUNKHDRSZ); + + return AllocChunkGetPointer(chunk); } /* @@ -207,19 +293,18 @@ AllocSetAlloc(AllocSet set, Size size) void AllocSetFree(AllocSet set, AllocPointer pointer) { - AllocElem alloc; + int fidx; + AllocChunk chunk; /* AssertArg(AllocSetIsValid(set)); */ /* AssertArg(AllocPointerIsValid(pointer)); */ AssertArg(AllocSetContains(set, pointer)); - alloc = AllocPointerGetAllocElem(pointer); - - /* remove from allocation set */ - OrderedElemPop(&alloc->elemData); + chunk = AllocPointerGetChunk(pointer); + fidx = AllocSetFreeIndex(chunk->size); - /* free storage */ - free(alloc); + chunk->aset = (void *)set->freelist[fidx]; + set->freelist[fidx] = chunk; } /* @@ -238,25 +323,26 @@ AllocPointer AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size) { AllocPointer newPointer; - AllocElem alloc; + Size oldsize; /* AssertArg(AllocSetIsValid(set)); */ /* AssertArg(AllocPointerIsValid(pointer)); */ AssertArg(AllocSetContains(set, pointer)); /* - * Calling realloc(3) directly is not be possible (unless we use our - * own hacked version of malloc) since we must keep the allocations in - * the allocation set. + * Chunk sizes are aligned to power of 2 on AllocSetAlloc(). + * Maybe the allocated area already is >= the new size. + * */ - - alloc = AllocPointerGetAllocElem(pointer); + if (AllocPointerGetSize(pointer) >= size) + return pointer; /* allocate new pointer */ newPointer = AllocSetAlloc(set, size); /* fill new memory */ - memmove(newPointer, pointer, (alloc->size < size) ? alloc->size : size); + oldsize = AllocPointerGetSize(pointer); + memmove(newPointer, pointer, (oldsize < size) ? oldsize : size); /* free old pointer */ AllocSetFree(set, pointer); @@ -265,126 +351,11 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size) } /* - * AllocSetIterate -- - * Returns size of set. Iterates through set elements calling function - * (if valid) on each. - * - * Note: - * This was written as an aid to debugging. It is intended for - * debugging use only. - * - * Exceptions: - * BadArg if set is invalid. - */ -static int -AllocSetIterate(AllocSet set, - void (*function) (AllocPointer pointer)) -{ - int count = 0; - AllocPointer pointer; - - AssertArg(AllocSetIsValid(set)); - - for (pointer = AllocSetGetFirst(set); - AllocPointerIsValid(pointer); - pointer = AllocPointerGetNext(pointer)) - { - - if (PointerIsValid(function)) - (*function) (pointer); - count += 1; - } - - return count; -} - -#ifdef NOT_USED -int -AllocSetCount(AllocSet set) -{ - int count = 0; - AllocPointer pointer; - - AssertArg(AllocSetIsValid(set)); - - for (pointer = AllocSetGetFirst(set); - AllocPointerIsValid(pointer); - pointer = AllocPointerGetNext(pointer)) - count++; - return count; -} - -#endif - -/* - * Private routines - */ - -/* - * AllocSetGetFirst -- - * Returns "first" allocation pointer in a set. - * - * Note: - * Assumes set is valid. - */ -static AllocPointer -AllocSetGetFirst(AllocSet set) -{ - AllocElem alloc; - - alloc = (AllocElem) OrderedSetGetHead(&set->setData); - - if (!AllocElemIsValid(alloc)) - return NULL; - - return AllocElemGetAllocPointer(alloc); -} - -/* - * AllocPointerGetNext -- - * Returns "successor" allocation pointer. - * - * Note: - * Assumes pointer is valid. - */ -static AllocPointer -AllocPointerGetNext(AllocPointer pointer) -{ - AllocElem alloc; - - alloc = (AllocElem) - OrderedElemGetSuccessor(&AllocPointerGetAllocElem(pointer)->elemData); - - if (!AllocElemIsValid(alloc)) - return NULL; - - return AllocElemGetAllocPointer(alloc); -} - - -/* - * Debugging routines - */ - -/* - * XXX AllocPointerDump -- - * Displays allocated pointer. - */ -static void -AllocPointerDump(AllocPointer pointer) -{ - printf("\t%-10ld@ %0#lx\n", ((long *) pointer)[-1], (long) pointer); /* XXX */ -} - -/* * AllocSetDump -- * Displays allocated set. */ void AllocSetDump(AllocSet set) { - int count; - - count = AllocSetIterate(set, AllocPointerDump); - printf("\ttotal %d allocations\n", count); + elog(DEBUG, "Currently unable to dump AllocSet"); } diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index 46c3869785..f0e2ee06f7 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.10 1998/09/01 04:33:36 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.11 1999/02/06 16:50:26 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -103,10 +103,11 @@ static struct MemoryContextMethodsData GlobalContextMethodsData = { */ /* extern bool EqualGlobalMemory(); */ -static struct GlobalMemory TopGlobalMemoryData = { +static struct GlobalMemoryData TopGlobalMemoryData = { T_GlobalMemory, /* NodeTag tag */ &GlobalContextMethodsData, /* ContextMethods method */ - {{0}}, /* uninitialized OrderedSetData allocSetD */ + { NULL, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, + /* free AllocSet */ "TopGlobal", /* char* name */ {0} /* uninitialized OrderedElemData elemD */ }; @@ -162,7 +163,7 @@ EnableMemoryContext(bool on) /* make TopGlobalMemoryData member of ActiveGlobalMemorySet */ OrderedSetInit(ActiveGlobalMemorySet, - offsetof(struct GlobalMemory, elemData)); + offsetof(struct GlobalMemoryData, elemData)); OrderedElemPushInto(&TopGlobalMemoryData.elemData, ActiveGlobalMemorySet); @@ -371,7 +372,7 @@ CreateGlobalMemory(char *name) /* XXX MemoryContextName */ savecxt = MemoryContextSwitchTo(TopMemoryContext); - context = (GlobalMemory) newNode(sizeof(struct GlobalMemory), T_GlobalMemory); + context = (GlobalMemory) newNode(sizeof(struct GlobalMemoryData), T_GlobalMemory); context->method = &GlobalContextMethodsData; context->name = name; /* assumes name is static */ AllocSetInit(&context->setData, DynamicAllocMode, (Size) 0); diff --git a/src/backend/utils/mmgr/palloc.c b/src/backend/utils/mmgr/palloc.c index 9c50c3a302..ad4e506f2f 100644 --- a/src/backend/utils/mmgr/palloc.c +++ b/src/backend/utils/mmgr/palloc.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/palloc.c,v 1.9 1999/01/17 03:04:54 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/palloc.c,v 1.10 1999/02/06 16:50:27 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -22,98 +22,26 @@ #include "nodes/memnodes.h" -#include "utils/palloc.h" /* ---------------------------------------------------------------- * User library functions * ---------------------------------------------------------------- */ -#undef palloc -#undef pfree -#undef MemoryContextAlloc -#undef MemoryContextFree -#undef malloc -#undef free - -/* define PALLOC_IS_MALLOC if you want palloc to go straight to the - raw malloc, without concern for the extra bookkeeping needed to - ensure garbage is collected at the end of transactions - jolly 1/12/94 */ - - -/* - * palloc -- - * Returns pointer to aligned memory of specified size. - * - * Exceptions: - * BadArgument if size < 1 or size >= MaxAllocSize. - * ExhaustedMemory if allocation fails. - * NonallocatedPointer if pointer was not returned by palloc or repalloc - * or may have been freed already. - * - * pfree -- - * Frees memory associated with pointer returned from palloc or repalloc. - * - * Exceptions: - * BadArgument if pointer is invalid. - * FreeInWrongContext if pointer was allocated in a different "context." - * NonallocatedPointer if pointer was not returned by palloc or repalloc - * or may have been subsequently freed. +/* ---------- + * palloc(), pfree() and repalloc() are now macros in palloc.h + * ---------- */ -void * -palloc(Size size) -{ -#ifdef PALLOC_IS_MALLOC - return malloc(size); -#else - return MemoryContextAlloc(CurrentMemoryContext, size); -#endif /* PALLOC_IS_MALLOC */ -} -void -pfree(void *pointer) -{ -#ifdef PALLOC_IS_MALLOC - free(pointer); -#else - MemoryContextFree(CurrentMemoryContext, pointer); -#endif /* PALLOC_IS_MALLOC */ -} - -/* - * repalloc -- - * Returns pointer to aligned memory of specified size. - * - * Side effects: - * The returned memory is first filled with the contents of *pointer - * up to the minimum of size and psize(pointer). Pointer is freed. - * - * Exceptions: - * BadArgument if pointer is invalid or size < 1 or size >= MaxAllocSize. - * ExhaustedMemory if allocation fails. - * NonallocatedPointer if pointer was not returned by palloc or repalloc - * or may have been freed already. - */ -void * -repalloc(void *pointer, Size size) -{ -#ifdef PALLOC_IS_MALLOC - return realloc(pointer, size); -#else - return MemoryContextRealloc(CurrentMemoryContext, pointer, size); -#endif -} - -/* pstrdup - allocates space for and copies a string - just like strdup except it uses palloc instead of malloc */ char * pstrdup(char *string) { - char *nstr; + char *nstr; + int len; - nstr = (char *) palloc(strlen(string) + 1); - strcpy(nstr, string); + nstr = palloc(len = strlen(string) + 1); + MemoryCopy(nstr, string, len); return nstr; } + diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index c6c31bc181..1aa456b943 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.16 1999/02/03 21:17:40 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.17 1999/02/06 16:50:28 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -812,6 +812,25 @@ PortalDestroy(Portal *portalP) (Pointer) portal->name); AllocSetReset(&portal->variable.setData); /* XXX log */ + /* + * In the case of a transaction abort it is possible that + * we get called while one of the memory contexts of the portal + * we're destroying is the current memory context. + * + * Don't know how to handle that cleanly because it is required + * to be in that context right now. This portal struct remains + * allocated in the PortalMemory context until backend dies. + * + * Not happy with that, but it's better to loose some bytes of + * memory than to have the backend dump core. + * + * --- Feb. 04, 1999 Jan Wieck + */ + if (CurrentMemoryContext == (MemoryContext)PortalGetHeapMemory(portal)) + return; + if (CurrentMemoryContext == (MemoryContext)PortalGetVariableMemory(portal)) + return; + if (portal != BlankPortal) MemoryContextFree((MemoryContext) PortalMemory, (Pointer) portal); } |
