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

Further class library development. MemoryPool works now

This commit is contained in:
skidder 2003-01-03 16:03:30 +00:00
parent 6a290efb47
commit 77761a16b9
6 changed files with 380 additions and 188 deletions

View File

@ -35,10 +35,12 @@
#define FB_MAX(M,N) ((M)>(N)?(M):(N))
// TODO:
// 1. red zones checking
// 2. alloc/free pattern
// 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)
namespace Firebird {
@ -50,8 +52,42 @@ static void pool_out_of_memory()
throw std::bad_alloc();
}
void MemoryPool::updateSpare() {
updatingSpare = true; // This is to prevent re-enterance
do {
try {
do {
needSpare = false;
while (spareLeafs.getCount() < spareLeafs.getCapacity())
spareLeafs.add(alloc(sizeof(FreeBlocksTree::ItemList), TYPE_LEAFPAGE));
while (spareNodes.getCount() <= freeBlocks.level)
spareNodes.add(alloc(sizeof(FreeBlocksTree::NodeList), TYPE_TREEPAGE));
break;
} while (needSpare);
// Great, if we were able to restore free blocks tree operations after critically low
// memory condition then try to add pending free blocks to our tree
while (pendingFree) {
PendingFreeBlock *temp = pendingFree;
pendingFree = temp->next;
MemoryBlock *blk = (MemoryBlock*)((char*)temp-ALIGN(sizeof(MemoryBlock)));
BlockInfo info = {
blk,
blk->length
};
internalAlloc = true;
freeBlocks.add(info); // We should be able to do this because we had all needed spare blocks
internalAlloc = false;
}
} catch(...) {
// We can always recover after this
break;
}
} while (needSpare);
updatingSpare = false;
}
void* MemoryPool::external_alloc(size_t size) {
// This method is assumed to throw exceptions in case it cannot alloc
// This method is assumed to return NULL in case it cannot alloc
return malloc(size);
}
@ -156,9 +192,7 @@ MemoryPool* MemoryPool::createPool() {
blk->prev = hdr;
BlockInfo temp = {blk, blockLength};
pool->freeBlocks.add(temp);
// This code may not work if tree factor is 2 (but if MIN_EXTENT_SIZE is large enough it will)
pool->spareLeaf = pool->alloc(sizeof(FreeBlocksTree::ItemList));
pool->spareNodes.add(pool->alloc(sizeof(FreeBlocksTree::NodeList)));
pool->updateSpare();
return pool;
}
@ -176,11 +210,13 @@ void* MemoryPool::alloc(size_t size, SSHORT type) {
if (internalAlloc) {
if (size == sizeof(FreeBlocksTree::ItemList))
// This condition is to handle case when nodelist and itemlist have equal size
if (sizeof(FreeBlocksTree::ItemList)!=sizeof(FreeBlocksTree::ItemList) || spareLeaf) {
void *temp = spareLeaf;
spareLeaf = NULL;
if (sizeof(FreeBlocksTree::ItemList)!=sizeof(FreeBlocksTree::NodeList) ||
spareLeafs.getCount())
{
if (!spareLeafs.getCount()) pool_out_of_memory();
void *temp = spareLeafs[spareLeafs.getCount()-1];
spareLeafs.shrink(spareLeafs.getCount()-1);
needSpare = true;
if (!temp) pool_out_of_memory();
return temp;
}
if (size == sizeof(FreeBlocksTree::NodeList)) {
@ -204,7 +240,9 @@ void* MemoryPool::alloc(size_t size, SSHORT type) {
current->block->used = true;
current->block->type = type;
result = (char *)current->block + 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
@ -221,7 +259,7 @@ void* MemoryPool::alloc(size_t size, SSHORT type) {
if (!blk->last)
((MemoryBlock *)((char*)blk + ALIGN(sizeof(MemoryBlock)) + blk->length))->prev = blk;
// Update tree of free blocks
if (!freeBlocks.getPrev() || freeBlocks.current().length <= current->block->length)
if (!freeBlocks.getPrev() || freeBlocks.current().length < current->block->length)
current->length = current->block->length;
else {
// Tree needs to be modified structurally
@ -230,23 +268,15 @@ void* MemoryPool::alloc(size_t size, SSHORT type) {
#else
bool res = freeBlocks.getNext();
assert(res);
assert(&freeBlocks.current()==current);
#endif
BlockInfo temp = {current->block, current->block->length};
freeBlocks.fastRemove();
internalAlloc = true;
try {
freeBlocks.add(temp);
} 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)));
temp->next = pendingFree;
pendingFree = temp;
}
MemoryBlock *block = current->block;
freeBlocks.fastRemove();
addFreeBlock(block);
internalAlloc = false;
}
result = blk+1;
result = (char*)blk+ALIGN(sizeof(MemoryBlock));
}
} else {
// If we are in a critically low memory condition look up for a block in a list
@ -263,7 +293,7 @@ void* MemoryPool::alloc(size_t size, SSHORT type) {
if (prev)
prev->next = itr->next;
else
pendingFree = itr->next;
pendingFree = itr->next;
return itr;
} else {
// Cut a piece at the end of block
@ -315,158 +345,107 @@ void* MemoryPool::alloc(size_t size, SSHORT type) {
rest->length = alloc_size - ALIGN(sizeof(MemoryExtent)) -
ALIGN(sizeof(MemoryBlock)) - size - ALIGN(sizeof(MemoryBlock));
rest->prev = blk;
BlockInfo temp = {rest, rest->length};
internalAlloc = true;
try {
freeBlocks.add(temp);
} 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)));
temp->next = pendingFree;
pendingFree = temp;
}
addFreeBlock(rest);
internalAlloc = false;
}
result = (char*)blk+ALIGN(sizeof(MemoryBlock));
}
// Grow spare blocks pool if necessary
if (needSpare) {
try {
if (!spareLeaf)
spareLeaf = alloc(sizeof(FreeBlocksTree::ItemList), TYPE_LEAFPAGE);
while (spareNodes.getCount() <= freeBlocks.level)
spareNodes.add(alloc(sizeof(FreeBlocksTree::NodeList), TYPE_TREEPAGE));
needSpare = false;
// We do not try to add pending blocks here because it is REALLY unlikely
// that we'll be able to recover after critically low memory condition
// during alloc()
} catch(...) {
// We can recover after this
}
}
if (needSpare && !updatingSpare) updateSpare();
return result;
}
void MemoryPool::free(void *block) {
MemoryBlock *blk = (MemoryBlock *)((char*)block - ALIGN(sizeof(MemoryBlock))), *prev;
// Try to merge block with preceding free block
if ((prev = blk->prev) && !prev->used) {
BlockInfo temp = {prev, prev->length};
if (freeBlocks.locate(temp)) {
freeBlocks.fastRemove();
} else {
// 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 *)(prev+1);
if (itr == temp)
pendingFree = itr->next;
else
{
while ( itr ) {
PendingFreeBlock *next = itr->next;
if (next==temp) {
itr->next = temp->next;
break;
}
itr = next;
void MemoryPool::addFreeBlock(MemoryBlock *blk) {
BlockInfo info = {blk, blk->length};
try {
freeBlocks.add(info);
} 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)));
temp->next = pendingFree;
pendingFree = temp;
}
}
void MemoryPool::removeFreeBlock(MemoryBlock *blk) {
BlockInfo info = {blk, blk->length};
if (freeBlocks.locate(info)) {
freeBlocks.fastRemove();
} else {
// 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)));
if (itr == temp)
pendingFree = itr->next;
else
{
while ( itr ) {
PendingFreeBlock *next = itr->next;
if (next==temp) {
itr->next = temp->next;
break;
}
itr = next;
}
assert(itr); // We had to find it somewhere
}
prev->length += blk->length + ALIGN(sizeof(MemoryBlock));
prev->last = blk->last;
if (!blk->last)
((MemoryBlock *)((char *)blk+ALIGN(sizeof(MemoryBlock))+blk->length))->prev = prev;
temp.length = prev->length;
internalAlloc = true;
try {
freeBlocks.add(temp);
} catch(...) {
// Add item to the list of pending free blocks in case of critically-low memory condition
PendingFreeBlock* temp = (PendingFreeBlock *)(freeBlocks.getAddErrorValue().block+1);
temp->next = pendingFree;
pendingFree = temp;
}
internalAlloc = false;
} else {
// Try to merge block with next free block
if (!blk->last) {
MemoryBlock *next = (MemoryBlock *)((char*)blk+ALIGN(sizeof(MemoryBlock))+blk->length);
if (!next->used) {
blk->length += next->length + ALIGN(sizeof(MemoryBlock));
blk->last = next->last;
if (!next->last)
((MemoryBlock *)((char *)next+ALIGN(sizeof(MemoryBlock))+next->length))->prev = blk;
BlockInfo temp = {next, next->length};
if (freeBlocks.locate(temp)) {
freeBlocks.fastRemove();
} else {
// 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*)prev+ALIGN(sizeof(MemoryBlock)));
if (itr == temp)
pendingFree = itr->next;
else
{
while ( itr ) {
PendingFreeBlock *next = itr->next;
if (next==temp) {
itr->next = temp->next;
break;
}
itr = next;
}
}
assert(itr); // We had to find it somewhere
}
}
}
// Mark block as free and add it to freeBlocks array
blk->used = false;
BlockInfo temp = {blk, blk->length};
internalAlloc = true;
try {
freeBlocks.add(temp);
} 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)));
temp->next = pendingFree;
pendingFree = temp;
}
internalAlloc = false;
}
// Grow spare blocks pool if necessary
if (needSpare) {
updateSpareBlocks: {
try {
if (!spareLeaf)
spareLeaf = alloc(sizeof(FreeBlocksTree::ItemList), TYPE_LEAFPAGE);
while (spareNodes.getCount() <= freeBlocks.level)
spareNodes.add(alloc(sizeof(FreeBlocksTree::NodeList), TYPE_TREEPAGE));
needSpare = false;
// Great, if we were able to restore free blocks tree operations after critically low
// memory condition then try to add pending free blocks to our tree
while (pendingFree) {
PendingFreeBlock *temp = pendingFree;
pendingFree = temp->next;
BlockInfo info = {
(MemoryBlock*)((char*)temp-ALIGN(sizeof(MemoryBlock))),
((MemoryBlock*)temp)->length
};
internalAlloc = true;
freeBlocks.add(info); // We should be able to do this because we had spare blocks
internalAlloc = false;
if (needSpare)
goto updateSpareBlocks;
}
} catch(...) {
// We can recover after this
}
}
}
}
void MemoryPool::free(void *block) {
if (internalAlloc) {
((PendingFreeBlock*)block)->next = pendingFree;
((MemoryBlock*)((char*)block-ALIGN(sizeof(MemoryBlock))))->used = false;
pendingFree = (PendingFreeBlock*)block;
needSpare = true;
return;
}
internalAlloc = true;
MemoryBlock *blk = (MemoryBlock *)((char*)block - 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));
MemoryBlock *next = NULL;
if (blk->last) {
prev->last = true;
} else {
next = (MemoryBlock *)((char *)blk+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->last = next->last;
if (!next->last)
((MemoryBlock *)((char *)next+ALIGN(sizeof(MemoryBlock))+next->length))->prev = prev;
}
}
addFreeBlock(prev);
} else {
MemoryBlock *next;
// Mark block as free
blk->used = false;
// Try to merge block with next free block
if (!blk->last &&
!(next = (MemoryBlock *)((char*)blk+ALIGN(sizeof(MemoryBlock))+blk->length))->used)
{
removeFreeBlock(next);
blk->length += next->length + ALIGN(sizeof(MemoryBlock));
blk->last = next->last;
if (!next->last)
((MemoryBlock *)((char *)next+ALIGN(sizeof(MemoryBlock))+next->length))->prev = blk;
}
addFreeBlock(blk);
}
internalAlloc = false;
if (needSpare && !updatingSpare) updateSpare();
}
} /* namespace Firebird */

View File

@ -79,19 +79,20 @@ private:
FreeBlocksTree freeBlocks; // B+ tree ordered by (length,address)
MemoryExtent *extents; // Linked list of all memory extents
void* spareLeaf;
Vector<void*,2> spareLeafs;
Vector<void*,MAX_TREE_DEPTH+1> spareNodes;
bool internalAlloc;
bool needSpare;
Vector<void*,MAX_TREE_DEPTH> spareNodes;
bool updatingSpare;
PendingFreeBlock *pendingFree;
// Do not allow to create and destroy pool directly from outside
MemoryPool(void *first_extent, void *root_page) :
freeBlocks(this, root_page),
extents((MemoryExtent *)first_extent),
spareLeaf(NULL),
internalAlloc(false),
needSpare(false),
updatingSpare(false),
pendingFree(NULL)
{
}
@ -104,6 +105,12 @@ private:
static void* external_alloc(size_t size);
static void external_free(void *blk);
void updateSpare();
void addFreeBlock(MemoryBlock *blk);
void removeFreeBlock(MemoryBlock *blk);
public:
static MemoryPool* createPool();

View File

@ -24,6 +24,8 @@
*/
#include "tree.h"
#include "alloc.h"
#include "../memory/memory_pool.h"
#include <stdio.h>
#include <time.h>
#include <set>
@ -38,12 +40,13 @@ void start() {
void report(int scale) {
clock_t d = clock();
printf("Add+remove %d elements from array of scale %d took %d milliseconds. \n",
printf("Add+remove %d elements from tree of scale %d took %d milliseconds. \n",
TEST_ITEMS, scale, (int)(d-t)*1000/CLOCKS_PER_SEC);
}
int main() {
using namespace Firebird;
using namespace Firebird;
static void testTree() {
printf("Fill array with test data (%d items)...", TEST_ITEMS);
Vector<int, TEST_ITEMS> *v = new Vector<int, TEST_ITEMS>();
int n = 0;
@ -142,3 +145,178 @@ int main() {
printf("Just a reference: add+remove %d elements from STL tree took %d milliseconds. \n",
TEST_ITEMS, (int)(d-t)*1000/CLOCKS_PER_SEC);
}
void report() {
clock_t d = clock();
printf("Operation took %d milliseconds.\n", (int)(d-t)*1000/CLOCKS_PER_SEC);
}
#define ALLOC_ITEMS 1000000
#define MAX_ITEM_SIZE 50
#define BIG_ITEMS (ALLOC_ITEMS/10)
#define BIG_SIZE (MAX_ITEM_SIZE*5)
struct AllocItem {
int order;
void *item;
static int compare(const AllocItem &i1, const AllocItem &i2) {
return i1.order > i2.order || (i1.order==i2.order && i1.item > i2.item);
}
};
static void testAllocatorOverhead() {
printf("Calculating measurement overhead...\n");
start();
MallocAllocator allocator;
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++) {
n = n * 47163 - 57412;
AllocItem temp = {n, (void*)i};
items.add(temp);
}
// Deallocate half of small items
n = 0;
if (items.getFirst()) do {
items.current();
n++;
} while (n < ALLOC_ITEMS/2 && items.getNext());
// Allocate big items
for (int i=0;i<BIG_ITEMS;i++) {
n = n * 47163 - 57412;
AllocItem temp = {n, (void*)i};
bigItems.add(temp);
}
// Deallocate the rest of small items
do {
items.current();
} while (items.getNext());
// Deallocate big items
if (bigItems.getFirst()) do {
bigItems.current();
} while (bigItems.getNext());
report();
}
static void testAllocatorMemoryPool() {
printf("Test run for Firebird::MemoryPool...\n");
start();
Firebird::MemoryPool* pool = Firebird::MemoryPool::createPool();
MallocAllocator allocator;
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++) {
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 (int 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 testAllocatorMalloc() {
printf("Test reference run for ::malloc...\n");
start();
MallocAllocator allocator;
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++) {
n = n * 47163 - 57412;
AllocItem temp = {n, malloc((n % MAX_ITEM_SIZE + MAX_ITEM_SIZE)/2+1)};
items.add(temp);
}
// Deallocate half of small items
n = 0;
if (items.getFirst()) do {
free(items.current().item);
n++;
} while (n < ALLOC_ITEMS/2 && items.getNext());
// Allocate big items
for (int i=0;i<BIG_ITEMS;i++) {
n = n * 47163 - 57412;
AllocItem temp = {n, malloc((n % BIG_SIZE + BIG_SIZE)/2+1)};
bigItems.add(temp);
}
// Deallocate the rest of small items
do {
free(items.current().item);
} while (items.getNext());
// Deallocate big items
if (bigItems.getFirst()) do {
free(bigItems.current().item);
} while (bigItems.getNext());
report();
}
static void testAllocatorOldPool() {
printf("Test run for old MemoryPool...\n");
start();
::MemoryPool *pool = new ::MemoryPool(0,getDefaultMemoryPool());
MallocAllocator allocator;
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++) {
n = n * 47163 - 57412;
AllocItem temp = {n, pool->allocate((n % MAX_ITEM_SIZE + MAX_ITEM_SIZE)/2+1,0)};
items.add(temp);
}
// Deallocate half of small items
n = 0;
if (items.getFirst()) do {
pool->deallocate(items.current().item);
n++;
} while (n < ALLOC_ITEMS/2 && items.getNext());
// Allocate big items
for (int i=0;i<BIG_ITEMS;i++) {
n = n * 47163 - 57412;
AllocItem temp = {n, pool->allocate((n % BIG_SIZE + BIG_SIZE)/2+1,0)};
bigItems.add(temp);
}
/* // Deallocate the rest of small items
do {
pool->deallocate(items.current().item);
} while (items.getNext());*/
// Deallocate big items
if (bigItems.getFirst()) do {
pool->deallocate(bigItems.current().item);
} while (bigItems.getNext());
delete pool;
report();
}
int main() {
testTree();
testAllocatorOverhead();
testAllocatorMemoryPool();
testAllocatorMalloc();
testAllocatorOldPool();
}

View File

@ -55,7 +55,7 @@ void testSortedVector() {
printf(passed?"PASSED\n":"FAILED\n");
}
#define TEST_ITEMS 100000
#define TEST_ITEMS 1000000
struct Test {
int value;
@ -244,8 +244,10 @@ void testBePlusTree() {
}
#define ALLOC_ITEMS 10
#define MAX_ITEM_SIZE 100
#define ALLOC_ITEMS 1000000
#define MAX_ITEM_SIZE 50
#define BIG_ITEMS (ALLOC_ITEMS/10)
#define BIG_SIZE (MAX_ITEM_SIZE*5)
struct AllocItem {
int order;
@ -260,7 +262,8 @@ void testAllocator() {
MemoryPool* pool = MemoryPool::createPool();
MallocAllocator allocator;
BePlusTree<AllocItem,AllocItem,MallocAllocator,DefaultKeyValue<AllocItem>,AllocItem> items(&allocator);
BePlusTree<AllocItem,AllocItem,MallocAllocator,DefaultKeyValue<AllocItem>,AllocItem> items(&allocator),
bigItems(&allocator);
printf("Allocate %d items: ", ALLOC_ITEMS);
int n = 0;
pool->verify_pool();
@ -268,18 +271,44 @@ void testAllocator() {
n = n * 47163 - 57412;
AllocItem temp = {n, pool->alloc((n % MAX_ITEM_SIZE + MAX_ITEM_SIZE)/2+1)};
items.add(temp);
pool->verify_pool();
}
printf(" DONE\n");
pool->verify_pool();
printf("Deallocate items in quasi-random order: ");
printf("Deallocate half of items in quasi-random order: ");
n = 0;
if (items.getFirst()) do {
pool->free(items.current().item);
pool->verify_pool();
n++;
} while (n < ALLOC_ITEMS/2 && items.getNext());
printf(" DONE\n");
pool->verify_pool();
printf("Allocate %d big items: ", BIG_ITEMS);
n = 0;
pool->verify_pool();
for (int 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);
}
printf(" DONE\n");
pool->verify_pool();
printf("Deallocate the rest of small items in quasi-random order: ");
do {
pool->free(items.current().item);
} while (items.getNext());
printf(" DONE\n");
pool->verify_pool();
printf("Deallocate big items in quasi-random order: ");
if (bigItems.getFirst()) do {
pool->free(bigItems.current().item);
} while (bigItems.getNext());
printf(" DONE\n");
pool->verify_pool();
// TODO:
// printf("Check that pool contains one free block per each segment and blocks have correct sizes");
// Test critically low memory conditions
MemoryPool::deletePool(pool);
}

View File

@ -5,5 +5,8 @@ g++ -ggdb -Wall class_test.cpp alloc.cpp 2> aa
./a.out
# Chose the best algorithm parameters for the target architecture
g++ -O3 -march=pentium3 -DNDEBUG class_perf.cpp
g++ -O3 -march=pentium3 -DNDEBUG -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
./a.out

View File

@ -30,6 +30,8 @@
#include <string.h>
#include <malloc.h>
#include "vector.h"
// FIXME: Temporary until we switch out of using STL
#include <new>
// This macro controls merging of nodes of all B+ trees
// Now it merges pages only when resulting page will be 3/4 filled or less
@ -57,9 +59,9 @@ public:
enum LocType { locEqual, locLess, locGreat, locGreatEqual, locLessEqual };
inline void* operator new (size_t size, void *place) {
/*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.
@ -286,10 +288,6 @@ private:
template <typename Value, typename Key, typename Allocator, typename KeyOfValue, typename Cmp, int LeafCount, int NodeCount>
void BePlusTree<Value, Key, Allocator, KeyOfValue, Cmp, LeafCount, NodeCount>::_removePage(int nodeLevel, void *node)
{
// We need to defer all deallocations until we finish manipulating the
// tree to enable re-enterance. That is why we use recursion instead
// of loops to climb up the tree. This doesn't hurt performance in any
// way but makes allocator implementation simplier
NodeList *list;
// Get parent and adjust the links
if (nodeLevel) {
@ -612,11 +610,9 @@ bool BePlusTree<Value, Key, Allocator, KeyOfValue, Cmp, LeafCount, NodeCount>::a
newNode = lower;
curLevel--;
}
Value temp = (*(ItemList*)newNode)[0];
addErrorValue = (*(ItemList*)newNode)[0];
((ItemList *)newNode)->~ItemList();
pool->free(newNode);
addErrorValue = temp; // We can do this only after all deallocations to prevent problems
// caused by re-enterance from allocator
throw;
}
return true;