mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 23:23:04 +01:00
Memory pages manager
This commit is contained in:
parent
9938e3d01b
commit
4b5428f833
@ -32,15 +32,21 @@
|
||||
* Contributor(s):
|
||||
*
|
||||
*
|
||||
* $Id: alloc.cpp,v 1.38 2004-02-20 06:42:35 robocop Exp $
|
||||
* $Id: alloc.cpp,v 1.39 2004-03-01 03:18:42 skidder Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../include/firebird.h"
|
||||
#include "alloc.h"
|
||||
#ifdef HAVE_MMAP
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
// Size in bytes, must be aligned according to ALLOC_ALIGNMENT
|
||||
#define MIN_EXTENT_SIZE 16384
|
||||
// It should also be a multiply of page size
|
||||
const size_t MIN_EXTENT_SIZE = 16384;
|
||||
// We cache this amount of extents to avoid memory mapping overhead
|
||||
const int MAP_CACHE_SIZE = 64;
|
||||
|
||||
#define FB_MAX(M,N) ((M)>(N)?(M):(N))
|
||||
|
||||
@ -48,9 +54,9 @@
|
||||
#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)
|
||||
# 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)
|
||||
# define PATTERN_FILL(ptr,size,pattern) ((void)0)
|
||||
#endif
|
||||
|
||||
// TODO (in order of importance):
|
||||
@ -121,13 +127,73 @@ void MemoryPool::updateSpare() {
|
||||
} while (needSpare);
|
||||
}
|
||||
|
||||
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
|
||||
# define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_MMAP) && !defined(MAP_ANONYMOUS)
|
||||
static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
|
||||
#endif
|
||||
|
||||
#if defined(WIN_NT) || defined(HAVE_MMAP)
|
||||
static Firebird::Vector<void*, MAP_CACHE_SIZE> extents_cache;
|
||||
static Mutex cache_mutex;
|
||||
#endif
|
||||
|
||||
void* MemoryPool::external_alloc(size_t size) {
|
||||
// This method is assumed to return NULL in case it cannot alloc
|
||||
#if defined(WIN_NT) || defined(HAVE_MMAP)
|
||||
if (size == MIN_EXTENT_SIZE) {
|
||||
cache_mutex.enter();
|
||||
void* result = NULL;
|
||||
if (extents_cache.getCount()) {
|
||||
// Use recently used object object to encourage caching
|
||||
result = extents_cache[extents_cache.getCount()-1];
|
||||
extents_cache.shrink(extents_cache.getCount()-1);
|
||||
}
|
||||
cache_mutex.leave();
|
||||
if (result) return result;
|
||||
}
|
||||
#endif
|
||||
#if defined WIN_NT
|
||||
return VirtualAlloc(NULL, size, MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
#elif defined HAVE_MMAP
|
||||
# ifdef MAP_ANONYMOUS
|
||||
return mmap(NULL, size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
# else
|
||||
// This code is needed for Solaris 2.6, AFAIK
|
||||
if (dev_zero_fd < 0) dev_zero_fd = open("/dev/zero", O_RDWR);
|
||||
return mmap(NULL, size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, dev_zero_fd, 0);
|
||||
# endif
|
||||
#else
|
||||
return malloc(size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MemoryPool::external_free(void *blk) {
|
||||
void MemoryPool::external_free(void *blk, size_t size) {
|
||||
#if defined(WIN_NT) || defined(HAVE_MMAP)
|
||||
if (size == MIN_EXTENT_SIZE) {
|
||||
cache_mutex.enter();
|
||||
if (extents_cache.getCount() < extents_cache.getCapacity()) {
|
||||
extents_cache.add(blk);
|
||||
cache_mutex.leave();
|
||||
return;
|
||||
}
|
||||
cache_mutex.leave();
|
||||
}
|
||||
#endif
|
||||
#if defined WIN_NT
|
||||
if (!VirtualFree(blk, 0, MEM_RELEASE))
|
||||
system_call_failed::raise("VirtualFree");
|
||||
#elif defined HAVE_MMAP
|
||||
if (munmap(blk, size))
|
||||
system_call_failed::raise("munmap");
|
||||
#else
|
||||
::free(blk);
|
||||
#endif
|
||||
}
|
||||
|
||||
void* MemoryPool::tree_alloc(size_t size) {
|
||||
@ -192,7 +258,7 @@ bool MemoryPool::verify_pool() {
|
||||
;
|
||||
blk = (MemoryBlock *)((char*)blk+MEM_ALIGN(sizeof(MemoryBlock))+blk->length))
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
# ifndef NDEBUG
|
||||
fb_assert(blk->pool == this); // Pool is correct ?
|
||||
fb_assert(blk->prev == prev); // Prev is correct ?
|
||||
BlockInfo temp = {blk, blk->length};
|
||||
@ -210,7 +276,7 @@ bool MemoryPool::verify_pool() {
|
||||
}
|
||||
else
|
||||
fb_assert(!foundTree && !foundPending); // Block is not free. Should not be in free lists
|
||||
#endif
|
||||
# endif
|
||||
prev = blk;
|
||||
if (blk->last) break;
|
||||
}
|
||||
@ -277,6 +343,7 @@ MemoryPool* MemoryPool::internal_create(size_t instance_size, int *cur_mem, int
|
||||
char* mem = (char *)external_alloc(alloc_size);
|
||||
if (!mem) pool_out_of_memory();
|
||||
((MemoryExtent *)mem)->next = NULL;
|
||||
((MemoryExtent *)mem)->extent_size = alloc_size;
|
||||
MemoryPool* pool = new(mem +
|
||||
MEM_ALIGN(sizeof(MemoryExtent)) +
|
||||
MEM_ALIGN(sizeof(MemoryBlock)))
|
||||
@ -335,17 +402,13 @@ MemoryPool* MemoryPool::internal_create(size_t instance_size, int *cur_mem, int
|
||||
void MemoryPool::deletePool(MemoryPool* pool) {
|
||||
/* dimitr: I think we need an abstract base class or a global macro
|
||||
in locks.h to avoid these architecture checks. */
|
||||
#ifdef MULTI_THREAD
|
||||
pool->lock.~Spinlock();
|
||||
#else
|
||||
pool->lock.~SharedSpinlock();
|
||||
#endif
|
||||
pool->lock.~Mutex();
|
||||
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);
|
||||
external_free(temp, temp->extent_size);
|
||||
temp = next;
|
||||
}
|
||||
}
|
||||
@ -483,6 +546,7 @@ void* MemoryPool::internal_alloc(size_t size, SSHORT type
|
||||
}
|
||||
extents_memory += alloc_size - MEM_ALIGN(sizeof(MemoryExtent));
|
||||
extent->next = extents;
|
||||
extent->extent_size = alloc_size;
|
||||
extents = extent;
|
||||
|
||||
blk = (MemoryBlock *)((char*)extent+MEM_ALIGN(sizeof(MemoryExtent)));
|
||||
@ -583,7 +647,7 @@ void MemoryPool::free_blk_extent(MemoryBlock *blk) {
|
||||
fb_assert(itr); // We had to find it somewhere
|
||||
}
|
||||
extents_memory -= blk->length + MEM_ALIGN(sizeof(MemoryBlock));
|
||||
external_free(extent);
|
||||
external_free(extent, extent->extent_size);
|
||||
}
|
||||
|
||||
void MemoryPool::deallocate(void *block) {
|
||||
|
@ -34,7 +34,7 @@
|
||||
* Contributor(s):
|
||||
*
|
||||
*
|
||||
* $Id: alloc.h,v 1.32 2004-02-20 06:42:35 robocop Exp $
|
||||
* $Id: alloc.h,v 1.33 2004-03-01 03:18:42 skidder Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@ -98,6 +98,7 @@ struct BlockInfo {
|
||||
|
||||
struct MemoryExtent {
|
||||
MemoryExtent *next;
|
||||
size_t extent_size; // Includes extent header size
|
||||
};
|
||||
|
||||
struct PendingFreeBlock {
|
||||
@ -133,18 +134,14 @@ private:
|
||||
Vector<void*, MAX_TREE_DEPTH + 1> spareNodes;
|
||||
bool needSpare;
|
||||
PendingFreeBlock *pendingFree;
|
||||
#ifdef MULTI_THREAD
|
||||
Spinlock lock;
|
||||
#else
|
||||
SharedSpinlock lock;
|
||||
#endif
|
||||
Mutex lock;
|
||||
int extents_memory; // Sum of memory in allocated extents minus size of extents headers
|
||||
int used_memory; // Size of used memory blocks including block headers
|
||||
|
||||
/* Returns NULL in case it cannot allocate requested chunk */
|
||||
static void* external_alloc(size_t size);
|
||||
|
||||
static void external_free(void* blk);
|
||||
static void external_free(void* blk, size_t size);
|
||||
|
||||
void* tree_alloc(size_t size);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user