#include "postgres.h"#include "utils/memutils.h"
Go to the source code of this file.
Data Structures | |
| struct | AllocSetContext |
| struct | AllocBlockData |
| struct | AllocChunkData |
Defines | |
| #define | ALLOC_MINBITS 3 |
| #define | ALLOCSET_NUM_FREELISTS 11 |
| #define | ALLOC_CHUNK_LIMIT (1 << (ALLOCSET_NUM_FREELISTS-1+ALLOC_MINBITS)) |
| #define | ALLOC_CHUNK_FRACTION 4 |
| #define | ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData)) |
| #define | ALLOC_CHUNKHDRSZ MAXALIGN(sizeof(AllocChunkData)) |
| #define | AllocPointerIsValid(pointer) PointerIsValid(pointer) |
| #define | AllocSetIsValid(set) PointerIsValid(set) |
| #define | AllocPointerGetChunk(ptr) ((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ)) |
| #define | AllocChunkGetPointer(chk) ((AllocPointer)(((char *)(chk)) + ALLOC_CHUNKHDRSZ)) |
| #define | LT16(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n |
| #define | AllocFreeInfo(_cxt, _chunk) |
| #define | AllocAllocInfo(_cxt, _chunk) |
Typedefs | |
| typedef struct AllocBlockData * | AllocBlock |
| typedef struct AllocChunkData * | AllocChunk |
| typedef void * | AllocPointer |
| typedef struct AllocSetContext | AllocSetContext |
| typedef AllocSetContext * | AllocSet |
| typedef struct AllocBlockData | AllocBlockData |
| typedef struct AllocChunkData | AllocChunkData |
Functions | |
| 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, int level) |
| static int | AllocSetFreeIndex (Size size) |
| MemoryContext | AllocSetContextCreate (MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize) |
Variables | |
| static MemoryContextMethods | AllocSetMethods |
| static const unsigned char | LogTable256 [256] |
| #define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData)) |
Definition at line 116 of file aset.c.
Referenced by AllocSetAlloc(), AllocSetContextCreate(), AllocSetFree(), and AllocSetRealloc().
| #define ALLOC_CHUNK_FRACTION 4 |
Definition at line 102 of file aset.c.
Referenced by AllocSetContextCreate().
| #define ALLOC_CHUNK_LIMIT (1 << (ALLOCSET_NUM_FREELISTS-1+ALLOC_MINBITS)) |
| #define ALLOC_CHUNKHDRSZ MAXALIGN(sizeof(AllocChunkData)) |
Definition at line 117 of file aset.c.
Referenced by AllocSetAlloc(), AllocSetContextCreate(), AllocSetFree(), and AllocSetRealloc().
| #define ALLOC_MINBITS 3 |
Definition at line 98 of file aset.c.
Referenced by AllocSetAlloc(), and AllocSetFreeIndex().
| #define AllocAllocInfo | ( | _cxt, | ||
| _chunk | ||||
| ) |
Definition at line 269 of file aset.c.
Referenced by AllocSetAlloc().
| #define AllocChunkGetPointer | ( | chk | ) | ((AllocPointer)(((char *)(chk)) + ALLOC_CHUNKHDRSZ)) |
Definition at line 206 of file aset.c.
Referenced by AllocSetAlloc(), and AllocSetRealloc().
| #define AllocFreeInfo | ( | _cxt, | ||
| _chunk | ||||
| ) |
Definition at line 268 of file aset.c.
Referenced by AllocSetFree().
| #define AllocPointerGetChunk | ( | ptr | ) | ((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ)) |
Definition at line 204 of file aset.c.
Referenced by AllocSetFree(), AllocSetGetChunkSpace(), and AllocSetRealloc().
| #define AllocPointerIsValid | ( | pointer | ) | PointerIsValid(pointer) |
| #define ALLOCSET_NUM_FREELISTS 11 |
Definition at line 99 of file aset.c.
Referenced by AllocSetFreeIndex().
| #define AllocSetIsValid | ( | set | ) | PointerIsValid(set) |
Definition at line 202 of file aset.c.
Referenced by AllocSetAlloc(), AllocSetDelete(), and AllocSetReset().
| #define LT16 | ( | n | ) | n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n |
| typedef struct AllocBlockData* AllocBlock |
| typedef struct AllocBlockData AllocBlockData |
| typedef struct AllocChunkData* AllocChunk |
| typedef struct AllocChunkData AllocChunkData |
| typedef void* AllocPointer |
| typedef AllocSetContext* AllocSet |
| typedef struct AllocSetContext AllocSetContext |
| static void * AllocSetAlloc | ( | MemoryContext | context, | |
| Size | size | |||
| ) | [static] |
Definition at line 562 of file aset.c.
References ALLOC_BLOCKHDRSZ, ALLOC_CHUNKHDRSZ, ALLOC_MINBITS, AllocAllocInfo, AllocChunkGetPointer, AllocSetFreeIndex(), AllocSetIsValid, AllocChunkData::aset, AllocBlockData::aset, Assert, AssertArg, AllocBlockData::endptr, ereport, errcode(), errdetail(), errmsg(), ERROR, AllocBlockData::freeptr, malloc, MAXALIGN, MemoryContextStats(), AllocBlockData::next, NULL, AllocChunkData::size, and TopMemoryContext.
Referenced by AllocSetRealloc().
{
AllocSet set = (AllocSet) context;
AllocBlock block;
AllocChunk chunk;
int fidx;
Size chunk_size;
Size blksize;
AssertArg(AllocSetIsValid(set));
/*
* If requested size exceeds maximum for chunks, allocate an entire block
* for this request.
*/
if (size > set->allocChunkLimit)
{
chunk_size = MAXALIGN(size);
blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
block = (AllocBlock) malloc(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->aset = set;
block->freeptr = block->endptr = ((char *) block) + blksize;
chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
chunk->aset = set;
chunk->size = chunk_size;
#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
#ifdef RANDOMIZE_ALLOCATED_MEMORY
/* fill the allocated space with junk */
randomize_mem((char *) AllocChunkGetPointer(chunk), size);
#endif
/*
* Stick the new block underneath the active allocation block, so that
* we don't lose the use of the space remaining therein.
*/
if (set->blocks != NULL)
{
block->next = set->blocks->next;
set->blocks->next = block;
}
else
{
block->next = NULL;
set->blocks = block;
}
AllocAllocInfo(set, chunk);
return AllocChunkGetPointer(chunk);
}
/*
* Request is small enough to be treated as a chunk. Look in the
* corresponding free list to see if there is a free chunk we could reuse.
* If one is found, remove it from the free list, make it again a member
* of the alloc set and return its data address.
*/
fidx = AllocSetFreeIndex(size);
chunk = set->freelist[fidx];
if (chunk != NULL)
{
Assert(chunk->size >= size);
set->freelist[fidx] = (AllocChunk) chunk->aset;
chunk->aset = (void *) set;
#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
#ifdef RANDOMIZE_ALLOCATED_MEMORY
/* fill the allocated space with junk */
randomize_mem((char *) AllocChunkGetPointer(chunk), size);
#endif
AllocAllocInfo(set, chunk);
return AllocChunkGetPointer(chunk);
}
/*
* Choose the actual chunk size to allocate.
*/
chunk_size = (1 << ALLOC_MINBITS) << fidx;
Assert(chunk_size >= size);
/*
* If there is enough room in the active allocation block, we will put the
* chunk into that block. Else must start a new one.
*/
if ((block = set->blocks) != NULL)
{
Size availspace = block->endptr - block->freeptr;
if (availspace < (chunk_size + ALLOC_CHUNKHDRSZ))
{
/*
* The existing active (top) block does not have enough room for
* the requested allocation, but it might still have a useful
* amount of space in it. Once we push it down in the block list,
* we'll never try to allocate more space from it. So, before we
* do that, carve up its free space into chunks that we can put on
* the set's freelists.
*
* Because we can only get here when there's less than
* ALLOC_CHUNK_LIMIT left in the block, this loop cannot iterate
* more than ALLOCSET_NUM_FREELISTS-1 times.
*/
while (availspace >= ((1 << ALLOC_MINBITS) + ALLOC_CHUNKHDRSZ))
{
Size availchunk = availspace - ALLOC_CHUNKHDRSZ;
int a_fidx = AllocSetFreeIndex(availchunk);
/*
* In most cases, we'll get back the index of the next larger
* freelist than the one we need to put this chunk on. The
* exception is when availchunk is exactly a power of 2.
*/
if (availchunk != ((Size) 1 << (a_fidx + ALLOC_MINBITS)))
{
a_fidx--;
Assert(a_fidx >= 0);
availchunk = ((Size) 1 << (a_fidx + ALLOC_MINBITS));
}
chunk = (AllocChunk) (block->freeptr);
block->freeptr += (availchunk + ALLOC_CHUNKHDRSZ);
availspace -= (availchunk + ALLOC_CHUNKHDRSZ);
chunk->size = availchunk;
#ifdef MEMORY_CONTEXT_CHECKING
chunk->requested_size = 0; /* mark it free */
#endif
chunk->aset = (void *) set->freelist[a_fidx];
set->freelist[a_fidx] = chunk;
}
/* Mark that we need to create a new block */
block = NULL;
}
}
/*
* Time to create a new regular (multi-chunk) block?
*/
if (block == NULL)
{
Size required_size;
/*
* The first such block has size initBlockSize, and we double the
* space in each succeeding block, but not more than maxBlockSize.
*/
blksize = set->nextBlockSize;
set->nextBlockSize <<= 1;
if (set->nextBlockSize > set->maxBlockSize)
set->nextBlockSize = set->maxBlockSize;
/*
* If initBlockSize is less than ALLOC_CHUNK_LIMIT, we could need more
* space... but try to keep it a power of 2.
*/
required_size = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
while (blksize < required_size)
blksize <<= 1;
/* Try to allocate it */
block = (AllocBlock) malloc(blksize);
/*
* We could be asking for pretty big blocks here, so cope if malloc
* fails. But give up if there's less than a meg or so available...
*/
while (block == NULL && blksize > 1024 * 1024)
{
blksize >>= 1;
if (blksize < required_size)
break;
block = (AllocBlock) malloc(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->aset = set;
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
block->endptr = ((char *) block) + blksize;
/*
* If this is the first block of the set, make it the "keeper" block.
* Formerly, a keeper block could only be created during context
* creation, but allowing it to happen here lets us have fast reset
* cycling even for contexts created with minContextSize = 0; that way
* we don't have to force space to be allocated in contexts that might
* never need any space. Don't mark an oversize block as a keeper,
* however.
*/
if (set->keeper == NULL && blksize == set->initBlockSize)
set->keeper = block;
block->next = set->blocks;
set->blocks = block;
}
/*
* OK, do the allocation
*/
chunk = (AllocChunk) (block->freeptr);
block->freeptr += (chunk_size + ALLOC_CHUNKHDRSZ);
Assert(block->freeptr <= block->endptr);
chunk->aset = (void *) set;
chunk->size = chunk_size;
#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
#ifdef RANDOMIZE_ALLOCATED_MEMORY
/* fill the allocated space with junk */
randomize_mem((char *) AllocChunkGetPointer(chunk), size);
#endif
AllocAllocInfo(set, chunk);
return AllocChunkGetPointer(chunk);
}
| MemoryContext AllocSetContextCreate | ( | MemoryContext | parent, | |
| const char * | name, | |||
| Size | minContextSize, | |||
| Size | initBlockSize, | |||
| Size | maxBlockSize | |||
| ) |
Definition at line 353 of file aset.c.
References ALLOC_BLOCKHDRSZ, ALLOC_CHUNK_FRACTION, ALLOC_CHUNKHDRSZ, AllocSetContext::allocChunkLimit, AllocBlockData::aset, AllocSetContext::blocks, AllocBlockData::endptr, ereport, errcode(), errdetail(), errmsg(), ERROR, AllocBlockData::freeptr, AllocSetContext::initBlockSize, AllocSetContext::keeper, malloc, MAXALIGN, AllocSetContext::maxBlockSize, MemoryContextCreate(), MemoryContextStats(), AllocBlockData::next, AllocSetContext::nextBlockSize, NULL, T_AllocSetContext, and TopMemoryContext.
Referenced by _bt_preprocess_array_keys(), _SPI_make_plan_non_temp(), _SPI_save_plan(), accumArrayResult(), afterTriggerAddEvent(), afterTriggerInvokeEvents(), AtStart_Memory(), AtSubStart_Memory(), AutoVacLauncherMain(), BackgroundWriterMain(), begin_heap_rewrite(), BeginCopy(), btvacuumscan(), BuildCachedPlan(), BuildEventTriggerCache(), CheckpointerMain(), cluster(), CompleteCachedPlan(), compute_index_stats(), CopyCachedPlan(), CopyTo(), CreateCachedPlan(), CreateCacheMemoryContext(), CreateExecutorState(), CreateExprContext(), CreatePortal(), CreateStandaloneExprContext(), createTempGistContext(), createTrgmNFA(), do_analyze_rel(), do_autovacuum(), do_compile(), do_start_worker(), each_worker(), EnablePortalManager(), EventTriggerBeginCompleteQuery(), EventTriggerInvoke(), exec_parse_message(), exec_replication_command(), ExecHashTableCreate(), ExecInitAgg(), ExecInitRecursiveUnion(), ExecInitSetOp(), ExecInitSubPlan(), ExecInitUnique(), ExecInitWindowAgg(), file_acquire_sample_rows(), geqo_eval(), GetLocalBufferStorage(), gin_xlog_startup(), ginbeginscan(), ginbuild(), gininsert(), ginInsertCleanup(), gistrescan(), hash_create(), index_register(), init_MultiFuncCall(), init_sql_fcache(), initGISTstate(), inline_function(), inline_set_returning_function(), json_array_elements(), load_hba(), load_ident(), load_relcache_init_file(), load_tzoffsets(), lookup_ts_dictionary_cache(), mdinit(), MemoryContextInit(), mXactCachePut(), NIStartBuild(), pgstat_setup_memcxt(), plperl_return_next(), plperl_spi_prepare(), plpgsql_compile_inline(), PLy_push_execution_context(), PortalCreateHoldStore(), postgresAcquireSampleRowsFunc(), postgresBeginForeignModify(), postgresBeginForeignScan(), PostgresMain(), PostmasterMain(), rebuild_database_list(), ReindexDatabase(), RelationBuildRuleLock(), RelationInitIndexAccessInfo(), ResetUnloggedRelations(), RevalidateCachedQuery(), sepgsql_avc_init(), spg_xlog_startup(), spgbeginscan(), spgbuild(), spginsert(), SPI_connect(), spi_dest_startup(), storeRow(), tokenize_file(), tuplesort_begin_common(), vacuum(), and WalWriterMain().
{
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;
context->nextBlockSize = initBlockSize;
/*
* Compute the allocation chunk size limit for this context. It can't be
* more than ALLOC_CHUNK_LIMIT because of the fixed number of freelists.
* If maxBlockSize is small then requests exceeding the maxBlockSize, or
* even a significant fraction of it, should be treated as large chunks
* too. For the typical case of maxBlockSize a power of 2, the chunk size
* limit will be at most 1/8th maxBlockSize, so that given a stream of
* requests that are all the maximum chunk size we will waste at most
* 1/8th of the allocated space.
*
* We have to have allocChunkLimit a power of two, because the requested
* and actually-allocated sizes of any chunk must be on the same side of
* the limit, else we get confused about whether the chunk is "big".
*/
context->allocChunkLimit = ALLOC_CHUNK_LIMIT;
while ((Size) (context->allocChunkLimit + ALLOC_CHUNKHDRSZ) >
(Size) ((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION))
context->allocChunkLimit >>= 1;
/*
* 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;
}
return (MemoryContext) context;
}
| static void AllocSetDelete | ( | MemoryContext | context | ) | [static] |
Definition at line 526 of file aset.c.
References AllocSetIsValid, AssertArg, free, AllocBlockData::freeptr, MemSetAligned, AllocBlockData::next, next(), and NULL.
{
AllocSet set = (AllocSet) context;
AllocBlock block = set->blocks;
AssertArg(AllocSetIsValid(set));
#ifdef MEMORY_CONTEXT_CHECKING
/* Check for corruption and leaks before freeing */
AllocSetCheck(context);
#endif
/* Make it look empty, just in case... */
MemSetAligned(set->freelist, 0, sizeof(set->freelist));
set->blocks = NULL;
set->keeper = NULL;
while (block != NULL)
{
AllocBlock next = block->next;
#ifdef CLOBBER_FREED_MEMORY
/* Wipe freed memory for debugging purposes */
memset(block, 0x7F, block->freeptr - ((char *) block));
#endif
free(block);
block = next;
}
}
| static void AllocSetFree | ( | MemoryContext | context, | |
| void * | pointer | |||
| ) | [static] |
Definition at line 820 of file aset.c.
References ALLOC_BLOCKHDRSZ, ALLOC_CHUNKHDRSZ, AllocFreeInfo, AllocPointerGetChunk, AllocSetFreeIndex(), AllocChunkData::aset, Assert, elog, ERROR, free, AllocBlockData::freeptr, AllocBlockData::next, NULL, AllocChunkData::size, and WARNING.
Referenced by AllocSetRealloc().
{
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;
}
}
| static int AllocSetFreeIndex | ( | Size | size | ) | [inline, static] |
Definition at line 281 of file aset.c.
References ALLOC_MINBITS, ALLOCSET_NUM_FREELISTS, Assert, and LogTable256.
Referenced by AllocSetAlloc(), and AllocSetFree().
{
int idx;
unsigned int t,
tsize;
if (size > (1 << ALLOC_MINBITS))
{
tsize = (size - 1) >> ALLOC_MINBITS;
/*
* At this point we need to obtain log2(tsize)+1, ie, the number of
* not-all-zero bits at the right. We used to do this with a
* shift-and-count loop, but this function is enough of a hotspot to
* justify micro-optimization effort. The best approach seems to be
* to use a lookup table. Note that this code assumes that
* ALLOCSET_NUM_FREELISTS <= 17, since we only cope with two bytes of
* the tsize value.
*/
t = tsize >> 8;
idx = t ? LogTable256[t] + 8 : LogTable256[tsize];
Assert(idx < ALLOCSET_NUM_FREELISTS);
}
else
idx = 0;
return idx;
}
| static Size AllocSetGetChunkSpace | ( | MemoryContext | context, | |
| void * | pointer | |||
| ) | [static] |
Definition at line 1029 of file aset.c.
References AllocPointerGetChunk, and AllocChunkData::size.
{
AllocChunk chunk = AllocPointerGetChunk(pointer);
return chunk->size + ALLOC_CHUNKHDRSZ;
}
| static void AllocSetInit | ( | MemoryContext | context | ) | [static] |
| static bool AllocSetIsEmpty | ( | MemoryContext | context | ) | [static] |
Definition at line 1041 of file aset.c.
References MemoryContextData::isReset.
{
/*
* 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 (context->isReset)
return true;
return false;
}
| static void * AllocSetRealloc | ( | MemoryContext | context, | |
| void * | pointer, | |||
| Size | size | |||
| ) | [static] |
Definition at line 895 of file aset.c.
References ALLOC_BLOCKHDRSZ, ALLOC_CHUNKHDRSZ, AllocChunkGetPointer, AllocPointerGetChunk, AllocSetAlloc(), AllocSetFree(), Assert, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, AllocBlockData::freeptr, MAXALIGN, MemoryContextStats(), AllocBlockData::next, NULL, realloc, AllocChunkData::size, TopMemoryContext, and WARNING.
{
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
/*
* 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
#ifdef RANDOMIZE_ALLOCATED_MEMORY
/* We can only fill the extra space if we know the prior request */
if (size > chunk->requested_size)
randomize_mem((char *) AllocChunkGetPointer(chunk) + chunk->requested_size,
size - chunk->requested_size);
#endif
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
#ifdef RANDOMIZE_ALLOCATED_MEMORY
/* We can only fill the extra space if we know the prior request */
randomize_mem((char *) AllocChunkGetPointer(chunk) + chunk->requested_size,
size - chunk->requested_size);
#endif
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;
}
}
| static void AllocSetReset | ( | MemoryContext | context | ) | [static] |
Definition at line 465 of file aset.c.
References AllocSetIsValid, AssertArg, free, AllocBlockData::freeptr, MemSetAligned, AllocBlockData::next, next(), and NULL.
{
AllocSet set = (AllocSet) context;
AllocBlock block;
AssertArg(AllocSetIsValid(set));
#ifdef MEMORY_CONTEXT_CHECKING
/* Check for corruption and leaks before freeing */
AllocSetCheck(context);
#endif
/* Clear chunk freelists */
MemSetAligned(set->freelist, 0, sizeof(set->freelist));
block = set->blocks;
/* New blocks list is either empty or just the keeper block */
set->blocks = set->keeper;
while (block != NULL)
{
AllocBlock next = block->next;
if (block == set->keeper)
{
/* Reset the block, but don't return it to malloc */
char *datastart = ((char *) block) + ALLOC_BLOCKHDRSZ;
#ifdef CLOBBER_FREED_MEMORY
/* Wipe freed memory for debugging purposes */
memset(datastart, 0x7F, block->freeptr - datastart);
#endif
block->freeptr = datastart;
block->next = NULL;
}
else
{
/* Normal case, release the block */
#ifdef CLOBBER_FREED_MEMORY
/* Wipe freed memory for debugging purposes */
memset(block, 0x7F, block->freeptr - ((char *) block));
#endif
free(block);
}
block = next;
}
/* Reset block size allocation sequence, too */
set->nextBlockSize = set->initBlockSize;
}
| static void AllocSetStats | ( | MemoryContext | context, | |
| int | level | |||
| ) | [static] |
Definition at line 1059 of file aset.c.
References AllocChunkData::aset, AllocBlockData::endptr, AllocBlockData::freeptr, i, AllocBlockData::next, NULL, and AllocChunkData::size.
{
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);
}
MemoryContextMethods AllocSetMethods [static] |
{
AllocSetAlloc,
AllocSetFree,
AllocSetRealloc,
AllocSetInit,
AllocSetReset,
AllocSetDelete,
AllocSetGetChunkSpace,
AllocSetIsEmpty,
AllocSetStats
}
const unsigned char LogTable256[256] [static] |
1.7.1