自己为了写SYBASE数据访问接口CTLIB的时候编写的一个类似的内存池管理,方便数据库那种只向前
访问方式的内存分配,避免内存平凡分配开销。
//
// All Rights Reserved
//
// Author:lwx Email: linweixuangz@126.net
//
// Date: 2004.11.10
//
// DBMemPool.h: interface for the DBMemPool class.
//
#if !defined(AFX_DBMEMPOOL_H__52D62462_62E1_4DF9_90AC_7429B6CB2AF5__INCLUDED_)
#define AFX_DBMEMPOOL_H__52D62462_62E1_4DF9_90AC_7429B6CB2AF5__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <new>
#include <assert.h>
#pragma warning( disable: 4661 )
#include "SQLSyncT.h"
#include "DBExport.h"
#include "cstypes.h"
//
// DBPagePool class manage the block memory pages. default
// allocate page size is 4k(win32).
//
template <class T,class LOCK>
class DBPOOL_EXPORT DBPagePool
{
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
//
// Construction/Destruction
//
protected:
DBPagePool() : _free_pages(0), _used_pages(0),
_free_pages_begin(0), _free_pages_end(0)
{
}
virtual ~DBPagePool(){
clear();
}
public:
static DBPagePool& instance(){
if(_instance==0){
DBPoolGuard<LOCK> gurad(_lock);
if(!_instance){ // double check
_instance = new DBPagePool();
atexit(release);
}
}
return *_instance;
}
static void release(){
if(_instance)
_instance->~DBPagePool();
}
//
// default alloc 4k page block place to the page pool.
//
pointer allocate(const size_t size = 4096) {
_page_size = size;
DBPoolGuard<LOCK> gurad(_lock);
T* new_page = 0;
if(_free_pages && _free_pages_begin){
_free_pages--;
new_page = _free_pages_begin;
_free_pages_begin = (T*)(*(long*)_free_pages_begin);
memset(new_page+page_reserv_size(),0,
(size_t)(size * sizeof(T))-page_reserv_size());
}else{
set_new_handler(0);
new_page = (T*) (::operator new((size_t)size * sizeof(T)));
if (new_page == 0) {
printf("out of memory/n");
throw;
}
memset(new_page,0,size * sizeof(T));
}
_used_pages++;
//((T*)(*new_page)) = 0; // init by memeset
return new_page;
}
//
// only put the page pointer to end of page pool.
//
void deallocate(const pointer p) {
DBPoolGuard<LOCK> gurad(_lock);
*reinterpret_cast<long*>(p) = 0;
if(_free_pages==0){
_free_pages_begin = _free_pages_end = p;
}else{
*(long*)_free_pages_end = (long)p;
_free_pages_end = p;
}
_used_pages--;
_free_pages++;
}
//
// release all page memory block in the page pool.
//
void clear(){
DBPoolGuard<LOCK> gurad(_lock);
if(_free_pages || _free_pages_begin) {
T* next = 0;
while(_free_pages_begin){
next = (T*)(*(long*)_free_pages_begin);
delete [] (_free_pages_begin);
_free_pages_begin = next;
}
}
_used_pages = 0;
_free_pages = 0;
_free_pages_begin = 0;
_free_pages_end = 0;
}
pointer address(reference x) {
return (pointer)&x;
}
const_pointer const_address(const_reference x) {
return (const_pointer)&x;
}
static size_type init_page_size() {
return _page_size;
}
static size_type page_reserv_size() {
return sizeof(T*);
}
static size_type page_capcity() {
return _page_size-sizeof(T*);
}
size_t free_pages() const{
return _free_pages;
}
size_t used_pages() const{
return _used_pages;
}
T* begin() const{
return _free_pages_begin;
}
T* end() const{
return _free_pages_end;
}
private:
static size_t _page_size;
volatile size_t _free_pages;
volatile size_t _used_pages;
size_t _reserv_size;
T* _free_pages_begin;
T* _free_pages_end;
static LOCK _lock;
static DBPagePool<T,LOCK>* _instance;
};
//
// DBColumnDataPool class manage the table row fileds
// it can use as line buffer.
//
// Row | ..... | ...... | ...... | ...... | ...... |
// Row | field | field2 | field3 | field4 | field4 |
// Row | ..... | ...... | ...... | ...... | ...... |
//
// field is pointer, it point to column_data structure.
// include the field's value buffer pointer and length.
//
template <class T,class LOCK>
class DBPOOL_EXPORT DBColumnDataPool
{
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef DBPagePool<T,LOCK> pool_type;
//
// Define structure row info
//
typedef struct column_data
{
T* value;
size_type valuelen;
short isNull;
char* cloneValue(){
char* v = new T[valuelen];
memcpy(v,value,valuelen*sizeof(T));
return v;
}
};
typedef column_data* column_pointer;
typedef const column_data& const_column_reference;
//
// Construction/Destruction
//
DBColumnDataPool() : _page_begin(0), _page_end(0),
_used_pages(0), _column_count(0),_remain_inpage(0),
_column_inrow(0),_row_size(0),_rows_inpage(0)
{}
virtual ~DBColumnDataPool() { clear(); }
// here assume the row's column size is fixed
column_pointer allocate(const size_t column) {
// not support above 255 columns table.
assert(column<255 && column>0);
if(!_column_inrow) _column_inrow = column;
assert(_column_inrow==column);
DBPoolGuard<LOCK> gurad(_lock);
size_t offset_size = 0;
size_t acquire_size = column*sizeof(column_data);
_row_size = acquire_size;
if(_remain_inpage<acquire_size){
T* new_page = pool_type::instance().allocate();
*reinterpret_cast<long*>(new_page) = 0;
_remain_inpage = pool_type::page_capcity();
if(_page_begin==0)
_page_begin = _page_end = new_page;
else
*(long*)_page_end = (long)new_page;
_page_end = new_page;
_used_pages++;
offset_size=pool_type::page_reserv_size();
}else{
offset_size = pool_type::init_page_size() - _remain_inpage;
}
_column_count += column;
_remain_inpage-=acquire_size;
return reinterpret_cast<column_data*>(_page_end+offset_size);
}
void deallocate(const pointer p) {
}
T* begin_page() const{
return _page_begin;
}
T* end_page() const{
return _page_begin;
}
size_t used_pages() const{
return _used_pages;
}
size_t size() const{
return _column_count;
}
size_t column_num() const {
return _column_inrow;
}
size_t row_num() const {
return _column_count/_column_inrow;
}
void clear(){
DBPoolGuard<LOCK> gurad(_lock);
T* next = 0;
while(_page_begin && _used_pages){
next = (T*)(*(long*)_page_begin);
pool_type::instance().deallocate(_page_begin);
_page_begin = next;
_used_pages--;
}
_used_pages = 0;
_column_count = 0;
_remain_inpage = 0;
_page_begin = _page_end = 0;
}
// the operator not for row locate
column_pointer operator [](const size_t column){
DBPoolGuard<LOCK> gurad(_lock);
size_t cols_inpage = pool_type::page_capcity()/sizeof(column_data);
size_t page_off = column/cols_inpage;
size_t col_off = column%cols_inpage;
if(page_off>_used_pages && page_off > 0){
printf("out of used pages range./n");
throw;
}
T* page_ptr = _page_begin;
T* next_ptr = 0;
size_t page_count = 0;
while(page_ptr){
next_ptr = (T*)(*(long*)page_ptr);
if(page_count++ == page_off)
break;
page_ptr = next_ptr;
}
return (column_pointer)(page_ptr+pool_type::page_reserv_size()+
col_off*sizeof(column_data));
}
column_pointer row_at(const size_t row_at){
DBPoolGuard<LOCK> gurad(_lock);
size_t rows_inpage = pool_type::page_capcity()/_row_size;
size_t page_off = row_at/rows_inpage;
size_t row_off = row_at%rows_inpage;
if(page_off>_used_pages && page_off > 0){
printf("out of used pages range./n");
throw;
}
T* page_ptr = _page_begin;
T* next_ptr = 0;
size_t page_count = 0;
while(page_ptr){
next_ptr = (T*)(*(long*)page_ptr);
if(page_count++ == page_off)
break;
page_ptr = next_ptr;
}
return (column_pointer)(page_ptr+pool_type::page_reserv_size()+
row_off*_row_size);
}
// Iterator
struct _Col;
friend struct _Col;
typedef T* _Nodeptr;
struct _Col {
static _Nodeptr next(_Nodeptr& _P,_Nodeptr& _F){
if(_F+sizeof(column_data) > _P+
pool_type::init_page_size())
{
_P = (_Nodeptr)(*(long*)_P);
_F = _P + pool_type::page_reserv_size();
return ((_Nodeptr)_F);
}
_F+=sizeof(column_data);
return ((_Nodeptr)_F);
}
static _Nodeptr prev(_Nodeptr& _P,_Nodeptr& _F){
if(_F-sizeof(column_data) < _P){
_P = (_Nodeptr)(*(long*)_P);
_F = _P + pool_type::page_reserv_size();
return ((_Nodeptr)_F);
}
_F-=sizeof(column_data);
return ((_Nodeptr)_F);
}
static _Nodeptr value(_Nodeptr& _P,_Nodeptr& _F){
return ((_Nodeptr)_F);
}
};
class iterator;
class const_iterator;
friend class const_iterator;
class const_iterator
{
public:
const_iterator()
: _Ptr(0),_Off(0) {}
const_iterator(_Nodeptr _P)
: _Ptr(_P),_Off(_P+pool_type::page_reserv_size())
{
//printf("Ptr:0x%x,Off:0x%x/n",_Ptr,_Off);
}
const_iterator(_Nodeptr _P,_Nodeptr _F)
: _Ptr(_P),_Off(_F) {}
const_iterator(const iterator& _X)
: _Ptr(_X._Ptr),_Off(_X._Off) {}
const_reference operator*() const
{return (const_reference)_Ptr; }
const_pointer operator->() const
{return (&**this); }
const_iterator& operator++()
{_Off = _Col::next(_Ptr,_Off);
return (*this); }
const_iterator operator++(int)
{const_iterator _Tmp = *this;
++*this;
return (_Tmp); }
const_iterator& operator--()
{_Off = _Col::prev(_Ptr,_Off);
return (*this); }
const_iterator operator--(int)
{const_iterator _Tmp = *this;
--*this;
return (_Tmp); }
bool operator==(const const_iterator& _X) const
{return (_Ptr == _X._Ptr && _Off == _X._Off); }
bool operator!=(const const_iterator& _X) const
{return (!(*this == _X)); }
protected:
_Nodeptr _Ptr;
_Nodeptr _Off;
};
friend class iterator;
class iterator : public const_iterator {
public:
iterator()
: const_iterator() {}
iterator(_Nodeptr _P)
: const_iterator(_P) {}
iterator(_Nodeptr _P,_Nodeptr _F)
: const_iterator(_P,_F) {}
column_pointer operator*()
{return reinterpret_cast<column_pointer>(_Col::value(_Ptr,_Off)); }
pointer operator->() const
{return (&**this); }
iterator& operator++()
{_Off = _Col::next(_Ptr,_Off);
return (*this); }
iterator operator++(int)
{iterator _Tmp = *this;
++*this;
return (_Tmp); }
iterator& operator--()
{_Off = _Col::prev(_Ptr,_Off);
return (*this); }
iterator operator--(int)
{iterator _Tmp = *this;
--*this;
return (_Tmp); }
bool operator==(const iterator& _X) const
{return (_Ptr == _X._Ptr && _Off == _X._Off); }
bool operator!=(const iterator& _X) const
{return (!(*this == _X)); }
};
// Iterators
iterator begin(){
return (iterator(_page_begin));
}
const_iterator begin() const{
return (const_iterator(_page_begin));
}
iterator end (){
size_t cols_inpage = pool_type::page_capcity()/sizeof(column_data);
size_t byte_off = _column_count%cols_inpage;
return (iterator(_page_end,_page_end+byte_off*sizeof(column_data)+
pool_type::page_reserv_size()));
}
const_iterator end () const{
size_t cols_inpage = pool_type::page_capcity()/sizeof(column_data);
size_t byte_off = _column_count%cols_inpage;
return (const_iterator(_page_end,_page_end+byte_off*sizeof(column_data)+
pool_type::page_reserv_size()));
}
protected:
T* _page_begin; /*fisrt used page pointer*/
T* _page_end; /*last used page pointer*/
size_t _row_size; /*size of one rows */
size_t _rows_inpage; /*rows in a page*/
volatile size_t _used_pages; /*current used page numbers*/
volatile size_t _column_count; /*current allocated columns*/
size_t _column_inrow; /*current allocated columns*/
size_t _remain_inpage; /*current remain number in page*/
LOCK _lock;
};
template <class T,class LOCK>
class DBPOOL_EXPORT DBRowSetPool : public DBColumnDataPool<T,LOCK>
{
public:
typedef DBColumnDataPool<T,LOCK> BaseClass;
typedef DBColumnDataPool<T,LOCK>::column_data* column_pointer;
typedef const column_data& const_column_reference;
//
// Construction/Destruction
//
DBRowSetPool() : DBColumnDataPool<T,LOCK>() {}
virtual ~DBRowSetPool() { clear(); }
size_t size() const{
return _column_count/_column_inrow;
}
column_pointer operator [](const size_t row){
BaseClass *base = dynamic_cast<BaseClass*>(this);
return base->row_at(row);
}
struct _Row;
friend struct _Row;
typedef T* _Nodeptr;
struct _Row {
static _Nodeptr next(_Nodeptr& _P,_Nodeptr& _F,size_t& _N){
//printf("_F:0x%x, _P:0x%x, _E:0x%x/n",_F,_P,_P+pool_type::init_page_size());
//printf("_N:0x%x, size=%d/n",_F+sizeof(column_data)*_N,sizeof(column_data)*_N);
if(_F+_N*2 > _P+pool_type::init_page_size())
{
_P = (_Nodeptr)(*(long*)_P);
_F = _P + pool_type::page_reserv_size();
return ((_Nodeptr)_F);
}
_F+=_N;
return ((_Nodeptr)_F);
}
static _Nodeptr prev(_Nodeptr& _P,_Nodeptr& _F){
if(_F-sizeof(column_data)*_N < _P){
_P = (_Nodeptr)(*(long*)_P);
_F = _P + pool_type::page_reserv_size();
return ((_Nodeptr)_F);
}
_F-=_N;
return ((_Nodeptr)_F);
}
static _Nodeptr value(_Nodeptr& _P,_Nodeptr& _F){
return ((_Nodeptr)_F);
}
};
class const_iterator
{
public:
const_iterator()
: _Ptr(0),_Off(0),_Num(0) {}
const_iterator(_Nodeptr _P,size_t _N)
: _Ptr(_P),_Off(_P+pool_type::page_reserv_size()),_Num(_N)
{
//printf("Ptr:0x%x,Off:0x%x/n",_Ptr,_Off);
}
const_iterator(_Nodeptr _P,_Nodeptr _F,size_t _N)
: _Ptr(_P),_Off(_F),_Num(_N)
{
//printf("Ptr:0x%x,Off:0x%x/n",_Ptr,_Off);
}
const_iterator(const iterator& _X)
: _Ptr(_X._Ptr),_Off(_X._Off),_Num(_X._Num) {}
const_reference operator*() const
{return (const_reference)_Ptr; }
const_pointer operator->() const
{return (&**this); }
const_iterator& operator++()
{_Off = _Row::next(_Ptr,_Off,_Num);
return (*this); }
const_iterator operator++(int)
{const_iterator _Tmp = *this;
++*this;
return (_Tmp); }
const_iterator& operator--()
{_Off = _Row::prev(_Ptr,_Off,_Num);
return (*this); }
const_iterator operator--(int)
{const_iterator _Tmp = *this;
--*this;
return (_Tmp); }
bool operator==(const const_iterator& _X) const
{return (_Ptr == _X._Ptr && _Off == _X._Off); }
bool operator!=(const const_iterator& _X) const
{return (!(*this == _X)); }
protected:
_Nodeptr _Ptr;
_Nodeptr _Off;
size_t _Num;
};
friend class iterator;
class iterator : public const_iterator {
public:
iterator()
: const_iterator() {}
iterator(_Nodeptr _P,size_t _N)
: const_iterator(_P,_N) {}
iterator(_Nodeptr _P,_Nodeptr _F,size_t _N)
: const_iterator(_P,_F,_N) {}
column_pointer operator*()
{return reinterpret_cast<column_pointer>(_Row::value(_Ptr,_Off)); }
pointer operator->() const
{return (&**this); }
iterator& operator++()
{_Off = _Row::next(_Ptr,_Off,_Num);
return (*this); }
iterator operator++(int)
{iterator _Tmp = *this;
++*this;
return (_Tmp); }
iterator& operator--()
{_Off = _Row::prev(_Ptr,_Off,_Num);
return (*this); }
iterator operator--(int)
{iterator _Tmp = *this;
--*this;
return (_Tmp); }
bool operator==(const iterator& _X) const
{
//printf("Ptr:0x%x,Off:0x%x/n",_Ptr,_Off);
return (_Ptr == _X._Ptr && _Off == _X._Off);
}
bool operator!=(const iterator& _X) const
{return (!(*this == _X)); }
};
// Iterators
iterator begin(){
return (iterator(_page_begin,_row_size));
}
const_iterator begin() const{
return (const_iterator(_page_begin,_row_size));
}
iterator end (){
size_t rows_inpage = pool_type::page_capcity()/_row_size;
size_t row_off = _column_count%rows_inpage;
assert(row_off>=_column_inrow);
return (iterator(_page_end,
_page_end+pool_type::page_reserv_size()+row_off*_row_size,
_row_size));
}
const_iterator end () const{
size_t rows_inpage = pool_type::page_capcity()/_row_size;
size_t row_off = _column_count%rows_inpage;
assert(row_off>=_column_inrow);
return (iterator(_page_end,
_page_end+pool_type::page_reserv_size()+row_off*_row_size,
_row_size));
}
};
//
// this pool only allocate table each field data buffer.
// the field is no fixed size, can be random. it always
// manage by DBColumnDataPool class.
//
template <class T,class LOCK>
class DBPOOL_EXPORT DBRowDataPool
{
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef DBPagePool<T,LOCK> pool_type;
//
// Construction/Destruction
//
DBRowDataPool() : _page_begin(0), _page_end(0),
_used_pages(0),_remain_inpage(0)
{
}
virtual ~DBRowDataPool()
{
clear();
}
//
// allocate a field size buffer in page pool.
//
pointer allocate(const size_t len) {
// not support over 4k data length.
assert(len<pool_type::page_capcity());
DBPoolGuard<LOCK> gurad(_lock);
if(_remain_inpage<len){
T* new_page = pool_type::instance().allocate();
*reinterpret_cast<long*>(new_page) = 0;
_remain_inpage = pool_type::page_capcity();
if(_page_begin==0)
_page_begin = _page_end = new_page;
else
*(long*)_page_end = (long)new_page;
_page_end = new_page;
_used_pages++;
}
size_t offset=pool_type::init_page_size()-_remain_inpage;
_remain_inpage-=len;
return _page_end+offset;
}
//
// here not need release a field buffer by allocate
// function. it will be free in clear function.
//
void deallocate(const pointer p) {
}
size_t used_pages() const{
return _used_pages;
}
T* begin() const{
return _page_begin;
}
T* end() const{
return _page_begin;
}
//
// release all page use in this class.
//
void clear(){
DBPoolGuard<LOCK> gurad(_lock);
T* next = 0;
while(_page_begin){
next = (T*)(*(long*)_page_begin);
pool_type::instance().deallocate(_page_begin);
_page_begin = next;
}
_used_pages = 0;
_remain_inpage = 0;
_page_begin = _page_end = 0;
}
private:
T* _page_begin; /*fisrt used page pointer*/
T* _page_end; /*last used page pointer*/
volatile size_t _used_pages;/*current used page numbers*/
size_t _remain_inpage; /*current remain number in page*/
LOCK _lock;
};
#ifdef WIN32
template class DBPagePool<char,win32_mutex>;
template class DBRowDataPool<char,win32_mutex>;
template class DBColumnDataPool<char,win32_mutex>;
template class DBRowSetPool<char,win32_mutex>;
typedef DBPagePool<char,win32_mutex> DBPagePools;
typedef DBRowDataPool<char,win32_mutex> DBRowDataPools;
typedef DBRowSetPool<char,win32_mutex> DBRowSetPools;
typedef DBColumnDataPool<char,win32_mutex> DBColumnDataPools;
#endif
#ifdef _POSIX_THREADS
template class DBPagePool<char,pthread_mutex>;
template class DBRowDataPool<char,pthread_mutex>;
template class DBColumnDataPool<char,pthread_mutex>;
template class DBRowSetPool<char,pthread_mutex>;
typedef DBPagePool<char,pthread_mutex> DBPagePools;
typedef DBRowDataPool<char,pthread_mutex> DBRowDataPools;
typedef DBRowSetPool<char,pthread_mutex> DBRowSetPools;
typedef DBColumnDataPool<char,pthread_mutex> DBColumnDataPools;
#endif
#endif // !defined(AFX_DBMEMPOOL_H__52D62462_62E1_4DF9_90AC_7429B6CB2AF5__INCLUDED_)