8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 00:03:03 +01:00

Further class library development. Added memory pool locking and line number allocation information

This commit is contained in:
skidder 2003-01-07 16:35:10 +00:00
parent 745c17a574
commit 1a44760aed
7 changed files with 387 additions and 97 deletions

View File

@ -29,19 +29,19 @@
// Size in bytes, must be aligned according to ALLOC_ALIGNMENT
#define MIN_EXTENT_SIZE 100000
// Must be a power of 2
#define ALLOC_ALIGNMENT 4
#define ALIGN(X) ((X+ALLOC_ALIGNMENT-1) & ~(ALLOC_ALIGNMENT-1))
#define FB_MAX(M,N) ((M)>(N)?(M):(N))
// TODO (in order of importance):
// 1. Pool size limit
// 2. debug alloc/free pattern
// 3. line number debug info
// 4. pool locking and allocation source
// 5. red zones checking (not really needed because verify_pool is able to detect most corruption cases)
// 1. local pool locking +
// 2. line number debug info +
// 3. debug alloc/free pattern
// 4. print pool contents function
//---- Not needed for current codebase
// 5. Pool size limit
// 6. allocation source
// 7. shared pool locking
// 8. red zones checking (not really needed because verify_pool is able to detect most corruption cases)
namespace Firebird {
@ -53,6 +53,19 @@ static void pool_out_of_memory()
throw std::bad_alloc();
}
static MemoryPool* processMemoryPool = MemoryPool::createPool(
// Do global pool locking only for SS
#ifdef SUPERSERVER
true
#else
false
#endif
);
MemoryPool* MemoryPool::getProcessPool() {
return processMemoryPool;
}
void MemoryPool::updateSpare() {
updatingSpare = true; // This is to prevent re-enterance
do {
@ -70,7 +83,7 @@ void MemoryPool::updateSpare() {
while (pendingFree) {
PendingFreeBlock *temp = pendingFree;
pendingFree = temp->next;
MemoryBlock *blk = (MemoryBlock*)((char*)temp-ALIGN(sizeof(MemoryBlock)));
MemoryBlock *blk = (MemoryBlock*)((char*)temp-MEM_ALIGN(sizeof(MemoryBlock)));
BlockInfo info = {
blk,
blk->length
@ -97,14 +110,15 @@ void MemoryPool::external_free(void *blk) {
}
void MemoryPool::verify_pool() {
if (locking) lock.enter();
assert (!pendingFree || needSpare); // needSpare flag should be set if we are in
// a critically low memory condition
// check each block in each segment for consistency with free blocks structure
for (MemoryExtent *extent = extents; extent; extent=extent->next) {
MemoryBlock *prev = NULL;
for (MemoryBlock *blk = (MemoryBlock *)((char*)extent+ALIGN(sizeof(MemoryExtent)));
for (MemoryBlock *blk = (MemoryBlock *)((char*)extent+MEM_ALIGN(sizeof(MemoryExtent)));
!blk->last;
blk = (MemoryBlock *)((char*)blk+ALIGN(sizeof(MemoryBlock))+blk->length))
blk = (MemoryBlock *)((char*)blk+MEM_ALIGN(sizeof(MemoryBlock))+blk->length))
{
#ifndef NDEBUG
assert(blk->pool == this); // Pool is correct ?
@ -112,7 +126,7 @@ void MemoryPool::verify_pool() {
BlockInfo temp = {blk, blk->length};
bool foundTree = freeBlocks.locate(temp), foundPending = false;
for (PendingFreeBlock *tmp = pendingFree; tmp; tmp = tmp->next)
if (tmp == (PendingFreeBlock *)((char*)blk+ALIGN(sizeof(MemoryBlock)))) {
if (tmp == (PendingFreeBlock *)((char*)blk+MEM_ALIGN(sizeof(MemoryBlock)))) {
assert(!foundPending); // Block may be in pending list only one time
foundPending = true;
}
@ -127,17 +141,18 @@ void MemoryPool::verify_pool() {
prev = blk;
}
}
if (locking) lock.leave();
}
MemoryPool* MemoryPool::createPool() {
MemoryPool* MemoryPool::createPool(bool locking) {
size_t alloc_size = FB_MAX(
// This is the exact initial layout of memory pool in the first extent //
ALIGN(sizeof(MemoryExtent)) +
ALIGN(sizeof(MemoryBlock)) +
ALIGN(sizeof(MemoryPool)) +
ALIGN(sizeof(MemoryBlock)) +
ALIGN(sizeof(FreeBlocksTree::ItemList)) +
ALIGN(sizeof(MemoryBlock)) +
MEM_ALIGN(sizeof(MemoryExtent)) +
MEM_ALIGN(sizeof(MemoryBlock)) +
MEM_ALIGN(sizeof(MemoryPool)) +
MEM_ALIGN(sizeof(MemoryBlock)) +
MEM_ALIGN(sizeof(FreeBlocksTree::ItemList)) +
MEM_ALIGN(sizeof(MemoryBlock)) +
ALLOC_ALIGNMENT,
// ******************************************************************* //
MIN_EXTENT_SIZE);
@ -146,45 +161,46 @@ MemoryPool* MemoryPool::createPool() {
if (!mem) pool_out_of_memory();
((MemoryExtent *)mem)->next = NULL;
MemoryPool* pool = new(mem +
ALIGN(sizeof(MemoryExtent)) +
ALIGN(sizeof(MemoryBlock)))
MEM_ALIGN(sizeof(MemoryExtent)) +
MEM_ALIGN(sizeof(MemoryBlock)))
MemoryPool(mem, mem +
ALIGN(sizeof(MemoryExtent)) +
ALIGN(sizeof(MemoryBlock)) +
ALIGN(sizeof(MemoryPool)) +
ALIGN(sizeof(MemoryBlock)));
MEM_ALIGN(sizeof(MemoryExtent)) +
MEM_ALIGN(sizeof(MemoryBlock)) +
MEM_ALIGN(sizeof(MemoryPool)) +
MEM_ALIGN(sizeof(MemoryBlock)),
locking);
MemoryBlock *poolBlk = (MemoryBlock*) (mem+ALIGN(sizeof(MemoryExtent)));
MemoryBlock *poolBlk = (MemoryBlock*) (mem+MEM_ALIGN(sizeof(MemoryExtent)));
poolBlk->pool = pool;
poolBlk->used = true;
poolBlk->last = false;
poolBlk->type = TYPE_POOL;
poolBlk->length = ALIGN(sizeof(MemoryPool));
poolBlk->length = MEM_ALIGN(sizeof(MemoryPool));
poolBlk->prev = NULL;
MemoryBlock *hdr = (MemoryBlock*) (mem +
ALIGN(sizeof(MemoryExtent)) +
ALIGN(sizeof(MemoryBlock)) +
ALIGN(sizeof(MemoryPool)));
MEM_ALIGN(sizeof(MemoryExtent)) +
MEM_ALIGN(sizeof(MemoryBlock)) +
MEM_ALIGN(sizeof(MemoryPool)));
hdr->pool = pool;
hdr->used = true;
hdr->last = false;
hdr->type = TYPE_LEAFPAGE;
hdr->length = ALIGN(sizeof(FreeBlocksTree::ItemList));
hdr->length = MEM_ALIGN(sizeof(FreeBlocksTree::ItemList));
hdr->prev = poolBlk;
MemoryBlock *blk = (MemoryBlock *)(mem +
ALIGN(sizeof(MemoryExtent)) +
ALIGN(sizeof(MemoryBlock)) +
ALIGN(sizeof(MemoryPool)) +
ALIGN(sizeof(MemoryBlock)) +
ALIGN(sizeof(FreeBlocksTree::ItemList)));
MEM_ALIGN(sizeof(MemoryExtent)) +
MEM_ALIGN(sizeof(MemoryBlock)) +
MEM_ALIGN(sizeof(MemoryPool)) +
MEM_ALIGN(sizeof(MemoryBlock)) +
MEM_ALIGN(sizeof(FreeBlocksTree::ItemList)));
int blockLength = alloc_size -
ALIGN(sizeof(MemoryExtent)) -
ALIGN(sizeof(MemoryBlock)) -
ALIGN(sizeof(MemoryPool)) -
ALIGN(sizeof(MemoryBlock)) -
ALIGN(sizeof(FreeBlocksTree::ItemList)) -
ALIGN(sizeof(MemoryBlock));
MEM_ALIGN(sizeof(MemoryExtent)) -
MEM_ALIGN(sizeof(MemoryBlock)) -
MEM_ALIGN(sizeof(MemoryPool)) -
MEM_ALIGN(sizeof(MemoryBlock)) -
MEM_ALIGN(sizeof(FreeBlocksTree::ItemList)) -
MEM_ALIGN(sizeof(MemoryBlock));
blk->pool = pool;
blk->used = false;
blk->last = true;
@ -207,7 +223,11 @@ void MemoryPool::deletePool(MemoryPool* pool) {
}
}
void* MemoryPool::alloc(size_t size, SSHORT type) {
void* MemoryPool::alloc(size_t size, SSHORT type
#ifdef DEBUG_GDS_ALLOC
, char* file, int line
#endif
) {
if (internalAlloc) {
if (size == sizeof(FreeBlocksTree::ItemList))
// This condition is to handle case when nodelist and itemlist have equal size
@ -229,36 +249,45 @@ void* MemoryPool::alloc(size_t size, SSHORT type) {
}
assert(false);
}
if (locking) lock.enter();
// Lookup a block greater or equal than size in freeBlocks tree
size = ALIGN(size);
size = MEM_ALIGN(size);
BlockInfo temp = {NULL, size};
void *result;
if (freeBlocks.locate(locGreatEqual,temp)) {
// Found large enough block
BlockInfo* current = &freeBlocks.current();
if (current->length-size < ALIGN(sizeof(MemoryBlock))+ALLOC_ALIGNMENT) {
if (current->length-size < MEM_ALIGN(sizeof(MemoryBlock))+ALLOC_ALIGNMENT) {
// Block is small enough to be returned AS IS
current->block->used = true;
current->block->type = type;
result = (char *)current->block + ALIGN(sizeof(MemoryBlock));
#ifdef DEBUG_GDS_ALLOC
current->block->file = file;
current->block->line = line;
#endif
result = (char *)current->block + MEM_ALIGN(sizeof(MemoryBlock));
internalAlloc = true;
freeBlocks.fastRemove();
internalAlloc = false;
} else {
// Cut a piece at the end of block in hope to avoid structural
// modification of free blocks tree
current->block->length -= ALIGN(sizeof(MemoryBlock))+size;
current->block->length -= MEM_ALIGN(sizeof(MemoryBlock))+size;
MemoryBlock *blk = (MemoryBlock *)((char*)current->block +
ALIGN(sizeof(MemoryBlock)) + current->block->length);
MEM_ALIGN(sizeof(MemoryBlock)) + current->block->length);
blk->pool = this;
blk->used = true;
#ifdef DEBUG_GDS_ALLOC
blk->file = file;
blk->line = line;
#endif
blk->last = current->block->last;
current->block->last = false;
blk->type = type;
blk->length = size;
blk->prev = current->block;
if (!blk->last)
((MemoryBlock *)((char*)blk + ALIGN(sizeof(MemoryBlock)) + blk->length))->prev = blk;
((MemoryBlock *)((char*)blk + MEM_ALIGN(sizeof(MemoryBlock)) + blk->length))->prev = blk;
// Update tree of free blocks
if (!freeBlocks.getPrev() || freeBlocks.current().length < current->block->length)
current->length = current->block->length;
@ -277,81 +306,99 @@ void* MemoryPool::alloc(size_t size, SSHORT type) {
addFreeBlock(block);
internalAlloc = false;
}
result = (char*)blk+ALIGN(sizeof(MemoryBlock));
result = (char*)blk+MEM_ALIGN(sizeof(MemoryBlock));
}
} else {
// If we are in a critically low memory condition look up for a block in a list
// of pending free blocks. We do not do "best fit" in this case
PendingFreeBlock *itr = pendingFree, *prev = NULL;
while (itr) {
MemoryBlock *temp = (MemoryBlock *)((char*)itr-ALIGN(sizeof(MemoryBlock)));
MemoryBlock *temp = (MemoryBlock *)((char*)itr-MEM_ALIGN(sizeof(MemoryBlock)));
if (temp->length >= size) {
if (temp->length-size < ALIGN(sizeof(MemoryBlock))+ALLOC_ALIGNMENT) {
if (temp->length-size < MEM_ALIGN(sizeof(MemoryBlock))+ALLOC_ALIGNMENT) {
// Block is small enough to be returned AS IS
temp->used = true;
temp->type = type;
#ifdef DEBUG_GDS_ALLOC
temp->file = file;
temp->line = line;
#endif
// Remove block from linked list
if (prev)
prev->next = itr->next;
else
pendingFree = itr->next;
if (locking) lock.leave();
return itr;
} else {
// Cut a piece at the end of block
// We don't need to modify tree of free blocks or a list of
// pending free blocks in this case
temp->length -= ALIGN(sizeof(MemoryBlock))+size;
temp->length -= MEM_ALIGN(sizeof(MemoryBlock))+size;
MemoryBlock *blk = (MemoryBlock *)((char*)temp +
ALIGN(sizeof(MemoryBlock)) + temp->length);
MEM_ALIGN(sizeof(MemoryBlock)) + temp->length);
blk->pool = this;
blk->used = true;
#ifdef DEBUG_GDS_ALLOC
blk->file = file;
blk->line = line;
#endif
blk->last = temp->last;
temp->last = false;
blk->type = type;
blk->length = size;
blk->prev = temp;
if (!blk->last)
((MemoryBlock *)((char*)blk + ALIGN(sizeof(MemoryBlock)) + blk->length))->prev = blk;
return (char *)blk + ALIGN(sizeof(MemoryBlock));
((MemoryBlock *)((char*)blk + MEM_ALIGN(sizeof(MemoryBlock)) + blk->length))->prev = blk;
if (locking) lock.leave();
return (char *)blk + MEM_ALIGN(sizeof(MemoryBlock));
}
}
prev = itr;
itr = itr->next;
}
// No large enough block found. We need to extend the pool
size_t alloc_size = FB_MAX(ALIGN(sizeof(MemoryExtent))+ALIGN(sizeof(MemoryBlock))+size, MIN_EXTENT_SIZE);
size_t alloc_size = FB_MAX(MEM_ALIGN(sizeof(MemoryExtent))+MEM_ALIGN(sizeof(MemoryBlock))+size, MIN_EXTENT_SIZE);
MemoryExtent* extent = (MemoryExtent *)external_alloc(alloc_size);
if (!extent) pool_out_of_memory();
if (!extent) {
if (locking) lock.leave();
pool_out_of_memory();
}
extent->next = extents;
extents = extent;
MemoryBlock *blk = (MemoryBlock *)((char*)extent+ALIGN(sizeof(MemoryExtent)));
MemoryBlock *blk = (MemoryBlock *)((char*)extent+MEM_ALIGN(sizeof(MemoryExtent)));
blk->pool = this;
blk->used = true;
blk->type = type;
#ifdef DEBUG_GDS_ALLOC
blk->file = file;
blk->line = line;
#endif
blk->prev = NULL;
if (alloc_size-size-ALIGN(sizeof(MemoryExtent))-ALIGN(sizeof(MemoryBlock)) < ALIGN(sizeof(MemoryBlock))+ALLOC_ALIGNMENT) {
if (alloc_size-size-MEM_ALIGN(sizeof(MemoryExtent))-MEM_ALIGN(sizeof(MemoryBlock)) < MEM_ALIGN(sizeof(MemoryBlock))+ALLOC_ALIGNMENT) {
// Block is small enough to be returned AS IS
blk->last = true;
blk->length = alloc_size - ALIGN(sizeof(MemoryExtent)) - ALIGN(sizeof(MemoryBlock));
blk->length = alloc_size - MEM_ALIGN(sizeof(MemoryExtent)) - MEM_ALIGN(sizeof(MemoryBlock));
} else {
// Cut a piece at the beginning of the block
blk->last = false;
blk->length = size;
// Put the rest to the tree of free blocks
MemoryBlock *rest = (MemoryBlock *)((char *)blk + ALIGN(sizeof(MemoryBlock)) + size);
MemoryBlock *rest = (MemoryBlock *)((char *)blk + MEM_ALIGN(sizeof(MemoryBlock)) + size);
rest->pool = this;
rest->used = false;
rest->last = true;
rest->length = alloc_size - ALIGN(sizeof(MemoryExtent)) -
ALIGN(sizeof(MemoryBlock)) - size - ALIGN(sizeof(MemoryBlock));
rest->length = alloc_size - MEM_ALIGN(sizeof(MemoryExtent)) -
MEM_ALIGN(sizeof(MemoryBlock)) - size - MEM_ALIGN(sizeof(MemoryBlock));
rest->prev = blk;
internalAlloc = true;
addFreeBlock(rest);
internalAlloc = false;
}
result = (char*)blk+ALIGN(sizeof(MemoryBlock));
result = (char*)blk+MEM_ALIGN(sizeof(MemoryBlock));
}
if (locking) lock.leave();
// Grow spare blocks pool if necessary
if (needSpare && !updatingSpare) updateSpare();
return result;
@ -364,7 +411,7 @@ void MemoryPool::addFreeBlock(MemoryBlock *blk) {
} catch(...) {
// Add item to the list of pending free blocks in case of critically-low memory condition
PendingFreeBlock* temp = (PendingFreeBlock *)((char *)freeBlocks.getAddErrorValue().block+
ALIGN(sizeof(MemoryBlock)));
MEM_ALIGN(sizeof(MemoryBlock)));
temp->next = pendingFree;
pendingFree = temp;
}
@ -378,7 +425,7 @@ void MemoryPool::removeFreeBlock(MemoryBlock *blk) {
// If we are in a critically-low memory condition our block could be in the
// pending free blocks list. Remove it from there
PendingFreeBlock *itr = pendingFree,
*temp = (PendingFreeBlock *)((char *)blk+ALIGN(sizeof(MemoryBlock)));
*temp = (PendingFreeBlock *)((char *)blk+MEM_ALIGN(sizeof(MemoryBlock)));
if (itr == temp)
pendingFree = itr->next;
else
@ -399,33 +446,34 @@ void MemoryPool::removeFreeBlock(MemoryBlock *blk) {
void MemoryPool::free(void *block) {
if (internalAlloc) {
((PendingFreeBlock*)block)->next = pendingFree;
((MemoryBlock*)((char*)block-ALIGN(sizeof(MemoryBlock))))->used = false;
((MemoryBlock*)((char*)block-MEM_ALIGN(sizeof(MemoryBlock))))->used = false;
pendingFree = (PendingFreeBlock*)block;
needSpare = true;
return;
}
internalAlloc = true;
MemoryBlock *blk = (MemoryBlock *)((char*)block - ALIGN(sizeof(MemoryBlock))), *prev;
if (locking) lock.enter();
MemoryBlock *blk = (MemoryBlock *)((char*)block - MEM_ALIGN(sizeof(MemoryBlock))), *prev;
// Try to merge block with preceding free block
if ((prev = blk->prev) && !prev->used) {
removeFreeBlock(prev);
prev->length += blk->length + ALIGN(sizeof(MemoryBlock));
prev->length += blk->length + MEM_ALIGN(sizeof(MemoryBlock));
MemoryBlock *next = NULL;
if (blk->last) {
prev->last = true;
} else {
next = (MemoryBlock *)((char *)blk+ALIGN(sizeof(MemoryBlock))+blk->length);
next = (MemoryBlock *)((char *)blk+MEM_ALIGN(sizeof(MemoryBlock))+blk->length);
if (next->used) {
next->prev = prev;
prev->last = false;
} else {
// Merge next block too
removeFreeBlock(next);
prev->length += next->length + ALIGN(sizeof(MemoryBlock));
prev->length += next->length + MEM_ALIGN(sizeof(MemoryBlock));
prev->last = next->last;
if (!next->last)
((MemoryBlock *)((char *)next+ALIGN(sizeof(MemoryBlock))+next->length))->prev = prev;
((MemoryBlock *)((char *)next+MEM_ALIGN(sizeof(MemoryBlock))+next->length))->prev = prev;
}
}
addFreeBlock(prev);
@ -435,18 +483,68 @@ void MemoryPool::free(void *block) {
blk->used = false;
// Try to merge block with next free block
if (!blk->last &&
!(next = (MemoryBlock *)((char*)blk+ALIGN(sizeof(MemoryBlock))+blk->length))->used)
!(next = (MemoryBlock *)((char*)blk+MEM_ALIGN(sizeof(MemoryBlock))+blk->length))->used)
{
removeFreeBlock(next);
blk->length += next->length + ALIGN(sizeof(MemoryBlock));
blk->length += next->length + MEM_ALIGN(sizeof(MemoryBlock));
blk->last = next->last;
if (!next->last)
((MemoryBlock *)((char *)next+ALIGN(sizeof(MemoryBlock))+next->length))->prev = blk;
((MemoryBlock *)((char *)next+MEM_ALIGN(sizeof(MemoryBlock))+next->length))->prev = blk;
}
addFreeBlock(blk);
}
if (locking) lock.leave();
internalAlloc = false;
if (needSpare && !updatingSpare) updateSpare();
}
} /* namespace Firebird */
#ifndef TESTING_ONLY
extern "C" {
#ifdef DEBUG_GDS_ALLOC
void* API_ROUTINE gds__alloc_debug(SLONG size_request,
TEXT* filename,
ULONG lineno)
{
return Firebird::processMemoryPool->alloc(size_request, 0, filename, lineno);
}
#else
void* API_ROUTINE gds__alloc(SLONG size_request)
{
return Firebird::processMemoryPool->alloc(size_request);
}
#endif
ULONG API_ROUTINE gds__free(void* blk) {
Firebird::processMemoryPool->free(blk);
return 0;
}
};
void* operator new(size_t s) {
#if defined(DEV_BUILD)
printf("You MUST allocate all memory from a pool. Don't use the default global new().\n");
#endif // DEV_BUILD
return Firebird::processMemoryPool->alloc(s, 0
#ifdef DEBUG_GDS_ALLOC
,__FILE__,__LINE__
#endif
);
}
void* operator new[](size_t s) {
#if defined(DEV_BUILD)
printf("You MUST allocate all memory from a pool. Don't use the default global new[]().\n");
#endif // DEV_BUILD
return Firebird::processMemoryPool->alloc(s, 0
#ifdef DEBUG_GDS_ALLOC
,__FILE__,__LINE__
#endif
);
}
#endif

View File

@ -28,9 +28,16 @@
#include <malloc.h>
#include "../../include/fb_types.h"
#include "../../include/firebird.h"
#include "../jrd/common.h"
#include "tree.h"
#include "locks.h"
#define MAX_TREE_DEPTH 4
// Must be a power of 2
#define ALLOC_ALIGNMENT 4
#define MEM_ALIGN(X) FB_ALIGN(X,ALLOC_ALIGNMENT)
namespace Firebird {
@ -41,10 +48,10 @@ struct MemoryBlock /* 16 bytes of block header is not too much I think */ {
SSHORT type;
size_t length; /* Includes only actual block size, header not included */
struct MemoryBlock *prev;
/*#ifdef DEBUG_GDS_ALLOC
#ifdef DEBUG_GDS_ALLOC
char *file;
int line;
#endif*/
#endif
};
#define TYPE_POOL -1
@ -72,6 +79,10 @@ struct PendingFreeBlock {
};
// Memory pool based on B+ tree of free memory blocks
// We are going to have two target architectures:
// 1. Multi-process server with customizable lock manager
// 2. Multi-threaded server with single process (SUPERSERVER)
class MemoryPool {
private:
typedef BePlusTree<BlockInfo, BlockInfo, MemoryPool,
@ -85,15 +96,23 @@ private:
bool needSpare;
bool updatingSpare;
PendingFreeBlock *pendingFree;
#ifdef SUPERSERVER
Spinlock lock;
#else
// FIXME: Shared memory lock needs to be here. Any attempt to use shared pool locking in CS will fail
Spinlock lock;
#endif
bool locking;
// Do not allow to create and destroy pool directly from outside
MemoryPool(void *first_extent, void *root_page) :
MemoryPool(void *first_extent, void *root_page, bool _locking) :
freeBlocks(this, root_page),
extents((MemoryExtent *)first_extent),
internalAlloc(false),
needSpare(false),
updatingSpare(false),
pendingFree(NULL)
pendingFree(NULL),
locking(_locking)
{
}
@ -112,22 +131,87 @@ private:
void removeFreeBlock(MemoryBlock *blk);
public:
static MemoryPool* createPool();
static MemoryPool* createPool(bool locking = false);
static MemoryPool* getProcessPool();
static void deletePool(MemoryPool* pool);
void* alloc(size_t size, SSHORT type = 0);
void* alloc(size_t size, SSHORT type = 0
#ifdef DEBUG_GDS_ALLOC
, char *file = NULL, int line = 0
#endif
);
void free(void *block);
void verify_pool();
/* void* calloc(size_t size) {
void* result = malloc(size);
static void globalFree(void *block) {
((MemoryBlock*)((char*)block-MEM_ALIGN(sizeof(MemoryBlock))))->pool->free(block);
}
void* calloc(size_t size, SSHORT type = 0
#ifdef DEBUG_GDS_ALLOC
, char *file = NULL, int line = 0
#endif
) {
void* result = alloc(size, type
#ifdef DEBUG_GDS_ALLOC
, file, line
#endif
);
memset(result,size,0);
}*/
return result;
}
};
}; // namespace Firebird
#ifndef TESTING_ONLY
extern "C" {
#ifdef DEBUG_GDS_ALLOC
void* API_ROUTINE gds__alloc_debug(SLONG size_request,
TEXT* filename,
ULONG lineno);
#else
void* API_ROUTINE gds__alloc(SLONG size_request);
#endif
ULONG API_ROUTINE gds__free(void* blk);
};
// Global versions of operator new() for compatibility with crappy libraries
void* operator new(size_t);
void* operator new[](size_t);
#ifdef DEBUG_GDS_ALLOC
inline void* operator new(size_t s, Firebird::MemoryPool* pool, char* file, int line) {
pool->alloc(s, 0, file, line);
}
inline void* operator new[](size_t s, Firebird::MemoryPool* pool, char* file, int line) {
pool->alloc(s, 0, pool, file, line);
}
#define FB_NEW(pool) new(pool,__FILE__,__LINE__)
#define FB_NEW_RPT(pool,count) new(pool,count,__FILE__,__LINE__)
#else
inline void* operator new(size_t s, Firebird::MemoryPool* pool) {
return pool->alloc(s);
}
inline void* operator new[](size_t s, Firebird::MemoryPool* pool) {
return pool->alloc(s);
}
#define FB_NEW(pool) new(pool)
#define FB_NEW_RPT(pool,count) new(pool,count)
#endif
inline void operator delete(void* mem) {
Firebird::MemoryPool::globalFree(mem);
}
inline void operator delete[](void* mem) {
Firebird::MemoryPool::globalFree(mem);
}
#endif
#endif

View File

@ -211,8 +211,46 @@ static void testAllocatorMemoryPool() {
BePlusTree<AllocItem,AllocItem,MallocAllocator,DefaultKeyValue<AllocItem>,AllocItem> items(&allocator),
bigItems(&allocator);
// Allocate small items
int n = 0;
for (int i=0;i<ALLOC_ITEMS;i++) {
int i, n = 0;
for (i=0;i<ALLOC_ITEMS;i++) {
n = n * 47163 - 57412;
AllocItem temp = {n, pool->alloc((n % MAX_ITEM_SIZE + MAX_ITEM_SIZE)/2+1)};
items.add(temp);
}
// Deallocate half of small items
n = 0;
if (items.getFirst()) do {
pool->free(items.current().item);
n++;
} while (n < ALLOC_ITEMS/2 && items.getNext());
// Allocate big items
for (i=0;i<BIG_ITEMS;i++) {
n = n * 47163 - 57412;
AllocItem temp = {n, pool->alloc((n % BIG_SIZE + BIG_SIZE)/2+1)};
bigItems.add(temp);
}
// Deallocate the rest of small items
do {
pool->free(items.current().item);
} while (items.getNext());
// Deallocate big items
if (bigItems.getFirst()) do {
pool->free(bigItems.current().item);
} while (bigItems.getNext());
Firebird::MemoryPool::deletePool(pool);
report();
}
static void testAllocatorMemoryPoolLocking() {
printf("Test run for Firebird::MemoryPool with locking...\n");
start();
Firebird::MemoryPool* pool = Firebird::MemoryPool::createPool(true);
MallocAllocator allocator;
BePlusTree<AllocItem,AllocItem,MallocAllocator,DefaultKeyValue<AllocItem>,AllocItem> items(&allocator),
bigItems(&allocator);
// Allocate small items
int i, n = 0;
for (i=0;i<ALLOC_ITEMS;i++) {
n = n * 47163 - 57412;
AllocItem temp = {n, pool->alloc((n % MAX_ITEM_SIZE + MAX_ITEM_SIZE)/2+1)};
items.add(temp);
@ -248,8 +286,8 @@ static void testAllocatorMalloc() {
BePlusTree<AllocItem,AllocItem,MallocAllocator,DefaultKeyValue<AllocItem>,AllocItem> items(&allocator),
bigItems(&allocator);
// Allocate small items
int n = 0;
for (int i=0;i<ALLOC_ITEMS;i++) {
int i, n = 0;
for (i=0;i<ALLOC_ITEMS;i++) {
n = n * 47163 - 57412;
AllocItem temp = {n, malloc((n % MAX_ITEM_SIZE + MAX_ITEM_SIZE)/2+1)};
items.add(temp);
@ -320,6 +358,7 @@ int main() {
testTree();
testAllocatorOverhead();
testAllocatorMemoryPool();
testAllocatorMemoryPoolLocking();
testAllocatorMalloc();
testAllocatorOldPool();
}

View File

@ -317,7 +317,7 @@ void testAllocator() {
MemoryPool::deletePool(pool);
}
void main() {
int main() {
testVector();
testSortedVector();
testBePlusTree();

View File

@ -0,0 +1,69 @@
#ifndef LOCKS_H
#define LOCKS_H
#include "firebird.h"
#ifdef WIN_NT
// It is relatively easy to avoid using this header. Maybe do the same stuff like
// in thd.h ? This is Windows platform maintainers choice
#include <windows.h>
#else
#include <pthread.h>
#endif
namespace Firebird {
#ifdef WIN_NT
/* Process-local spinlock. Used to manage memory heaps in threaded environment. */
// Windows version of the class
class Spinlock {
private:
CRITICAL_SECTION spinlock;
public:
Spinlock() {
if (!InitializeCriticalSectionAndSpinCount(&spinlock, 4000))
system_call_failed::raise();
}
~Spinlock() {
DeleteCriticalSection(&spinlock);
}
void enter() {
EnterCriticalSection(&spinlock);
}
void leave() {
LeaveCriticalSection(&spinlock);
}
};
#else
/* Process-local spinlock. Used to manage memory heaps in threaded environment. */
// Pthreads version of the class
class Spinlock {
private:
pthread_spinlock_t spinlock;
public:
Spinlock() {
if (pthread_spin_init(&spinlock, false))
system_call_failed::raise();
}
~Spinlock() {
if (pthread_spin_destroy(&spinlock))
system_call_failed::raise();
}
void enter() {
if (pthread_spin_lock(&spinlock))
system_call_failed::raise();
}
void leave() {
if (pthread_spin_unlock(&spinlock))
system_call_failed::raise();
}
};
#endif
}
#endif

View File

@ -1,11 +1,11 @@
# Test for library integrity
# this should be compiled with optimization turned off and with NDEBUG undefined
ulimit -s unlimited
g++ -ggdb -Wall class_test.cpp alloc.cpp 2> aa
g++ -ggdb -Wall -I../../include -pthread class_test.cpp alloc.cpp ../fb_exception.cpp 2> aa
./a.out
# Chose the best algorithm parameters for the target architecture
g++ -O3 -march=pentium3 -DNDEBUG -I../../include class_perf.cpp alloc.cpp \
g++ -O3 -pthread -march=pentium3 -DNDEBUG -DTESTING_ONLY -I../../include class_perf.cpp alloc.cpp \
../memory/memory_pool.cpp ../fb_exception.cpp ../memory/allocators.cpp 2> aa
#g++ -ggdb -I../../include class_perf.cpp alloc.cpp \
#../memory/memory_pool.cpp ../fb_exception.cpp ../memory/allocators.cpp 2> aa

View File

@ -45,6 +45,10 @@
#define LEAF_PAGE_SIZE 100
#define NODE_PAGE_SIZE 100
/*inline void* operator new (size_t size, void *place) {
return place;
}*/
namespace Firebird {
class MallocAllocator {
@ -59,10 +63,6 @@ public:
enum LocType { locEqual, locLess, locGreat, locGreatEqual, locLessEqual };
/*inline void* operator new (size_t size, void *place) {
return place;
}*/
// Fast and simple B+ tree of simple types
// Tree has state (current item) and no iterator classes.
// This is by design to make it simplier and faster :)))