blob: 0a61d92645fe6133acc321bc1d78efb2d3e32979 [file] [log] [blame]
/*
*
* Shared memory control - based on alocating chunks aligned on
* asize array (fibonachi), and dividing free bigger block.
*
*/
#include "postgres.h"
#include "shmmc.h"
#include "stdlib.h"
#include "string.h"
#include "orafunc.h"
#define LIST_ITEMS 512
int context;
typedef struct {
size_t size;
void* first_byte_ptr;
bool dispossible;
/* int16 context; */
} list_item;
typedef struct {
int list_c;
int max_size;
vardata data[1]; /* flexible array member */
} mem_desc;
#define MAX_SIZE 82688
static size_t asize[] = {
32,
64, 96, 160, 256,
416, 672, 1088, 1760,
2848, 4608, 7456, 12064,
19520, 31584, 51104, 82688};
int *list_c = NULL;
list_item *list = NULL;
size_t max_size;
int cycle = 0;
/* align requested size */
static int
ptr_comp(const void* a, const void* b)
{
list_item *_a = (list_item*) a;
list_item *_b = (list_item*) b;
return (long)_a->first_byte_ptr - (long)_b->first_byte_ptr;
}
char *
ora_sstrcpy(char *str)
{
int len;
char *result;
len = strlen(str);
if (NULL != (result = ora_salloc(len+1)))
memcpy(result, str, len + 1);
else
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"),
errdetail("Failed while allocation block %d bytes in shared memory.", len+1),
errhint("Increase SHMEMMSGSZ and recompile package.")));
return result;
}
char *
ora_scstring(text *str)
{
int len;
char *result;
len = VARSIZE_ANY_EXHDR(str);
if (NULL != (result = ora_salloc(len+1)))
{
memcpy(result, VARDATA_ANY(str), len);
result[len] = '\0';
}
else
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"),
errdetail("Failed while allocation block %d bytes in shared memory.", len+1),
errhint("Increase SHMEMMSGSZ and recompile package.")));
return result;
}
/*
* Compact the list of slots, by merging adjacent unused slots into larger
* slots.
*/
static void
defragmentation()
{
int src, target;
/* Sort the array to pointer order */
qsort(list, *list_c, sizeof(list_item), ptr_comp);
/* Merge adjacent dispossible slots, and move up other slots */
target = 0;
for (src = 0; src < *list_c; src++)
{
if (target > 0 &&
list[src].dispossible &&
list[target - 1].dispossible)
{
list[target - 1].size += list[src].size;
}
else
{
if (src != target)
memcpy(&list[target], &list[src], sizeof(list_item));
target++;
}
}
*list_c = target;
}
static size_t
align_size(size_t size)
{
int i;
/* default, we can allocate max MAX_SIZE memory block */
for (i = 0; i < 17; i++)
if (asize[i] >= size)
return asize[i];
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("too much large memory block request"),
errdetail("Failed while allocation block %lu bytes in shared memory.", (unsigned long) size),
errhint("Increase MAX_SIZE constant, fill table a_size and recompile package.")));
return 0;
}
/*
inicialize shared memory. It works in two modes, create and no create.
No create is used for mounting shared memory buffer. Top of memory is
used for list_item array.
*/
void
ora_sinit(void *ptr, size_t size, bool create)
{
if (list == NULL)
{
mem_desc *m = (mem_desc*)ptr;
list = (list_item*)m->data;
list_c = &m->list_c;
max_size = m->max_size = size;
if (create)
{
list[0].size = size - sizeof(list_item)*LIST_ITEMS - sizeof(mem_desc);
list[0].first_byte_ptr = &m->data + sizeof(list_item)*LIST_ITEMS;
list[0].dispossible = true;
*list_c = 1;
}
}
}
void*
ora_salloc(size_t size)
{
size_t aligned_size;
int repeat_c;
void *ptr = NULL;
aligned_size = align_size(size);
for (repeat_c = 0; repeat_c < 2; repeat_c++)
{
size_t max_min = max_size;
int select = -1;
int i;
/* find first good free block */
for (i = 0; i < *list_c; i++)
{
if (list[i].dispossible)
{
/* If this block is just the right size, return it */
if (list[i].size == aligned_size)
{
list[i].dispossible = false;
ptr = list[i].first_byte_ptr;
/* list[i].context = context; */
return ptr;
}
if (list[i].size > aligned_size && list[i].size < max_min)
{
max_min = list[i].size;
select = i;
}
}
}
/* If no suitable free slot found, defragment and try again. */
if (select == -1 || *list_c == LIST_ITEMS)
{
defragmentation();
continue;
}
/*
* A slot larger than required was found. Divide it to avoid wasting
* space, and return the slot of the right size.
*/
list[*list_c].size = list[select].size - aligned_size;
list[*list_c].first_byte_ptr = (char*)list[select].first_byte_ptr + aligned_size;
list[*list_c].dispossible = true;
list[select].size = aligned_size;
list[select].dispossible = false;
/* list[select].context = context; */
ptr = list[select].first_byte_ptr;
*list_c += 1;
break;
}
return ptr;
}
void
ora_sfree(void* ptr)
{
int i;
/*
if (cycle++ % 100 == 0)
{
size_t suma = 0;
for (i = 0; i < *list_c; i++)
if (list[i].dispossible)
suma += list[i].size;
elog(NOTICE, "=============== FREE MEM REPORT === %10d ================", suma);
}
*/
for (i = 0; i < *list_c; i++)
if (list[i].first_byte_ptr == ptr)
{
list[i].dispossible = true;
/* list[i].context = -1; */
memset(list[i].first_byte_ptr, '#', list[i].size);
return;
}
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("corrupted pointer"),
errdetail("Failed while reallocating memory block in shared memory."),
errhint("Report this bug to autors.")));
}
void*
ora_srealloc(void *ptr, size_t size)
{
void *result;
size_t aux_s = 0;
int i;
for (i = 0; i < *list_c; i++)
if (list[i].first_byte_ptr == ptr)
{
if (align_size(size) <= list[i].size)
return ptr;
aux_s = list[i].size;
}
if (aux_s == 0)
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("corrupted pointer"),
errdetail("Failed while reallocating memory block in shared memory."),
errhint("Report this bug to autors.")));
if (NULL != (result = ora_salloc(size)))
{
memcpy(result, ptr, aux_s);
ora_sfree(ptr);
}
return result;
}
/*
* alloc shared memory, raise exception if not
*/
void*
salloc(size_t size)
{
void* result;
if (NULL == (result = ora_salloc(size)))
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"),
errdetail("Failed while allocation block %lu bytes in shared memory.", (unsigned long) size),
errhint("Increase SHMEMMSGSZ and recompile package.")));
return result;
}
void*
srealloc(void *ptr, size_t size)
{
void* result;
if (NULL == (result = ora_srealloc(ptr, size)))
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"),
errdetail("Failed while reallocation block %lu bytes in shared memory.", (unsigned long) size),
errhint("Increase SHMEMMSGSZ and recompile package.")));
return result;
}