forked from GitHub/gf-core
consolidation of free blocks
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
// #define DEBUG_MEMORY_ALLOCATOR
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -372,13 +374,14 @@ PgfDB::PgfDB(const char* filepath, int flags, int mode) {
|
||||
cleanup_revisions();
|
||||
}
|
||||
|
||||
top = ms->top;
|
||||
free_blocks = ms->free_blocks;
|
||||
free_descriptors[0] = ms->free_descriptors;
|
||||
free_descriptors[1] = 0;
|
||||
free_descriptors[2] = 0;
|
||||
last_free_block = 0;
|
||||
last_free_block_size= 0;
|
||||
top = ms->top;
|
||||
free_blocks = ms->free_blocks;
|
||||
free_descriptors[0] = ms->free_descriptors;
|
||||
free_descriptors[1] = 0;
|
||||
free_descriptors[2] = 0;
|
||||
last_free_block = 0;
|
||||
last_free_block_size = 0;
|
||||
last_free_block_txn_id= 0;
|
||||
}
|
||||
|
||||
PGF_INTERNAL
|
||||
@@ -1024,7 +1027,7 @@ object PgfDB::pop_last_block_descriptor(object map, object *res)
|
||||
}
|
||||
|
||||
PGF_INTERNAL
|
||||
object PgfDB::delete_block_descriptor(object map, size_t *psize, object *po)
|
||||
object PgfDB::delete_block_descriptor(object map, object *po, size_t *psize, txn_t *ptxn_id)
|
||||
{
|
||||
if (map == 0) {
|
||||
*po = 0;
|
||||
@@ -1034,11 +1037,11 @@ object PgfDB::delete_block_descriptor(object map, size_t *psize, object *po)
|
||||
block_descr *descr = ptr(block_descr, map);
|
||||
int cmp = (*psize < descr->block_size) ? -1
|
||||
: (*psize > descr->block_size) ? 1
|
||||
: (descr->block_txn_id > ms->min_txn_id) ? -1
|
||||
: (ms->min_txn_id < descr->block_txn_id) ? -1
|
||||
: 0;
|
||||
if (cmp < 0) {
|
||||
object right = descr->right;
|
||||
object left = delete_block_descriptor(descr->left, psize, po);
|
||||
object left = delete_block_descriptor(descr->left, po, psize, ptxn_id);
|
||||
if (*po != 0) {
|
||||
map = upd_block_descr(map,left,right);
|
||||
map = balanceR_block_descriptor(map);
|
||||
@@ -1052,7 +1055,7 @@ object PgfDB::delete_block_descriptor(object map, size_t *psize, object *po)
|
||||
return map;
|
||||
} else if (cmp > 0) {
|
||||
object left = descr->left;
|
||||
object right = delete_block_descriptor(descr->right, psize, po);
|
||||
object right = delete_block_descriptor(descr->right, po, psize, ptxn_id);
|
||||
if (*po != 0) {
|
||||
map = upd_block_descr(map,left,right);
|
||||
map = balanceL_block_descriptor(map);
|
||||
@@ -1061,6 +1064,7 @@ object PgfDB::delete_block_descriptor(object map, size_t *psize, object *po)
|
||||
} else {
|
||||
fit:
|
||||
*po = descr->o;
|
||||
*ptxn_id = descr->block_txn_id;
|
||||
|
||||
object new_map;
|
||||
if (descr->left == 0) {
|
||||
@@ -1126,11 +1130,39 @@ object PgfDB::malloc_internal(size_t bytes)
|
||||
size_t block_size = request2size(bytes);
|
||||
|
||||
object o;
|
||||
if (last_free_block != 0 &&
|
||||
last_free_block_size >= block_size &&
|
||||
last_free_block_txn_id < ms->min_txn_id) {
|
||||
|
||||
/* We can grab a piece of the last free block */
|
||||
o = last_free_block;
|
||||
last_free_block += block_size;
|
||||
last_free_block_size -= block_size;
|
||||
if (last_free_block_size == 0) {
|
||||
last_free_block = 0;
|
||||
last_free_block_txn_id = 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEMORY_ALLOCATOR
|
||||
fprintf(stderr, "grabbed from the last block %016lx %ld\n", o, block_size);
|
||||
#endif
|
||||
return o;
|
||||
}
|
||||
|
||||
txn_t txn_id;
|
||||
size_t alloc_size = block_size;
|
||||
free_blocks = delete_block_descriptor(free_blocks, &alloc_size, &o);
|
||||
free_blocks = delete_block_descriptor(free_blocks, &o, &alloc_size, &txn_id);
|
||||
if (o != 0) {
|
||||
if (alloc_size > block_size) {
|
||||
free_blocks = insert_block_descriptor(free_blocks, o+block_size, alloc_size-block_size);
|
||||
if (last_free_block != 0) {
|
||||
free_blocks = insert_block_descriptor(free_blocks,
|
||||
last_free_block,
|
||||
last_free_block_size,
|
||||
last_free_block_txn_id);
|
||||
}
|
||||
last_free_block = o+block_size;
|
||||
last_free_block_size = alloc_size-block_size;
|
||||
last_free_block_txn_id = txn_id;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEMORY_ALLOCATOR
|
||||
@@ -1140,10 +1172,6 @@ object PgfDB::malloc_internal(size_t bytes)
|
||||
#endif
|
||||
|
||||
return o;
|
||||
} else {
|
||||
#ifdef DEBUG_MEMORY_ALLOCATOR
|
||||
fprintf(stderr, "allocated from top %016lx\n", top);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t free_size = mmap_size - top;
|
||||
@@ -1159,6 +1187,10 @@ object PgfDB::malloc_internal(size_t bytes)
|
||||
o = top;
|
||||
top += block_size;
|
||||
|
||||
#ifdef DEBUG_MEMORY_ALLOCATOR
|
||||
fprintf(stderr, "allocated from top %016lx\n", o);
|
||||
#endif
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -1206,10 +1238,8 @@ object PgfDB::realloc_internal(object oldo, size_t old_bytes, size_t new_bytes,
|
||||
}
|
||||
|
||||
PGF_INTERNAL
|
||||
object PgfDB::insert_block_descriptor(object map, object o, size_t size)
|
||||
object PgfDB::insert_block_descriptor(object map, object o, size_t size, txn_t txn_id)
|
||||
{
|
||||
txn_t txn_id = (o >= ms->top) ? 0 : ms->curr_txn_id;
|
||||
|
||||
if (map == 0)
|
||||
return new_block_descr(o, size, txn_id);
|
||||
|
||||
@@ -1222,12 +1252,12 @@ object PgfDB::insert_block_descriptor(object map, object o, size_t size)
|
||||
: 1;
|
||||
if (cmp < 0) {
|
||||
object right = descr->right;
|
||||
object left = insert_block_descriptor(descr->left, o, size);
|
||||
object left = insert_block_descriptor(descr->left, o, size, txn_id);
|
||||
map = upd_block_descr(map,left,right);
|
||||
return balanceL_block_descriptor(map);
|
||||
} else {
|
||||
object left = descr->left;
|
||||
object right = insert_block_descriptor(descr->right, o, size);
|
||||
object right = insert_block_descriptor(descr->right, o, size, txn_id);
|
||||
map = upd_block_descr(map,left,right);
|
||||
return balanceR_block_descriptor(map);
|
||||
}
|
||||
@@ -1244,36 +1274,64 @@ void PgfDB::free_internal(object o, size_t bytes)
|
||||
return;
|
||||
|
||||
size_t block_size = request2size(bytes);
|
||||
txn_t txn_id = (o >= ms->top) ? 0 : ms->curr_txn_id;
|
||||
|
||||
if (o >= ms->top && o+block_size == top) {
|
||||
if (txn_id == 0 && o+block_size == top) {
|
||||
// The block has been allocated in the current transaction
|
||||
// and it is the last just before the top area. We can
|
||||
// simply decrement top;
|
||||
top -= block_size;
|
||||
if (last_free_block_txn_id == 0 &&
|
||||
last_free_block != 0 &&
|
||||
last_free_block+last_free_block_size == top) {
|
||||
// After the merge of the current block, the last one is
|
||||
// also on the border with top.
|
||||
top -= last_free_block_size;
|
||||
#ifdef DEBUG_MEMORY_ALLOCATOR
|
||||
fprintf(stderr, "merged with last free block and top %016lx\n", top);
|
||||
#endif
|
||||
last_free_block = 0;
|
||||
last_free_block_size = 0;
|
||||
last_free_block_txn_id = 0;
|
||||
} else {
|
||||
#ifdef DEBUG_MEMORY_ALLOCATOR
|
||||
fprintf(stderr, "merged with top %016lx\n", top);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_free_block != 0) {
|
||||
if (last_free_block+last_free_block_size == o) {
|
||||
if (last_free_block_txn_id == txn_id && last_free_block+last_free_block_size == o) {
|
||||
last_free_block_size += block_size;
|
||||
#ifdef DEBUG_MEMORY_ALLOCATOR
|
||||
fprintf(stderr, "merged block %016lx %ld\n", last_free_block, last_free_block_size);
|
||||
#endif
|
||||
} else if (o+block_size == last_free_block) {
|
||||
return;
|
||||
} else if (txn_id == last_free_block_txn_id && o+block_size == last_free_block) {
|
||||
last_free_block = o;
|
||||
last_free_block_size += block_size;
|
||||
#ifdef DEBUG_MEMORY_ALLOCATOR
|
||||
fprintf(stderr, "merged block %016lx %ld\n", last_free_block, last_free_block_size);
|
||||
#endif
|
||||
return;
|
||||
} else {
|
||||
free_blocks = insert_block_descriptor(free_blocks,
|
||||
last_free_block,
|
||||
last_free_block_size,
|
||||
last_free_block_txn_id);
|
||||
}
|
||||
}
|
||||
|
||||
last_free_block = o;
|
||||
last_free_block_size = block_size;
|
||||
|
||||
free_blocks = insert_block_descriptor(free_blocks, o, block_size);
|
||||
last_free_block_txn_id = txn_id;
|
||||
|
||||
#ifdef DEBUG_MEMORY_ALLOCATOR
|
||||
fprintf(stderr, "last free block %016lx (size: %ld, txn_id: %ld)\n",
|
||||
last_free_block,
|
||||
last_free_block_size,
|
||||
last_free_block_txn_id);
|
||||
dump_free_blocks(free_blocks);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
@@ -1341,14 +1399,20 @@ void PgfDB::start_transaction()
|
||||
free_descriptors[2] = 0;
|
||||
last_free_block = 0;
|
||||
last_free_block_size = 0;
|
||||
last_free_block_txn_id = 0;
|
||||
}
|
||||
|
||||
PGF_INTERNAL
|
||||
void PgfDB::commit(object o)
|
||||
{
|
||||
if (last_free_block != 0) {
|
||||
last_free_block = 0;
|
||||
free_blocks = insert_block_descriptor(free_blocks,
|
||||
last_free_block,
|
||||
last_free_block_size,
|
||||
last_free_block_txn_id);
|
||||
last_free_block = 0;
|
||||
last_free_block_size = 0;
|
||||
last_free_block_txn_id = 0;
|
||||
}
|
||||
|
||||
malloc_state *ms = current_db->ms;
|
||||
@@ -1445,8 +1509,9 @@ void PgfDB::rollback()
|
||||
free_descriptors[0] = ms->free_descriptors;
|
||||
free_descriptors[1] = 0;
|
||||
free_descriptors[2] = 0;
|
||||
last_free_block = 0;
|
||||
last_free_block = 0;
|
||||
last_free_block_size = 0;
|
||||
last_free_block_txn_id = 0;
|
||||
|
||||
#ifndef _WIN32
|
||||
pthread_mutex_unlock(&ms->write_mutex);
|
||||
|
||||
@@ -73,6 +73,7 @@ private:
|
||||
object free_descriptors[3];
|
||||
object last_free_block;
|
||||
size_t last_free_block_size;
|
||||
txn_t last_free_block_txn_id;
|
||||
|
||||
size_t mmap_size;
|
||||
size_t page_size;
|
||||
@@ -136,8 +137,8 @@ private:
|
||||
PGF_INTERNAL_DECL object balanceR_block_descriptor(object map);
|
||||
PGF_INTERNAL_DECL object pop_first_block_descriptor(object map, object *res);
|
||||
PGF_INTERNAL_DECL object pop_last_block_descriptor(object map, object *res);
|
||||
PGF_INTERNAL_DECL object insert_block_descriptor(object map, object o, size_t size);
|
||||
PGF_INTERNAL_DECL object delete_block_descriptor(object map, size_t *psize, object *po);
|
||||
PGF_INTERNAL_DECL object insert_block_descriptor(object map, object o, size_t size, txn_t txn_id);
|
||||
PGF_INTERNAL_DECL object delete_block_descriptor(object map, object *po, size_t *psize, txn_t *ptxn_id);
|
||||
|
||||
#ifdef DEBUG_MEMORY_ALLOCATOR
|
||||
PGF_INTERNAL_DECL void dump_free_blocks(object map);
|
||||
|
||||
Reference in New Issue
Block a user