blob: b53da378fdbaf3362ac54d5118cd03b09b6a1dea [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*-------------------------------------------------------------------------
*
* mpool.c
* Fast memory pool to manage lots of variable sizes of objects. This pool
* does not support free individual objects, but you can release all
* objects as a whole.
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "utils/memutils.h"
#define PRINT(x) elog x
#undef PRINT
#define PRINT(x)
#define MPOOL_BLOCK_SIZE (64 * 1024)
struct MPool
{
MemoryContextData *parent;
MemoryContextData *context;
/*
* Total number of bytes are allocated through the memory
* context.
*/
uint64 total_bytes_allocated;
/* How many bytes are used by the caller. */
uint64 bytes_used;
/*
* When a new allocation request arrives, and the current block
* does not have enough space for this request, we waste those
* several bytes at the end of the block. This variable stores
* total number of these wasted bytes.
*/
uint64 bytes_wasted;
/* The latest allocated block of available space. */
void *start;
void *end;
};
static void
mpool_init(MPool *mpool)
{
Assert(mpool != NULL);
mpool->total_bytes_allocated = 0;
mpool->bytes_used = 0;
mpool->bytes_wasted = 0;
mpool->start = NULL;
mpool->end = NULL;
}
/*
* Create a MPool object and initialize its variables.
*/
MPool *
mpool_create(MemoryContext parent,
const char *name)
{
MPool *mpool = MemoryContextAlloc(parent, sizeof(MPool));
Assert(parent != NULL);
mpool->parent = parent;
mpool->context = AllocSetContextCreate(parent,
name,
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
mpool_init(mpool);
return mpool;
}
/*
* Return a pointer to a space with the given 'size'.
*/
void *
mpool_alloc(MPool *mpool, Size size)
{
void *alloc_space;
size = MAXALIGN(size);
if (mpool->start == NULL ||
(char *)mpool->end - (char *)mpool->start < size)
{
Size alloc_size;
if (mpool->start != NULL)
{
Assert(mpool->end != NULL);
mpool->bytes_wasted = (char *)mpool->end - (char *)mpool->start;
}
alloc_size = MPOOL_BLOCK_SIZE;
if (size > MPOOL_BLOCK_SIZE)
alloc_size = size;
mpool->start = MemoryContextAlloc(mpool->context, alloc_size);
mpool->end = (char *)mpool->start + alloc_size;
mpool->total_bytes_allocated += alloc_size;
}
Assert(mpool->start != NULL && mpool->end != NULL &&
(char *)mpool->end - (char *)mpool->start >= size);
alloc_space = mpool->start;
mpool->start = (char *)mpool->start + size;
Assert(mpool->start <= mpool->end);
mpool->bytes_used += size;
return alloc_space;
}
/*
* Release all objects in the pool, and reset the memory context.
*/
void
mpool_reset(MPool *mpool)
{
Assert(mpool != NULL && mpool->context != NULL);
Assert(MemoryContextIsValid(mpool->context));
elog(DEBUG2, "MPool: total_bytes_allocated=" INT64_FORMAT
", bytes_used=" INT64_FORMAT ", bytes_wasted=" INT64_FORMAT,
mpool->total_bytes_allocated, mpool->bytes_used,
mpool->bytes_wasted);
MemoryContextReset(mpool->context);
mpool_init(mpool);
}
/*
* Delete the MPool object and its related space.
*/
void
mpool_delete(MPool *mpool)
{
Assert(mpool != NULL && mpool->context != NULL);
Assert(MemoryContextIsValid(mpool->context));
mpool_reset(mpool);
MemoryContextDelete(mpool->context);
pfree(mpool);
}
uint64 mpool_total_bytes_allocated(MPool *mpool)
{
Assert(mpool != NULL);
return mpool->total_bytes_allocated;
}
uint64 mpool_bytes_used(MPool *mpool)
{
Assert(mpool != NULL);
return mpool->bytes_used;
}