最便捷的序列化方式

 

最便捷、最强大、速度最快的C++序列化框架。

 

特别注意:vc6太古老,不符合C++规范,无法使用该框架

 

1.         高性能,速度非常快,比你能找到的同类产品至少快一个数量级

2.         在网络通讯,数据库存储中非常好用。

3.         预先支持所有基本类型,所有stl容器类型(除stack/queue之外)

4.         支持变长int32/uint32/int64/uint64

5.         支持stl::pairboost::tuple

6.         可选的版本控制,而非强制

a)         对于小对象,通常不需要版本控制

b)         boost::serialization的版本号是强制的,当初我设计这个序列化框架就是因为boost不能省略版本号

7.         非侵入式设计,不污染名字空间

8.         声明式语法,简单,可靠

9.         …….

 

该框架的易用性

还是用代码说明问题最简洁,看这个例子:

 

struct MyData1

{

    int  a, b, c;

    var_int32_t d;  // d.t is int32 value

    var_uint64_t e; // d.t is uint64 value

    std::string f;

    std::map<std::string, int> g;

    std::set<int> h;

 

    // 声明序列化,无版本控制,最简洁的声明,后面几个稍微复杂点

    DATA_IO_LOAD_SAVE(MyData1, &a&b&c&d&e&f&g&h)

};

 

struct MyData2

{

    int  a, b, c;

    var_int32_t d;

    var_uint64_t e;

    std::string f;

    std::map<std::string, int> g;

    std::set<int> h;

 

    // 声明序列化,有版本控制

    DATA_IO_LOAD_SAVE_V(MyData2,

        1, // 当前版本

        &a&b&c&d&e&f&g&h

        )

};

 

struct MyData3

{

    int  a, b, c;

    boost::int32_t d;

    boost::uint64_t e;

    std::string f;

    std::map<std::string, int> g;

    std::set<int> h;

    std::multiset<int> i;

 

    unsigned version;

 

    // 声明序列化,有版本控制

    DATA_IO_LOAD_SAVE_V(MyData3,

        2, // 当前版本

        &a

        &b

        &c

        &as_var_int(d) // d 声明为int32_t, 但是作为var_int32_t 来存储

        &as_var_int(e) // e 声明为uint64_t, 但是作为var_uint64_t 来存储

        &f

        &g

        &h

        &vmg.since(2, i) // 版本2 新增了成员i

        &vmg.get_version(version) // 如果需要,将版本值存入version 成员

        )

};

 

int main(int argc, char* argv[])

{

    PortableDataOutput<AutoGrownMemIO> output;

    PortableDataInput<MemIO> input;

 

    output.resize(1024); // 可选,如果没有这一行最多就是多拷贝几次内存,相当于使用vector.reserve

 

    MyData1 d1;

    // set d1 values

    // ...

 

    MyData2 d2;

    // set d2 values

    // ...

 

    MyData3 d3;

    // set d3 values

    // ...

 

    output << d1 << d2 << d3; // 存储

 

    input.set(output.begin(), output.current());

 

    input >> d1 >> d2 >> d3; // 载入

 

//----------------------------------

 

// operator& operator<< 等效

    output & d1 & d2 & d3; // 存储

 

    input.set(output.begin(), output.current());

 

// operator& operator>> 等效

    input & d1 & d2 & d3; // 载入

}

 

模仿这段代码,可以完成大部分的现实需求,如果有更多的需求,可以使用该框架的高级功能。例如,系统中已经定义了一些数据结构,但又不能修改现有代码,怎样给它们增加序列化能力呢?请看如下代码:

 

// in system header, can not change

struct SysData1

{

    int a;

    unsigned b;

    string c;

};

 

// add these 2 function in your header

template<class DataIO>

void DataIO_saveObject(DataIO& dio, const SysData1& x)

{

    dio & x.a & x.b & x.c;

}

template<class DataIO>

void DataIO_loadObject(DataIO& dio, SysData1& x)

{

    dio & x.a & x.b & x.c;

}

 

如果现存的对象需要版本控制,参考如下代码:

 

struct SysData2

{

    int a;

    unsigned b;

    string c;

};

 

// add these 2 function in your header

template<class DataIO>

void DataIO_saveObject(DataIO& dio, const SysData2& x)

{

    const unsigned curr_version = 2;

    dio & serialize_version_t(curr_version);

    dio & x.a & x.b;

    dio & x.c;

}

template<class DataIO>

void DataIO_loadObject(DataIO& dio, SysData2& x)

{

    const unsigned curr_version = 2;

    serialize_version_t loaded_version;

    in >> loaded_version;

    if (loaded_version.t > curr_version)

    {

        throw BadVersionException(loaded_version.t, curr_version, className);

    }

    dio & x.a & x.b;

    if (loaded_version.t >= 2)

        dio & x.c;

}

 

 

 

DataIO_loadObject/DataIO_saveObject只要在调用点可见,就可以对SysData进行序列化。

因为DataIO 序列化框架使用DataIO_loadObject/DataIO_saveObject来载入和存储对象,这样做的好处有以下几点:

l  非侵入,对象类型和加载/存储函数可以分离定义

n   否则无法为不可更改代码的对象增加序列化能力

l  这两个函数可以定义在任何名字空间

n   根据C++的名字查找规则,只要在调用环境和每个参数所在的名字空间中有相应的匹配函数,就会使用该函数。我们需要有效地利用这一点。

l  DataIO_loadObject/DataIO_saveObject这两个函数名较长,并且罕见

n   因此不会与系统中的其他标识符发生冲突。(对比boost::serialization中的serialize函数,它就比较容易和其他名字发生冲突,serialize太常见了)。

 

性能

在上面的代码中可以看到几个陌生的名字:MemIO, AutoGrownMemIOPortableDataOutputPortableDataInput…

代码中没有提到MinMemIO,因为MinMemIO没有越界检查,只有在非常简单,完全可控的情况下,才能使用它。因为没有越界检查,它的性能非常好,在大多数情况下相当于手工的memcpy序列化。

使用MemIO稍微慢一点,但是有越界检查,读取时越界会抛出EndOfFileException异常,写入越界时会抛出OutOfSpaceException异常

使用AutoGrownMemIO,在save时,碰到边界会自动增加内存(相当于vector.push_back自动增加内存),也可以使用resize预先分配内存(相当于vector.reserve/resize)。

这个几个MemIO类都非常简单,速度快是很自然的。

PortableDataOutputPortableDataInput中,如果机器字节序是LittleEndian,需要交换字节序,这一点,在新版的vc中和gcc中,会直接映射到一条指令:bswap。所以也不会有性能问题。

对于var_int的存储,无符号数,每个字节包含7个有效位,余下一位表示是否需要读取下一个字节。因此0~127仅需要一个字节,0~2^14-1需要两个字节,等等。对于有符号数,最低有效位存储符号,其余位存储绝对值。所有stl容器和string的尺寸就是用var_uint32_t存储的。

该框架中,同时实现了StreamBuffer,可以为任意Stream增加一层缓冲,往缓冲里面序列化数据的效率和MemIO系列是一样的,不同之处在于当缓冲耗尽或填满时会调用真实Stream的读写方法。这比起通常很多实现中将BufferedStream作为一个抽象,在读取哪怕一个字节时也需要一个虚函数调用,速度要快得多。

扩展应用

使用该序列化框架,我实现了一个不需要IDLRPC

使用该序列化框架,对Berkeley DB进行包装,可以让它象标准容器一样使用,免除了复杂的编码。后面我会继续介绍。

=================================================================

=================================================================

 

使用前面介绍的序列化框架,可以非常简单地将Bekeley DB作为存储层,实现一个易于使用的,强类型的,持久化的map。

 

这个设计的的基本原则就是:模板作为一个薄的、类型安全的包装层,实现层的代码可以多个模板实例来公用,这样不但加快了编译时间,也减小了生成的代码尺寸。

这个实现相当于std::map<Key,Data>,但接口上也不完全相同,主要是基于易实现和性能考虑。

下一篇介绍std::map<Key1,std::map<Key2,Data> >的BerkeleyDB实现。

 

 多的不说,贴上代码。

 

file: dbmap.h

 

 

 

  1. /* vim: set tabstop=4 : */
  2. #ifndef __febird_bdb_dbmap_h__
  3. #define __febird_bdb_dbmap_h__
  4. #if defined(_MSC_VER) && (_MSC_VER >= 1020)
  5. # pragma once
  6. #endif
  7. #include <db_cxx.h>
  8. #include "native_compare.h"
  9. #include "../io/DataIO.h"
  10. #include "../io/MemStream.h"
  11. #include "../refcount.h"
  12. namespace febird {
  13. class FEBIRD_DLL_EXPORT dbmap_iterator_impl_base : public RefCounter
  14. {
  15. public:
  16.     class dbmap_base* m_owner;
  17.     DBC*  m_curp;
  18.     int   m_ret;
  19. public:
  20.     dbmap_iterator_impl_base(class dbmap_base* owner);
  21.     void init(DB* dbp, DB_TXN* txn, const char* func);
  22.     virtual ~dbmap_iterator_impl_base();
  23.     virtual void load_key(void* data, size_t size) = 0;
  24.     virtual void load_val(void* data, size_t size) = 0;
  25.     virtual void save_key(PortableDataOutput<AutoGrownMemIO>& oKey) = 0;
  26.     void advance(u_int32_t direction_flag, const char* func);
  27.     void update(const void* d, const char* func);
  28.     void remove(const char* func);
  29. };
  30. class FEBIRD_DLL_EXPORT dbmap_base
  31. {
  32.     DECLARE_NONE_COPYABLE_CLASS(dbmap_base)
  33. public:
  34.     DB*    m_db;
  35.     size_t m_bulkSize;
  36.     bt_compare_fcn_type m_bt_comp;
  37.     dbmap_base(DB_ENV* env, const char* dbname
  38.         , DB_TXN* txn
  39.         , bt_compare_fcn_type bt_comp
  40.         , const char* func
  41.         );
  42.     virtual ~dbmap_base();
  43.     virtual void save_key(PortableDataOutput<AutoGrownMemIO>& dio, const void* key) const = 0;
  44.     virtual void save_val(PortableDataOutput<AutoGrownMemIO>& dio, const void* data) const = 0;
  45.     virtual dbmap_iterator_impl_base* make_iter() = 0;
  46.     dbmap_iterator_impl_base* begin_impl(DB_TXN* txn, const char* func);
  47.     dbmap_iterator_impl_base* end_impl(DB_TXN* txn, const char* func);
  48.     dbmap_iterator_impl_base* find_impl(const void* k, DB_TXN* txn, u_int32_t flags, const char* func);
  49.     bool insert_impl(const void* k, const void* d, u_int32_t flags, DB_TXN* txn, const char* func);
  50.     bool remove_impl(const void* k, DB_TXN* txn, const char* func);
  51.     void clear_impl(DB_TXN* txn, const char* func);
  52. };
  53. template<class Key, class Val, class Value, class Impl>
  54. class dbmap_iterator :
  55.     public std::iterator<std::bidirectional_iterator_tag, Value, ptrdiff_tconst Value*, const Value&>
  56. {
  57.     boost::intrusive_ptr<Impl> m_impl;
  58.     void copy_on_write()
  59.     {
  60.         if (m_impl->getRefCount() > 1)
  61.         {
  62.             Impl* p = new Impl(m_impl->m_owner);
  63.             m_impl->m_ret = m_impl->m_curp->dup(m_impl->m_curp, &p->m_curp, DB_POSITION);
  64.             FEBIRD_RT_assert(0 == m_impl->m_ret, std::runtime_error);
  65.             m_impl.reset(p);
  66.         }
  67.     }
  68. private:
  69. #ifdef _MSC_VER
  70. //# pragma warning(disable: 4661) // declaration but not definition
  71. //! MSVC will warning C4661 "declaration but not definition"
  72. void operator++(int) { assert(0); }
  73. void operator--(int) { assert(0); }
  74. #else
  75. //! disable, because clone iterator will cause very much time and resource
  76. void operator++(int);// { assert(0); }
  77. void operator--(int);// { assert(0); }
  78. #endif
  79. public:
  80.     dbmap_iterator() {}
  81.     explicit dbmap_iterator(dbmap_iterator_impl_base* impl)
  82.         : m_impl(static_cast<Impl*>(impl))
  83.     {
  84.         assert(impl);
  85.         assert(dynamic_cast<Impl*>(impl));
  86.     }
  87. //  bool exist() const { return DB_NOTFOUND != m_impl->m_ret && DB_KEYEMPTY != m_impl->m_ret; }
  88.     bool exist() const { return 0 == m_impl->m_ret; }
  89.     void update(const Val& val) { m_impl->update(&val, BOOST_CURRENT_FUNCTION); }
  90.     void remove() { m_impl->remove(BOOST_CURRENT_FUNCTION); }
  91.     dbmap_iterator& operator++()
  92.     {
  93.         assert(0 == m_impl->m_ret);
  94.         copy_on_write();
  95.         m_impl->advance(DB_NEXT, BOOST_CURRENT_FUNCTION);
  96.         return *this;
  97.     }
  98.     dbmap_iterator& operator--()
  99.     {
  100.         assert(0 == m_impl->m_ret);
  101.         copy_on_write();
  102.         m_impl->advance(DB_PREV, BOOST_CURRENT_FUNCTION);
  103.         return *this;
  104.     }
  105.     const Value& operator*() const
  106.     {
  107.         assert(0 == m_impl->m_ret);
  108.         return m_impl->m_val;
  109.     }
  110.     const Value* operator->() const
  111.     {
  112.         assert(0 == m_impl->m_ret);
  113.         return &m_impl->m_val;
  114.     }
  115.     Value& get_mutable() const
  116.     {
  117.         assert(0 == m_impl->m_ret);
  118.         return m_impl->m_val;
  119.     }
  120. };
  121. template<class Key, class Val>
  122. class dbmap : protected dbmap_base
  123. {
  124.     DECLARE_NONE_COPYABLE_CLASS(dbmap)
  125. public:
  126.     typedef Key     key_type;
  127.     typedef std::pair<Key, Val> value_type;
  128. protected:
  129.     class dbmap_iterator_impl : public dbmap_iterator_impl_base
  130.     {
  131.     public:
  132.         value_type m_val;
  133.         dbmap_iterator_impl(dbmap_base* owner)
  134.             : dbmap_iterator_impl_base(owner)
  135.         {}
  136.         virtual void load_key(void* data, size_t size)
  137.         {
  138.             PortableDataInput<MemIO> iKey;
  139.             iKey.set(data, size);
  140.             iKey >> m_val.first;
  141.             FEBIRD_RT_assert(iKey.eof(), std::logic_error);
  142.         }
  143.         virtual void load_val(void* data, size_t size)
  144.         {
  145.             PortableDataInput<MinMemIO> iVal;
  146.             iVal.set(data);
  147.             iVal >> m_val.second;
  148.             FEBIRD_RT_assert(iVal.diff(data) == size, std::logic_error);
  149.         }
  150.         virtual void save_key(PortableDataOutput<AutoGrownMemIO>& oKey1)
  151.         {
  152.             oKey1 << m_val.first;
  153.         }
  154.     };
  155.     //! overrides
  156.     void save_key(PortableDataOutput<AutoGrownMemIO>& dio, const void* key) const { dio << *(const Key*)key; }
  157.     void save_val(PortableDataOutput<AutoGrownMemIO>& dio, const void* val) const { dio << *(const Val*)val; }
  158.     dbmap_iterator_impl_base* make_iter() { return new dbmap_iterator_impl(this); }
  159. public:
  160.     typedef dbmap_iterator<Key, Val, value_type, dbmap_iterator_impl>
  161.             iterator, const_iterator;
  162.     dbmap(DB_ENV* env, const char* dbname
  163.         , DB_TXN* txn = NULL
  164.         , bt_compare_fcn_type bt_comp = bdb_auto_bt_compare((Key*)(0))
  165.         )
  166.         : dbmap_base(env, dbname, txn, bt_comp, BOOST_CURRENT_FUNCTION)
  167.     {
  168.     }
  169.     dbmap(DbEnv* env, const char* dbname
  170.         , DbTxn* txn = NULL
  171.         , bt_compare_fcn_type bt_comp = bdb_auto_bt_compare((Key*)(0))
  172.         )
  173.         : dbmap_base(env->get_DB_ENV(), dbname, txn ? txn->get_DB_TXN() : NULL, bt_comp, BOOST_CURRENT_FUNCTION)
  174.     {
  175.     }
  176.     iterator begin(DB_TXN* txn = NULL) { return iterator(begin_impl(txn, BOOST_CURRENT_FUNCTION)); }
  177.     iterator end  (DB_TXN* txn = NULL) { return iterator(end_impl  (txn, BOOST_CURRENT_FUNCTION)); }
  178.     iterator begin(DbTxn* txn) { return iterator(begin_impl(txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION)); }
  179.     iterator end  (DbTxn* txn) { return iterator(end_impl  (txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION)); }
  180.     value_type back()
  181.     {
  182.         iterator iter = this->end();
  183.         --iter;
  184.         if (iter.exist())
  185.             return *iter;
  186.         throw std::runtime_error(BOOST_CURRENT_FUNCTION);
  187.     }
  188.     value_type front()
  189.     {
  190.         iterator iter = this->begin();
  191.         if (iter.exist())
  192.             return *iter;
  193.         throw std::runtime_error(BOOST_CURRENT_FUNCTION);
  194.     }
  195.     iterator find(const Key& k, DB_TXN* txn = NULL)
  196.     {
  197.         return iterator(find_impl(&k, txn, DB_SET, BOOST_CURRENT_FUNCTION));
  198.     }
  199.     iterator find(const Key& k, DbTxn* txn)
  200.     {
  201.         return iterator(find_impl(&k, txn ? txn->get_DB_TXN() : NULL, DB_SET, BOOST_CURRENT_FUNCTION));
  202.     }
  203.     iterator lower_bound(const Key& k, DB_TXN* txn = NULL)
  204.     {
  205.         return iterator(find_impl(&k, txn, DB_SET_RANGE, BOOST_CURRENT_FUNCTION));
  206.     }
  207.     iterator lower_bound(const Key& k, DbTxn* txn)
  208.     {
  209.         return iterator(find_impl(&k, txn ? txn->get_DB_TXN() : NULL, DB_SET_RANGE, BOOST_CURRENT_FUNCTION));
  210.     }
  211.     bool insert(const std::pair<Key,Val>& kv, DB_TXN* txn = NULL)
  212.     {
  213.         return insert_impl(&kv.first, &kv.second, DB_NOOVERWRITE, txn, BOOST_CURRENT_FUNCTION);
  214.     }
  215.     bool insert(const std::pair<Key,Val>& kv, DbTxn* txn)
  216.     {
  217.         return insert_impl(&kv.first, &kv.second, DB_NOOVERWRITE, txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION);
  218.     }
  219.     bool insert(const Key& k, const Val& d, DB_TXN* txn = NULL)
  220.     {
  221.         return insert_impl(&k, &d, DB_NOOVERWRITE, txn, BOOST_CURRENT_FUNCTION);
  222.     }
  223.     bool insert(const Key& k, const Val& d, DbTxn* txn)
  224.     {
  225.         return insert_impl(&k, &d, DB_NOOVERWRITE, txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION);
  226.     }
  227.     void replace(const std::pair<Key,Val>& kv, DB_TXN* txn = NULL)
  228.     {
  229.         insert_impl(&kv.first, &kv.second, 0, txn, BOOST_CURRENT_FUNCTION);
  230.     }
  231.     void replace(const std::pair<Key,Val>& kv, DbTxn* txn)
  232.     {
  233.         insert_impl(&kv.first, &kv.second, 0, txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION);
  234.     }
  235.     void replace(const Key& k, const Val& d, DB_TXN* txn = NULL)
  236.     {
  237.         insert_impl(&k, &d, 0, txn, BOOST_CURRENT_FUNCTION);
  238.     }
  239.     void replace(const Key& k, const Val& d, DbTxn* txn)
  240.     {
  241.         insert_impl(&k, &d, 0, txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION);
  242.     }
  243.     bool remove(const Key& k, DB_TXN* txn = NULL)
  244.     {
  245.         return remove_impl(&k, txn, BOOST_CURRENT_FUNCTION);
  246.     }
  247.     bool remove(const Key& k, DbTxn* txn)
  248.     {
  249.         return remove_impl(&k, txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION);
  250.     }
  251.     bool erase(iterator& iter)
  252.     {
  253.         return iter.remove();
  254.     }
  255.     void clear(DB_TXN* txn = NULL)
  256.     {
  257.         clear_impl(txn, BOOST_CURRENT_FUNCTION);
  258.     }
  259.     void clear(DbTxn* txn)
  260.     {
  261.         return clear_impl(txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION);
  262.     }
  263.     DB* getDB() { return m_db; }
  264.     const DB* getDB() const { return m_db; }
  265. };
  266. // namespace febird
  267. #endif // __febird_bdb_dbmap_h__

file: dbmap.cpp

 

  1. /* vim: set tabstop=4 : */
  2. #include "dbmap.h"
  3. #include <sstream>
  4. /**
  5.  @brief when iterate from end to begin
  6.  @code
  7.     for (dbmap<Key, Val>::iterator iter = dbm.end();;)
  8.     {
  9.         --iter;
  10.         if (!iter.exist()) break;
  11.         pair<Key,Val>& kv = *iter;
  12.     //  do some thing
  13.     }
  14.  @endcode
  15.  */
  16. namespace febird {
  17. dbmap_iterator_impl_base::dbmap_iterator_impl_base(class dbmap_base* owner)
  18.     : m_owner(owner)
  19.     , m_curp(0), m_ret(-1)
  20. {
  21. }
  22. void dbmap_iterator_impl_base::init(DB* dbp, DB_TXN* txn, const char* func)
  23. {
  24.     int ret = dbp->cursor(dbp, txn, &m_curp, 0);
  25.     if (0 != ret)
  26.     {
  27.         delete this;
  28.         std::ostringstream oss;
  29.         oss << db_strerror(ret) << "... at: " << func;
  30.         throw std::runtime_error(oss.str());
  31.     }
  32.     m_ret = 0;
  33. }
  34. dbmap_iterator_impl_base::~dbmap_iterator_impl_base()
  35. {
  36.     if (m_curp)
  37.         m_curp->close(m_curp);
  38. }
  39. void dbmap_iterator_impl_base::advance(u_int32_t direction_flag, const char* func)
  40. {
  41.     FEBIRD_RT_assert(0 == m_ret, std::logic_error);
  42.     DBT tk; memset(&tk, 0, sizeof(DBT));
  43.     DBT td; memset(&td, 0, sizeof(DBT));
  44.     m_ret = m_curp->get(m_curp, &tk, &td, direction_flag);
  45.     if (0 == m_ret)
  46.     {
  47.         load_key(tk.data, tk.size);
  48.         load_val(td.data, td.size);
  49.     }
  50.     else if (DB_NOTFOUND != m_ret)
  51.     {
  52.         std::ostringstream oss;
  53.         oss << db_strerror(m_ret) << "... at: " << func;
  54.         throw std::runtime_error(oss.str());
  55.     }
  56. }
  57. /**
  58.  @brief 
  59.  @return true successful updated
  60.         false (key, d.key2) did not exist, not updated
  61.  @throw other errors
  62.  */
  63. void dbmap_iterator_impl_base::update(const void* d, const char* func)
  64. {
  65.     FEBIRD_RT_assert(0 == m_ret, std::logic_error);
  66.     PortableDataOutput<AutoGrownMemIO> oKey1, oData;
  67.     this->save_key(oKey1);
  68.     m_owner->save_val(oData, d);
  69.     DBT tk; memset(&tk, 0, sizeof(DBT)); tk.data = oKey1.begin(); tk.size = oKey1.tell();
  70.     DBT td; memset(&td, 0, sizeof(DBT)); td.data = oData.begin(); td.size = oData.tell();
  71.     int ret = m_curp->put(m_curp, &tk, &td, DB_CURRENT);
  72.     if (0 != ret)
  73.     {
  74.         std::ostringstream oss;
  75.         oss << db_strerror(ret)
  76.             << "... at: " << func;
  77.         throw std::runtime_error(oss.str());
  78.     }
  79. }
  80. void dbmap_iterator_impl_base::remove(const char* func)
  81. {
  82.     FEBIRD_RT_assert(0 == m_ret, std::logic_error);
  83.     int ret = m_curp->del(m_curp, 0);
  84.     if (0 != ret)
  85.     {
  86.         std::ostringstream oss;
  87.         oss << db_strerror(ret)
  88.             << "... at: " << func;
  89.         throw std::runtime_error(oss.str());
  90.     }
  91. }
  92. //////////////////////////////////////////////////////////////////////////
  93. dbmap_base::dbmap_base(DB_ENV* env, const char* dbname
  94.     , DB_TXN* txn
  95.     , bt_compare_fcn_type bt_comp
  96.     , const char* func
  97.     )
  98.     : m_bt_comp(0)
  99. {
  100.     m_bulkSize = 512*1024;
  101.     m_db = 0;
  102.     int ret = db_create(&m_db, env, 0);
  103.     if (0 == ret)
  104.     {
  105.         if (bt_comp) {
  106.             m_bt_comp = bt_comp;
  107.             m_db->set_bt_compare(m_db, bt_comp);
  108.         }
  109.         m_db->app_private = (this);
  110.         int flags = env->open_flags & (DB_THREAD|DB_MULTIVERSION|DB_AUTO_COMMIT);
  111.         ret = m_db->open(m_db, txn, dbname, dbname, DB_BTREE, DB_CREATE|flags, 0);
  112.     }
  113.     if (0 != ret)
  114.     {
  115.         std::ostringstream oss;
  116.         oss << db_strerror(ret)
  117.             << "... at: " << func;
  118.         throw std::runtime_error(oss.str());
  119.     }
  120. }
  121. dbmap_base::~dbmap_base()
  122. {
  123.     if (m_db)
  124.         m_db->close(m_db, 0);
  125. }
  126. dbmap_iterator_impl_base* dbmap_base::begin_impl(DB_TXN* txn, const char* func)
  127. {
  128.     dbmap_iterator_impl_base* iter = make_iter();
  129.     iter->init(m_db, txn, func);
  130.     DBT tk; memset(&tk, 0, sizeof(DBT));
  131.     DBT td; memset(&td, 0, sizeof(DBT));
  132.     iter->m_ret = iter->m_curp->get(iter->m_curp, &tk, &td, DB_FIRST);
  133.     if (0 == iter->m_ret)
  134.     {
  135.         iter->load_key(tk.data, tk.size);
  136.         iter->load_val(td.data, td.size);
  137.     }
  138.     else if (DB_NOTFOUND != iter->m_ret)
  139.     {
  140.         std::ostringstream oss;
  141.         oss << db_strerror(iter->m_ret)
  142.             << "... at: " << func;
  143.         delete iter; iter = 0;
  144.         throw std::runtime_error(oss.str());
  145.     }
  146.     return iter;
  147. }
  148. dbmap_iterator_impl_base* dbmap_base::end_impl(DB_TXN* txn, const char* func)
  149. {
  150.     dbmap_iterator_impl_base* iter = make_iter();
  151.     iter->init(m_db, txn, func);
  152. //  iter->m_ret = DB_NOTFOUND;
  153.     return iter;
  154. }
  155. dbmap_iterator_impl_base* dbmap_base::find_impl(const void* k, DB_TXN* txn, u_int32_t flags, const char* func)
  156. {
  157.     PortableDataOutput<AutoGrownMemIO> oKey1;
  158.     save_key(oKey1, k);
  159.     DBT tk; memset(&tk, 0, sizeof(DBT)); tk.data = oKey1.begin(); tk.size = oKey1.tell();
  160.     DBT td; memset(&td, 0, sizeof(DBT));
  161.     dbmap_iterator_impl_base* iter = make_iter();
  162.     iter->init(m_db, txn, func);
  163.     iter->m_ret = iter->m_curp->get(iter->m_curp, &tk, &td, flags);
  164.     if (0 == iter->m_ret)
  165.     {
  166.         iter->load_key(tk.data, tk.size);
  167.         iter->load_val(td.data, td.size);
  168.     }
  169.     else if (DB_NOTFOUND != iter->m_ret && DB_KEYEMPTY != iter->m_ret)
  170.     {
  171.         std::ostringstream oss;
  172.         oss << db_strerror(iter->m_ret)
  173.             << "... at: " << func
  174.             << "/n"
  175.             << "flags=" << flags
  176.             ;
  177.         throw std::runtime_error(oss.str());
  178.     }
  179.     return iter;
  180. }
  181. /**
  182.  @brief insert a record
  183.  @return true success,  no same k-k2 in db, the record was inserted
  184.          false failed, has same k-k2 in db, the record was not inserted, not replaced existing yet
  185.  @throws exception, failed
  186.  */
  187. bool dbmap_base::insert_impl(const void* k, const void* d, u_int32_t flags, DB_TXN* txn, const char* func)
  188. {
  189.     PortableDataOutput<AutoGrownMemIO> oKey1, oData;
  190.     try {
  191.         save_key(oKey1, k);
  192.         save_val(oData, d);
  193.     }
  194.     catch (const IOException& exp)
  195.     {
  196.         std::ostringstream oss;
  197.         oss << exp.what() << "... at: " << func;
  198.         throw std::runtime_error(oss.str());
  199.     }
  200.     DBT tk; memset(&tk, 0, sizeof(DBT)); tk.data = oKey1.begin(); tk.size = oKey1.tell();
  201.     DBT td; memset(&td, 0, sizeof(DBT)); td.data = oData.begin(); td.size = oData.tell();
  202.     int ret = m_db->put(m_db, txn, &tk, &td, flags);
  203.     if (DB_KEYEXIST == ret)
  204.         return false;
  205.     if (0 == ret)
  206.         return true;
  207.     std::ostringstream oss;
  208.     oss << db_strerror(ret)
  209.         << "... at: " << func
  210.         << "/n"
  211.         ;
  212.     throw std::runtime_error(oss.str());
  213. }
  214. /**
  215.  @brief 
  216.  @return true (k) existed, remove success
  217.         false (k) not existed, nothing done
  218.  */
  219. bool dbmap_base::remove_impl(const void* k, DB_TXN* txn, const char* func)
  220. {
  221.     PortableDataOutput<AutoGrownMemIO> oKey1;
  222.     save_key(oKey1, k);
  223.     DBT tk; memset(&tk, 0, sizeof(DBT)); tk.data = oKey1.begin(); tk.size = oKey1.tell();
  224.     int ret = m_db->del(m_db, txn, &tk, 0);
  225.     if (DB_NOTFOUND == ret)
  226.         return false;
  227.     if (0 == ret)
  228.         return true;
  229.     std::ostringstream oss;
  230.     oss << db_strerror(ret)
  231.         << "... at: " << func
  232.         << "/n"
  233.         ;
  234.     throw std::runtime_error(oss.str());
  235. }
  236. void dbmap_base::clear_impl(DB_TXN* txn, const char* func)
  237. {
  238.     u_int32_t count;
  239.     int ret = m_db->truncate(m_db, txn, &count, 0);
  240.     if (0 != ret)
  241.     {
  242.         std::ostringstream oss;
  243.         oss << db_strerror(ret)
  244.             << "... at: " << func
  245.             << "/n"
  246.             ;
  247.         throw std::runtime_error(oss.str());
  248.     }
  249. }
  250. // namespace febird

你可能感兴趣的:(最便捷的序列化方式)