diff options
Diffstat (limited to 'src/backend/utils/mmgr/slab.c')
-rw-r--r-- | src/backend/utils/mmgr/slab.c | 102 |
1 files changed, 61 insertions, 41 deletions
diff --git a/src/backend/utils/mmgr/slab.c b/src/backend/utils/mmgr/slab.c index ee2175278d2..c01c77913a8 100644 --- a/src/backend/utils/mmgr/slab.c +++ b/src/backend/utils/mmgr/slab.c @@ -67,6 +67,7 @@ typedef struct SlabContext Size chunkSize; /* chunk size */ Size fullChunkSize; /* chunk size including header and alignment */ Size blockSize; /* block size */ + Size headerSize; /* allocated size of context header */ int chunksPerBlock; /* number of chunks per block */ int minFreeChunks; /* min number of free chunks in any block */ int nblocks; /* number of blocks allocated */ @@ -126,7 +127,6 @@ typedef struct SlabChunk static void *SlabAlloc(MemoryContext context, Size size); static void SlabFree(MemoryContext context, void *pointer); static void *SlabRealloc(MemoryContext context, void *pointer, Size size); -static void SlabInit(MemoryContext context); static void SlabReset(MemoryContext context); static void SlabDelete(MemoryContext context); static Size SlabGetChunkSpace(MemoryContext context, void *pointer); @@ -140,11 +140,10 @@ static void SlabCheck(MemoryContext context); /* * This is the virtual function table for Slab contexts. */ -static MemoryContextMethods SlabMethods = { +static const MemoryContextMethods SlabMethods = { SlabAlloc, SlabFree, SlabRealloc, - SlabInit, SlabReset, SlabDelete, SlabGetChunkSpace, @@ -177,24 +176,30 @@ static MemoryContextMethods SlabMethods = { * Create a new Slab context. * * parent: parent context, or NULL if top-level context - * name: name of context (for debugging --- string will be copied) + * name: name of context (for debugging only, need not be unique) + * flags: bitmask of MEMCONTEXT_XXX option flags * blockSize: allocation block size * chunkSize: allocation chunk size * + * Notes: if flags & MEMCONTEXT_COPY_NAME, the name string will be copied into + * context-lifespan storage; otherwise, it had better be statically allocated. * The chunkSize may not exceed: * MAXALIGN_DOWN(SIZE_MAX) - MAXALIGN(sizeof(SlabBlock)) - SLAB_CHUNKHDRSZ - * */ MemoryContext SlabContextCreate(MemoryContext parent, const char *name, + int flags, Size blockSize, Size chunkSize) { int chunksPerBlock; Size fullChunkSize; Size freelistSize; + Size nameOffset; + Size headerSize; SlabContext *slab; + int i; /* Assert we padded SlabChunk properly */ StaticAssertStmt(sizeof(SlabChunk) == MAXALIGN(sizeof(SlabChunk)), @@ -211,7 +216,7 @@ SlabContextCreate(MemoryContext parent, fullChunkSize = sizeof(SlabChunk) + MAXALIGN(chunkSize); /* Make sure the block can store at least one chunk. */ - if (blockSize - sizeof(SlabBlock) < fullChunkSize) + if (blockSize < fullChunkSize + sizeof(SlabBlock)) elog(ERROR, "block size %zu for slab is too small for %zu chunks", blockSize, chunkSize); @@ -221,45 +226,58 @@ SlabContextCreate(MemoryContext parent, /* The freelist starts with 0, ends with chunksPerBlock. */ freelistSize = sizeof(dlist_head) * (chunksPerBlock + 1); - /* if we can't fit at least one chunk into the block, we're hosed */ - Assert(chunksPerBlock > 0); + /* + * Allocate the context header. Unlike aset.c, we never try to combine + * this with the first regular block; not worth the extra complication. + */ - /* make sure the chunks actually fit on the block */ - Assert((fullChunkSize * chunksPerBlock) + sizeof(SlabBlock) <= blockSize); + /* Size of the memory context header, including name storage if needed */ + nameOffset = offsetof(SlabContext, freelist) + freelistSize; + if (flags & MEMCONTEXT_COPY_NAME) + headerSize = nameOffset + strlen(name) + 1; + else + headerSize = nameOffset; - /* Do the type-independent part of context creation */ - slab = (SlabContext *) - MemoryContextCreate(T_SlabContext, - (offsetof(SlabContext, freelist) + freelistSize), - &SlabMethods, - parent, - name); + slab = (SlabContext *) malloc(headerSize); + if (slab == NULL) + { + MemoryContextStats(TopMemoryContext); + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"), + errdetail("Failed while creating memory context \"%s\".", + name))); + } - slab->blockSize = blockSize; + /* + * Avoid writing code that can fail between here and MemoryContextCreate; + * we'd leak the header if we ereport in this stretch. + */ + + /* Fill in SlabContext-specific header fields */ slab->chunkSize = chunkSize; slab->fullChunkSize = fullChunkSize; + slab->blockSize = blockSize; + slab->headerSize = headerSize; slab->chunksPerBlock = chunksPerBlock; - slab->nblocks = 0; slab->minFreeChunks = 0; - - return (MemoryContext) slab; -} - -/* - * SlabInit - * Context-type-specific initialization routine. - */ -static void -SlabInit(MemoryContext context) -{ - int i; - SlabContext *slab = castNode(SlabContext, context); - - Assert(slab); + slab->nblocks = 0; /* initialize the freelist slots */ for (i = 0; i < (slab->chunksPerBlock + 1); i++) dlist_init(&slab->freelist[i]); + + /* Finally, do the type-independent part of context creation */ + MemoryContextCreate((MemoryContext) slab, + T_SlabContext, + headerSize, + nameOffset, + &SlabMethods, + parent, + name, + flags); + + return (MemoryContext) slab; } /* @@ -308,14 +326,15 @@ SlabReset(MemoryContext context) /* * SlabDelete - * Frees all memory which is allocated in the given slab, in preparation - * for deletion of the slab. We simply call SlabReset(). + * Free all memory which is allocated in the given context. */ static void SlabDelete(MemoryContext context) { - /* just reset the context */ + /* Reset to release all the SlabBlocks */ SlabReset(context); + /* And free the context header */ + free(context); } /* @@ -613,7 +632,7 @@ SlabIsEmpty(MemoryContext context) /* * SlabStats - * Compute stats about memory consumption of an Slab. + * Compute stats about memory consumption of a Slab context. * * level: recursion level (0 at top level); used for print indentation. * print: true to print stats to stderr. @@ -626,11 +645,12 @@ SlabStats(MemoryContext context, int level, bool print, SlabContext *slab = castNode(SlabContext, context); Size nblocks = 0; Size freechunks = 0; - Size totalspace = 0; + Size totalspace; Size freespace = 0; int i; - Assert(slab); + /* Include context header in totalspace */ + totalspace = slab->headerSize; for (i = 0; i <= slab->chunksPerBlock; i++) { @@ -682,7 +702,7 @@ SlabCheck(MemoryContext context) { int i; SlabContext *slab = castNode(SlabContext, context); - char *name = slab->header.name; + const char *name = slab->header.name; char *freechunks; Assert(slab); |