SYBASE數據訪問接口CTLIB簡單的內存池分配

自己爲了寫SYBASE數據訪問接口CTLIB的時候編寫的一個類似的內存池管理,方便數據庫那種只向前
訪問方式的內存分配,避免內存平凡分配開銷。

//
// All Rights Reserved
//
// Author:lwx  Email: [email protected]
//
// 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_)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章