diff options
Diffstat (limited to 'src/backend/utils/mmgr/aset.c')
-rw-r--r-- | src/backend/utils/mmgr/aset.c | 367 |
1 files changed, 169 insertions, 198 deletions
diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index 008c629e5c6..15b5094881e 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"); } |