Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Functions | Variables

aset.c File Reference

#include "postgres.h"
#include "utils/memutils.h"
Include dependency graph for aset.c:

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 AllocBlockDataAllocBlock
typedef struct AllocChunkDataAllocChunk
typedef void * AllocPointer
typedef struct AllocSetContext AllocSetContext
typedef AllocSetContextAllocSet
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 Documentation

#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))

Definition at line 100 of file aset.c.

#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)

Definition at line 196 of file aset.c.

#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

Definition at line 247 of file aset.c.


Typedef Documentation

typedef struct AllocBlockData* AllocBlock

Definition at line 119 of file aset.c.

typedef struct AllocChunkData* AllocChunk

Definition at line 120 of file aset.c.

typedef void* AllocPointer

Definition at line 126 of file aset.c.

Definition at line 151 of file aset.c.


Function Documentation

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]

Definition at line 445 of file aset.c.

{
    /*
     * Since MemoryContextCreate already zeroed the context node, we don't
     * have to do anything here: it's already OK.
     */
}

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);
}


Variable Documentation

Initial value:
 {
    AllocSetAlloc,
    AllocSetFree,
    AllocSetRealloc,
    AllocSetInit,
    AllocSetReset,
    AllocSetDelete,
    AllocSetGetChunkSpace,
    AllocSetIsEmpty,
    AllocSetStats



}

Definition at line 229 of file aset.c.

const unsigned char LogTable256[256] [static]
Initial value:
{
    0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
    LT16(5), LT16(6), LT16(6), LT16(7), LT16(7), LT16(7), LT16(7),
    LT16(8), LT16(8), LT16(8), LT16(8), LT16(8), LT16(8), LT16(8), LT16(8)
}

Definition at line 249 of file aset.c.

Referenced by AllocSetFreeIndex().