8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 12:43:02 +01:00
firebird-mirror/src/common/classes/alloc.cpp

683 lines
21 KiB
C++
Raw Normal View History

/*
* PROGRAM: Client/Server Common Code
* MODULE: alloc.cpp
* DESCRIPTION: Memory Pool Manager (based on B+ tree)
*
* The contents of this file are subject to the Interbase Public
* License Version 1.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.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* Created by: Nickolay Samofatov <skidder@bssys.com>
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
2003-01-06 18:35:21 +01:00
#include "../../include/firebird.h"
#include "alloc.h"
#include <new>
// Size in bytes, must be aligned according to ALLOC_ALIGNMENT
2002-12-16 19:33:54 +01:00
#define MIN_EXTENT_SIZE 100000
#define FB_MAX(M,N) ((M)>(N)?(M):(N))
#define FREE_PATTERN 0xDEADBEEF
#define ALLOC_PATTERN 0xFEEDABED
//#define ALLOC_PATTERN 0x0
#ifdef DEBUG_GDS_ALLOC
#define PATTERN_FILL(ptr,size,pattern) for (size_t _i=0;_i< size>>2;_i++) ((unsigned int*)(ptr))[_i]=(pattern)
#else
#define PATTERN_FILL(ptr,size,pattern) ((void)0)
#endif
// TODO (in order of importance):
// 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)
2002-12-16 19:33:54 +01:00
namespace Firebird {
int process_max_memory = 0;
int process_current_memory = 0;
// Helper function to reduce code size, since many compilers
// generate quite a bit of code at the point of the throw.
static void pool_out_of_memory()
{
// FIXME: this is a temporary solution until we switch out of using STL exceptions
throw std::bad_alloc();
}
static MemoryPool* processMemoryPool;
void MemoryPool::updateSpare() {
do {
do {
needSpare = false;
while (spareLeafs.getCount() < spareLeafs.getCapacity()) {
void* temp = internal_alloc(sizeof(FreeBlocksTree::ItemList), TYPE_LEAFPAGE);
if (!temp) return;
spareLeafs.add(temp);
}
while (spareNodes.getCount() <= freeBlocks.level) {
void* temp = internal_alloc(sizeof(FreeBlocksTree::NodeList), TYPE_TREEPAGE);
if (!temp) return;
spareNodes.add(temp);
}
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-MEM_ALIGN(sizeof(MemoryBlock)));
BlockInfo info = {
blk,
blk->length
};
freeBlocks.add(info); // We should be able to do this because we had all needed spare blocks
}
} while (needSpare);
}
void* MemoryPool::external_alloc(size_t size) {
// This method is assumed to return NULL in case it cannot alloc
return malloc(size);
}
void MemoryPool::external_free(void *blk) {
::free(blk);
}
void* MemoryPool::tree_alloc(size_t size) {
2003-01-10 13:27:57 +01:00
if (size == sizeof(FreeBlocksTree::ItemList))
// This condition is to handle case when nodelist and itemlist have equal size
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;
return temp;
}
if (size == sizeof(FreeBlocksTree::NodeList)) {
if (!spareNodes.getCount()) pool_out_of_memory();
void *temp = spareNodes[spareNodes.getCount()-1];
spareNodes.shrink(spareNodes.getCount()-1);
needSpare = true;
return temp;
}
assert(false);
2003-01-18 19:43:52 +01:00
return 0;
2003-01-10 13:27:57 +01:00
}
void MemoryPool::tree_free(void* block) {
2003-01-10 13:27:57 +01:00
((PendingFreeBlock*)block)->next = pendingFree;
((MemoryBlock*)((char*)block-MEM_ALIGN(sizeof(MemoryBlock))))->used = false;
pendingFree = (PendingFreeBlock*)block;
needSpare = true;
return;
}
void* MemoryPool::allocate(size_t size, SSHORT type
#ifdef DEBUG_GDS_ALLOC
, char* file, int line
#endif
) {
lock.enter();
void* result = internal_alloc(size, type
#ifdef DEBUG_GDS_ALLOC
, file, line
#endif
);
if (needSpare) updateSpare();
lock.leave();
if (!result) pool_out_of_memory();
// test with older behavior
// memset(result,0,size);
return result;
}
bool MemoryPool::verify_pool() {
#ifdef TESTING_ONLY
lock.enter();
2002-12-16 19:33:54 +01:00
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+MEM_ALIGN(sizeof(MemoryExtent)));
;
blk = (MemoryBlock *)((char*)blk+MEM_ALIGN(sizeof(MemoryBlock))+blk->length))
2002-12-16 19:33:54 +01:00
{
#ifndef NDEBUG
assert(blk->pool == this); // Pool is correct ?
assert(blk->prev == prev); // Prev is correct ?
BlockInfo temp = {blk, blk->length};
bool foundTree = freeBlocks.locate(temp), foundPending = false;
2003-01-06 18:35:21 +01:00
for (PendingFreeBlock *tmp = pendingFree; tmp; tmp = tmp->next)
if (tmp == (PendingFreeBlock *)((char*)blk+MEM_ALIGN(sizeof(MemoryBlock)))) {
2002-12-16 19:33:54 +01:00
assert(!foundPending); // Block may be in pending list only one time
foundPending = true;
}
assert(! (foundTree && foundPending)); // Block shouldn't be present both in
// pending list and in tree list
if (!blk->used) {
assert(foundTree || foundPending); // Block is free. Should be somewhere
} else
assert(!foundTree && !foundPending); // Block is not free. Should not be in free lists
#endif
prev = blk;
if (blk->last) break;
}
}
lock.leave();
#endif
return true;
}
void MemoryPool::print_contents(IB_FILE *file, bool used_only) {
lock.enter();
for (MemoryExtent *extent = extents; extent; extent=extent->next) {
if (!used_only)
ib_fprintf(file, "EXTENT %p:\n", extent);
for (MemoryBlock *blk = (MemoryBlock *)((char*)extent+MEM_ALIGN(sizeof(MemoryExtent)));
;
blk = (MemoryBlock *)((char*)blk+MEM_ALIGN(sizeof(MemoryBlock))+blk->length))
{
void *mem = (char*)blk + MEM_ALIGN(sizeof(MemoryBlock));
if (blk->used && (blk->type>0 || !used_only)) {
#ifdef DEBUG_GDS_ALLOC
2003-01-20 09:40:02 +01:00
if (blk->type > 0)
ib_fprintf(file, "Block %p: size=%d allocated at %s:%d\n",
mem, blk->length, blk->file, blk->line);
2003-01-20 09:40:02 +01:00
else if (blk->type == 0)
ib_fprintf(file, "Typed block %p: type=%d size=%d allocated at %s:%d\n",
mem, blk->type, blk->length, blk->file, blk->line);
2003-01-20 09:40:02 +01:00
else
ib_fprintf(file, "Typed block %p: type=%d size=%d\n",
mem, blk->type, blk->length);
#else
if (blk->type)
ib_fprintf(file, "Typed block %p: type=%d size=%d\n", mem, blk->type, blk->length);
else
ib_fprintf(file, "Block %p: size=%d\n", mem, blk->length);
#endif
} else {
if (!used_only)
ib_fprintf(file, "Free block %p: size=%d\n", mem, blk->length);
}
if (blk->last) break;
2002-12-16 19:33:54 +01:00
}
}
lock.leave();
2002-12-16 19:33:54 +01:00
}
MemoryPool* MemoryPool::internal_create(size_t instance_size, int *cur_mem, int *max_mem) {
size_t alloc_size = FB_MAX(
// This is the exact initial layout of memory pool in the first extent //
MEM_ALIGN(sizeof(MemoryExtent)) +
MEM_ALIGN(sizeof(MemoryBlock)) +
MEM_ALIGN(instance_size) +
MEM_ALIGN(sizeof(MemoryBlock)) +
MEM_ALIGN(sizeof(FreeBlocksTree::ItemList)) +
MEM_ALIGN(sizeof(MemoryBlock)) +
ALLOC_ALIGNMENT,
// ******************************************************************* //
MIN_EXTENT_SIZE);
char* mem = (char *)external_alloc(alloc_size);
if (!mem) pool_out_of_memory();
((MemoryExtent *)mem)->next = NULL;
2002-12-16 19:33:54 +01:00
MemoryPool* pool = new(mem +
MEM_ALIGN(sizeof(MemoryExtent)) +
MEM_ALIGN(sizeof(MemoryBlock)))
2002-12-16 19:33:54 +01:00
MemoryPool(mem, mem +
MEM_ALIGN(sizeof(MemoryExtent)) +
MEM_ALIGN(sizeof(MemoryBlock)) +
MEM_ALIGN(instance_size) +
MEM_ALIGN(sizeof(MemoryBlock)),
cur_mem, max_mem);
pool->extents_memory = alloc_size - MEM_ALIGN(sizeof(MemoryExtent));
MemoryBlock *poolBlk = (MemoryBlock*) (mem+MEM_ALIGN(sizeof(MemoryExtent)));
2002-12-16 19:33:54 +01:00
poolBlk->pool = pool;
poolBlk->used = true;
poolBlk->last = false;
poolBlk->type = TYPE_POOL;
poolBlk->length = MEM_ALIGN(instance_size);
2002-12-16 19:33:54 +01:00
poolBlk->prev = NULL;
2002-12-16 19:33:54 +01:00
MemoryBlock *hdr = (MemoryBlock*) (mem +
MEM_ALIGN(sizeof(MemoryExtent)) +
MEM_ALIGN(sizeof(MemoryBlock)) +
MEM_ALIGN(instance_size));
hdr->pool = pool;
hdr->used = true;
hdr->last = false;
hdr->type = TYPE_LEAFPAGE;
hdr->length = MEM_ALIGN(sizeof(FreeBlocksTree::ItemList));
2002-12-16 19:33:54 +01:00
hdr->prev = poolBlk;
MemoryBlock *blk = (MemoryBlock *)(mem +
MEM_ALIGN(sizeof(MemoryExtent)) +
MEM_ALIGN(sizeof(MemoryBlock)) +
MEM_ALIGN(instance_size) +
MEM_ALIGN(sizeof(MemoryBlock)) +
MEM_ALIGN(sizeof(FreeBlocksTree::ItemList)));
2002-12-16 19:33:54 +01:00
int blockLength = alloc_size -
MEM_ALIGN(sizeof(MemoryExtent)) -
MEM_ALIGN(sizeof(MemoryBlock)) -
MEM_ALIGN(instance_size) -
MEM_ALIGN(sizeof(MemoryBlock)) -
MEM_ALIGN(sizeof(FreeBlocksTree::ItemList)) -
MEM_ALIGN(sizeof(MemoryBlock));
blk->pool = pool;
blk->used = false;
blk->last = true;
blk->type = 0;
blk->length = blockLength;
blk->prev = hdr;
BlockInfo temp = {blk, blockLength};
pool->freeBlocks.add(temp);
pool->updateSpare();
return pool;
}
void MemoryPool::deletePool(MemoryPool* pool) {
2003-01-21 13:19:32 +01:00
/* dimitr: I think we need an abstract base class or a global macro
in locks.h to avoid these architecture checks. */
#ifdef SUPERSERVER
pool->lock.~Spinlock();
#else
pool->lock.~SharedSpinlock();
#endif
if (pool->cur_memory) *pool->cur_memory -= pool->used_memory;
// Delete all extents now
MemoryExtent *temp = pool->extents;
while (temp) {
MemoryExtent *next = temp->next;
external_free(temp);
temp = next;
}
}
void* MemoryPool::internal_alloc(size_t size, SSHORT type
#ifdef DEBUG_GDS_ALLOC
, char* file, int line
#endif
) {
// Lookup a block greater or equal than size in freeBlocks tree
size = MEM_ALIGN(size);
BlockInfo temp = {NULL, size};
MemoryBlock* blk;
if (freeBlocks.locate(locGreatEqual,temp)) {
// Found large enough block
BlockInfo* current = &freeBlocks.current();
if (current->length-size < MEM_ALIGN(sizeof(MemoryBlock))+ALLOC_ALIGNMENT) {
blk = current->block;
// Block is small enough to be returned AS IS
blk->used = true;
blk->type = type;
#ifdef DEBUG_GDS_ALLOC
blk->file = file;
blk->line = line;
#endif
freeBlocks.fastRemove();
} else {
// Cut a piece at the end of block in hope to avoid structural
// modification of free blocks tree
current->block->length -= MEM_ALIGN(sizeof(MemoryBlock))+size;
blk = (MemoryBlock *)((char*)current->block +
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 + 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;
else {
// Tree needs to be modified structurally
2002-12-16 19:33:54 +01:00
#ifdef NDEBUG
freeBlocks.getNext();
#else
bool res = freeBlocks.getNext();
assert(res);
assert(&freeBlocks.current()==current);
2002-12-16 19:33:54 +01:00
#endif
MemoryBlock *block = current->block;
freeBlocks.fastRemove();
addFreeBlock(block);
}
}
} 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-MEM_ALIGN(sizeof(MemoryBlock)));
if (temp->length >= size) {
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;
// We can do this w/o any locking because
// (1) -= integer operation is atomic on all current platforms
// (2) nobody will die if max_memory will be a little inprecise
used_memory += temp->length + MEM_ALIGN(sizeof(MemoryBlock));
if (cur_memory) {
*cur_memory += temp->length + MEM_ALIGN(sizeof(MemoryBlock));
if (max_memory && *max_memory < *cur_memory) *max_memory = *cur_memory;
}
PATTERN_FILL(itr,size,ALLOC_PATTERN);
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 -= MEM_ALIGN(sizeof(MemoryBlock))+size;
blk = (MemoryBlock *)((char*)temp +
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 + MEM_ALIGN(sizeof(MemoryBlock)) + blk->length))->prev = blk;
used_memory += blk->length + MEM_ALIGN(sizeof(MemoryBlock));
if (cur_memory) {
*cur_memory += blk->length + MEM_ALIGN(sizeof(MemoryBlock));
if (max_memory && *max_memory < *cur_memory) *max_memory = *cur_memory;
}
void *result = (char *)blk + MEM_ALIGN(sizeof(MemoryBlock));
PATTERN_FILL(result,size,ALLOC_PATTERN);
return result;
}
}
prev = itr;
itr = itr->next;
}
// No large enough block found. We need to extend the pool
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) {
return NULL;
}
extents_memory += alloc_size - MEM_ALIGN(sizeof(MemoryExtent));
extent->next = extents;
extents = extent;
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-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 - 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 + MEM_ALIGN(sizeof(MemoryBlock)) + size);
rest->pool = this;
rest->used = false;
rest->last = true;
rest->length = alloc_size - MEM_ALIGN(sizeof(MemoryExtent)) -
MEM_ALIGN(sizeof(MemoryBlock)) - size - MEM_ALIGN(sizeof(MemoryBlock));
rest->prev = blk;
addFreeBlock(rest);
}
}
used_memory += blk->length + MEM_ALIGN(sizeof(MemoryBlock));
if (cur_memory) {
*cur_memory += blk->length + MEM_ALIGN(sizeof(MemoryBlock));
if (max_memory && *max_memory < *cur_memory) *max_memory = *cur_memory;
}
void *result = (char*)blk+MEM_ALIGN(sizeof(MemoryBlock));
// Grow spare blocks pool if necessary
PATTERN_FILL(result,size,ALLOC_PATTERN);
return result;
}
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+
MEM_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+MEM_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
}
}
}
void MemoryPool::free_blk_extent(MemoryBlock *blk) {
MemoryExtent *extent = (MemoryExtent *)((char *)blk-MEM_ALIGN(sizeof(MemoryExtent)));
MemoryExtent *itr = extents;
if (extents == extent)
extents = extents->next;
else
{
while ( itr ) {
MemoryExtent *next = itr->next;
if (next==extent) {
itr->next = extent->next;
break;
}
itr = next;
}
assert(itr); // We had to find it somewhere
}
extents_memory -= blk->length + MEM_ALIGN(sizeof(MemoryBlock));
external_free(extent);
}
void MemoryPool::deallocate(void *block) {
if (!block) return;
lock.enter();
MemoryBlock *blk = (MemoryBlock *)((char*)block - MEM_ALIGN(sizeof(MemoryBlock))), *prev;
assert(blk->used);
assert(blk->pool==this);
used_memory -= blk->length + MEM_ALIGN(sizeof(MemoryBlock));
if (cur_memory) *cur_memory -= blk->length + MEM_ALIGN(sizeof(MemoryBlock));
// Try to merge block with preceding free block
if ((prev = blk->prev) && !prev->used) {
removeFreeBlock(prev);
prev->length += blk->length + MEM_ALIGN(sizeof(MemoryBlock));
MemoryBlock *next = NULL;
if (blk->last) {
prev->last = true;
} else {
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 + MEM_ALIGN(sizeof(MemoryBlock));
prev->last = next->last;
if (!next->last)
((MemoryBlock *)((char *)next+MEM_ALIGN(sizeof(MemoryBlock))+next->length))->prev = prev;
}
}
PATTERN_FILL((char*)prev+MEM_ALIGN(sizeof(MemoryBlock)),prev->length,FREE_PATTERN);
if (!prev->prev && prev->last)
free_blk_extent(prev);
else
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+MEM_ALIGN(sizeof(MemoryBlock))+blk->length))->used)
{
removeFreeBlock(next);
blk->length += next->length + MEM_ALIGN(sizeof(MemoryBlock));
blk->last = next->last;
if (!next->last)
((MemoryBlock *)((char *)next+MEM_ALIGN(sizeof(MemoryBlock))+next->length))->prev = blk;
}
PATTERN_FILL(block,blk->length,FREE_PATTERN);
if (!blk->prev && blk->last)
free_blk_extent(blk);
else
addFreeBlock(blk);
}
if (needSpare) updateSpare();
lock.leave();
2003-01-10 13:27:57 +01:00
}
} /* namespace Firebird */
#ifndef TESTING_ONLY
Firebird::MemoryPool* getDefaultMemoryPool() {
if (!Firebird::processMemoryPool) Firebird::processMemoryPool = MemoryPool::createPool();
return Firebird::processMemoryPool;
}
extern "C" {
#ifdef DEBUG_GDS_ALLOC
void* API_ROUTINE gds__alloc_debug(SLONG size_request,
TEXT* filename,
ULONG lineno)
{
return Firebird::processMemoryPool->allocate(size_request, 0, filename, lineno);
// return Firebird::processMemoryPool->calloc(size_request, 0, filename, lineno);
}
#else
void* API_ROUTINE gds__alloc(SLONG size_request)
{
return Firebird::processMemoryPool->allocate(size_request);
// return Firebird::processMemoryPool->calloc(size_request);
}
#endif
ULONG API_ROUTINE gds__free(void* blk) {
Firebird::processMemoryPool->deallocate(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
if (!Firebird::processMemoryPool) Firebird::processMemoryPool = MemoryPool::createPool();
// return Firebird::processMemoryPool->calloc(s, 0
return Firebird::processMemoryPool->allocate(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
if (!Firebird::processMemoryPool) Firebird::processMemoryPool = MemoryPool::createPool();
// return Firebird::processMemoryPool->calloc(s, 0
return Firebird::processMemoryPool->allocate(s, 0
#ifdef DEBUG_GDS_ALLOC
,__FILE__,__LINE__
#endif
);
}
void operator delete(void* mem) throw() {
Firebird::MemoryPool::globalFree(mem);
}
void operator delete[](void* mem) throw() {
Firebird::MemoryPool::globalFree(mem);
}
#endif