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, AutoGrownMemIO,PortableDataOutput,PortableDataInput…
代码中没有提到MinMemIO,因为MinMemIO没有越界检查,只有在非常简单,完全可控的情况下,才能使用它。因为没有越界检查,它的性能非常好,在大多数情况下相当于手工的memcpy序列化。
使用MemIO稍微慢一点,但是有越界检查,读取时越界会抛出EndOfFileException异常,写入越界时会抛出OutOfSpaceException异常。
使用AutoGrownMemIO,在save时,碰到边界会自动增加内存(相当于vector.push_back自动增加内存),也可以使用resize预先分配内存(相当于vector.reserve/resize)。
这个几个MemIO类都非常简单,速度快是很自然的。
在PortableDataOutput,PortableDataInput中,如果机器字节序是LittleEndian,需要交换字节序,这一点,在新版的vc中和gcc中,会直接映射到一条指令:bswap。所以也不会有性能问题。
对于var_int的存储,无符号数,每个字节包含7个有效位,余下一位表示是否需要读取下一个字节。因此0~127仅需要一个字节,0~2^14-1需要两个字节,等等。对于有符号数,最低有效位存储符号,其余位存储绝对值。所有stl容器和string的尺寸就是用var_uint32_t存储的。
该框架中,同时实现了StreamBuffer,可以为任意Stream增加一层缓冲,往缓冲里面序列化数据的效率和MemIO系列是一样的,不同之处在于当缓冲耗尽或填满时会调用真实Stream的读写方法。这比起通常很多实现中将BufferedStream作为一个抽象,在读取哪怕一个字节时也需要一个虚函数调用,速度要快得多。
扩展应用
使用该序列化框架,我实现了一个不需要IDL的RPC。
使用该序列化框架,对Berkeley DB进行包装,可以让它象标准容器一样使用,免除了复杂的编码。后面我会继续介绍。
=================================================================
=================================================================
使用前面介绍的序列化框架,可以非常简单地将Bekeley DB作为存储层,实现一个易于使用的,强类型的,持久化的map。
这个设计的的基本原则就是:模板作为一个薄的、类型安全的包装层,实现层的代码可以多个模板实例来公用,这样不但加快了编译时间,也减小了生成的代码尺寸。
这个实现相当于std::map<Key,Data>,但接口上也不完全相同,主要是基于易实现和性能考虑。
下一篇介绍std::map<Key1,std::map<Key2,Data> >的BerkeleyDB实现。
多的不说,贴上代码。
file: dbmap.h
-
- #ifndef __febird_bdb_dbmap_h__
- #define __febird_bdb_dbmap_h__
-
- #if defined(_MSC_VER) && (_MSC_VER >= 1020)
- # pragma once
- #endif
-
- #include <db_cxx.h>
- #include "native_compare.h"
- #include "../io/DataIO.h"
- #include "../io/MemStream.h"
- #include "../refcount.h"
-
- namespace febird {
-
- class FEBIRD_DLL_EXPORT dbmap_iterator_impl_base : public RefCounter
- {
- public:
- class dbmap_base* m_owner;
- DBC* m_curp;
- int m_ret;
-
- public:
- dbmap_iterator_impl_base(class dbmap_base* owner);
- void init(DB* dbp, DB_TXN* txn, const char* func);
-
- virtual ~dbmap_iterator_impl_base();
-
- virtual void load_key(void* data, size_t size) = 0;
- virtual void load_val(void* data, size_t size) = 0;
- virtual void save_key(PortableDataOutput<AutoGrownMemIO>& oKey) = 0;
-
- void advance(u_int32_t direction_flag, const char* func);
-
- void update(const void* d, const char* func);
- void remove(const char* func);
- };
-
- class FEBIRD_DLL_EXPORT dbmap_base
- {
- DECLARE_NONE_COPYABLE_CLASS(dbmap_base)
-
- public:
- DB* m_db;
- size_t m_bulkSize;
- bt_compare_fcn_type m_bt_comp;
-
- dbmap_base(DB_ENV* env, const char* dbname
- , DB_TXN* txn
- , bt_compare_fcn_type bt_comp
- , const char* func
- );
-
- virtual ~dbmap_base();
- virtual void save_key(PortableDataOutput<AutoGrownMemIO>& dio, const void* key) const = 0;
- virtual void save_val(PortableDataOutput<AutoGrownMemIO>& dio, const void* data) const = 0;
-
- virtual dbmap_iterator_impl_base* make_iter() = 0;
-
- dbmap_iterator_impl_base* begin_impl(DB_TXN* txn, const char* func);
- dbmap_iterator_impl_base* end_impl(DB_TXN* txn, const char* func);
-
- dbmap_iterator_impl_base* find_impl(const void* k, DB_TXN* txn, u_int32_t flags, const char* func);
-
- bool insert_impl(const void* k, const void* d, u_int32_t flags, DB_TXN* txn, const char* func);
- bool remove_impl(const void* k, DB_TXN* txn, const char* func);
- void clear_impl(DB_TXN* txn, const char* func);
- };
-
- template<class Key, class Val, class Value, class Impl>
- class dbmap_iterator :
- public std::iterator<std::bidirectional_iterator_tag, Value, ptrdiff_t, const Value*, const Value&>
- {
- boost::intrusive_ptr<Impl> m_impl;
-
- void copy_on_write()
- {
- if (m_impl->getRefCount() > 1)
- {
- Impl* p = new Impl(m_impl->m_owner);
- m_impl->m_ret = m_impl->m_curp->dup(m_impl->m_curp, &p->m_curp, DB_POSITION);
- FEBIRD_RT_assert(0 == m_impl->m_ret, std::runtime_error);
- m_impl.reset(p);
- }
- }
- private:
- #ifdef _MSC_VER
-
-
- void operator++(int) { assert(0); }
- void operator--(int) { assert(0); }
- #else
-
- void operator++(int);
- void operator--(int);
- #endif
-
- public:
- dbmap_iterator() {}
- explicit dbmap_iterator(dbmap_iterator_impl_base* impl)
- : m_impl(static_cast<Impl*>(impl))
- {
- assert(impl);
- assert(dynamic_cast<Impl*>(impl));
- }
-
-
- bool exist() const { return 0 == m_impl->m_ret; }
-
- void update(const Val& val) { m_impl->update(&val, BOOST_CURRENT_FUNCTION); }
-
- void remove() { m_impl->remove(BOOST_CURRENT_FUNCTION); }
-
- dbmap_iterator& operator++()
- {
- assert(0 == m_impl->m_ret);
- copy_on_write();
- m_impl->advance(DB_NEXT, BOOST_CURRENT_FUNCTION);
- return *this;
- }
- dbmap_iterator& operator--()
- {
- assert(0 == m_impl->m_ret);
- copy_on_write();
- m_impl->advance(DB_PREV, BOOST_CURRENT_FUNCTION);
- return *this;
- }
- const Value& operator*() const
- {
- assert(0 == m_impl->m_ret);
- return m_impl->m_val;
- }
- const Value* operator->() const
- {
- assert(0 == m_impl->m_ret);
- return &m_impl->m_val;
- }
- Value& get_mutable() const
- {
- assert(0 == m_impl->m_ret);
- return m_impl->m_val;
- }
- };
-
- template<class Key, class Val>
- class dbmap : protected dbmap_base
- {
- DECLARE_NONE_COPYABLE_CLASS(dbmap)
-
- public:
- typedef Key key_type;
- typedef std::pair<Key, Val> value_type;
-
- protected:
- class dbmap_iterator_impl : public dbmap_iterator_impl_base
- {
- public:
- value_type m_val;
-
- dbmap_iterator_impl(dbmap_base* owner)
- : dbmap_iterator_impl_base(owner)
- {}
-
- virtual void load_key(void* data, size_t size)
- {
- PortableDataInput<MemIO> iKey;
- iKey.set(data, size);
- iKey >> m_val.first;
- FEBIRD_RT_assert(iKey.eof(), std::logic_error);
- }
- virtual void load_val(void* data, size_t size)
- {
- PortableDataInput<MinMemIO> iVal;
- iVal.set(data);
- iVal >> m_val.second;
- FEBIRD_RT_assert(iVal.diff(data) == size, std::logic_error);
- }
- virtual void save_key(PortableDataOutput<AutoGrownMemIO>& oKey1)
- {
- oKey1 << m_val.first;
- }
- };
-
-
- void save_key(PortableDataOutput<AutoGrownMemIO>& dio, const void* key) const { dio << *(const Key*)key; }
- void save_val(PortableDataOutput<AutoGrownMemIO>& dio, const void* val) const { dio << *(const Val*)val; }
-
- dbmap_iterator_impl_base* make_iter() { return new dbmap_iterator_impl(this); }
-
- public:
-
- typedef dbmap_iterator<Key, Val, value_type, dbmap_iterator_impl>
- iterator, const_iterator;
-
- dbmap(DB_ENV* env, const char* dbname
- , DB_TXN* txn = NULL
- , bt_compare_fcn_type bt_comp = bdb_auto_bt_compare((Key*)(0))
- )
- : dbmap_base(env, dbname, txn, bt_comp, BOOST_CURRENT_FUNCTION)
- {
- }
- dbmap(DbEnv* env, const char* dbname
- , DbTxn* txn = NULL
- , bt_compare_fcn_type bt_comp = bdb_auto_bt_compare((Key*)(0))
- )
- : dbmap_base(env->get_DB_ENV(), dbname, txn ? txn->get_DB_TXN() : NULL, bt_comp, BOOST_CURRENT_FUNCTION)
- {
- }
-
- iterator begin(DB_TXN* txn = NULL) { return iterator(begin_impl(txn, BOOST_CURRENT_FUNCTION)); }
- iterator end (DB_TXN* txn = NULL) { return iterator(end_impl (txn, BOOST_CURRENT_FUNCTION)); }
-
- iterator begin(DbTxn* txn) { return iterator(begin_impl(txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION)); }
- iterator end (DbTxn* txn) { return iterator(end_impl (txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION)); }
-
- value_type back()
- {
- iterator iter = this->end();
- --iter;
- if (iter.exist())
- return *iter;
- throw std::runtime_error(BOOST_CURRENT_FUNCTION);
- }
- value_type front()
- {
- iterator iter = this->begin();
- if (iter.exist())
- return *iter;
- throw std::runtime_error(BOOST_CURRENT_FUNCTION);
- }
-
- iterator find(const Key& k, DB_TXN* txn = NULL)
- {
- return iterator(find_impl(&k, txn, DB_SET, BOOST_CURRENT_FUNCTION));
- }
- iterator find(const Key& k, DbTxn* txn)
- {
- return iterator(find_impl(&k, txn ? txn->get_DB_TXN() : NULL, DB_SET, BOOST_CURRENT_FUNCTION));
- }
-
- iterator lower_bound(const Key& k, DB_TXN* txn = NULL)
- {
- return iterator(find_impl(&k, txn, DB_SET_RANGE, BOOST_CURRENT_FUNCTION));
- }
- iterator lower_bound(const Key& k, DbTxn* txn)
- {
- return iterator(find_impl(&k, txn ? txn->get_DB_TXN() : NULL, DB_SET_RANGE, BOOST_CURRENT_FUNCTION));
- }
-
- bool insert(const std::pair<Key,Val>& kv, DB_TXN* txn = NULL)
- {
- return insert_impl(&kv.first, &kv.second, DB_NOOVERWRITE, txn, BOOST_CURRENT_FUNCTION);
- }
- bool insert(const std::pair<Key,Val>& kv, DbTxn* txn)
- {
- return insert_impl(&kv.first, &kv.second, DB_NOOVERWRITE, txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION);
- }
-
- bool insert(const Key& k, const Val& d, DB_TXN* txn = NULL)
- {
- return insert_impl(&k, &d, DB_NOOVERWRITE, txn, BOOST_CURRENT_FUNCTION);
- }
- bool insert(const Key& k, const Val& d, DbTxn* txn)
- {
- return insert_impl(&k, &d, DB_NOOVERWRITE, txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION);
- }
-
- void replace(const std::pair<Key,Val>& kv, DB_TXN* txn = NULL)
- {
- insert_impl(&kv.first, &kv.second, 0, txn, BOOST_CURRENT_FUNCTION);
- }
- void replace(const std::pair<Key,Val>& kv, DbTxn* txn)
- {
- insert_impl(&kv.first, &kv.second, 0, txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION);
- }
- void replace(const Key& k, const Val& d, DB_TXN* txn = NULL)
- {
- insert_impl(&k, &d, 0, txn, BOOST_CURRENT_FUNCTION);
- }
- void replace(const Key& k, const Val& d, DbTxn* txn)
- {
- insert_impl(&k, &d, 0, txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION);
- }
-
- bool remove(const Key& k, DB_TXN* txn = NULL)
- {
- return remove_impl(&k, txn, BOOST_CURRENT_FUNCTION);
- }
- bool remove(const Key& k, DbTxn* txn)
- {
- return remove_impl(&k, txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION);
- }
-
- bool erase(iterator& iter)
- {
- return iter.remove();
- }
-
- void clear(DB_TXN* txn = NULL)
- {
- clear_impl(txn, BOOST_CURRENT_FUNCTION);
- }
- void clear(DbTxn* txn)
- {
- return clear_impl(txn ? txn->get_DB_TXN() : NULL, BOOST_CURRENT_FUNCTION);
- }
-
- DB* getDB() { return m_db; }
- const DB* getDB() const { return m_db; }
- };
-
- }
-
-
- #endif // __febird_bdb_dbmap_h__
file: dbmap.cpp
-
- #include "dbmap.h"
- #include <sstream>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- namespace febird {
-
- dbmap_iterator_impl_base::dbmap_iterator_impl_base(class dbmap_base* owner)
- : m_owner(owner)
- , m_curp(0), m_ret(-1)
- {
- }
-
- void dbmap_iterator_impl_base::init(DB* dbp, DB_TXN* txn, const char* func)
- {
- int ret = dbp->cursor(dbp, txn, &m_curp, 0);
- if (0 != ret)
- {
- delete this;
- std::ostringstream oss;
- oss << db_strerror(ret) << "... at: " << func;
- throw std::runtime_error(oss.str());
- }
- m_ret = 0;
- }
-
- dbmap_iterator_impl_base::~dbmap_iterator_impl_base()
- {
- if (m_curp)
- m_curp->close(m_curp);
- }
-
- void dbmap_iterator_impl_base::advance(u_int32_t direction_flag, const char* func)
- {
- FEBIRD_RT_assert(0 == m_ret, std::logic_error);
- DBT tk; memset(&tk, 0, sizeof(DBT));
- DBT td; memset(&td, 0, sizeof(DBT));
- m_ret = m_curp->get(m_curp, &tk, &td, direction_flag);
- if (0 == m_ret)
- {
- load_key(tk.data, tk.size);
- load_val(td.data, td.size);
- }
- else if (DB_NOTFOUND != m_ret)
- {
- std::ostringstream oss;
- oss << db_strerror(m_ret) << "... at: " << func;
- throw std::runtime_error(oss.str());
- }
- }
-
-
-
-
-
-
-
- void dbmap_iterator_impl_base::update(const void* d, const char* func)
- {
- FEBIRD_RT_assert(0 == m_ret, std::logic_error);
- PortableDataOutput<AutoGrownMemIO> oKey1, oData;
- this->save_key(oKey1);
- m_owner->save_val(oData, d);
- DBT tk; memset(&tk, 0, sizeof(DBT)); tk.data = oKey1.begin(); tk.size = oKey1.tell();
- DBT td; memset(&td, 0, sizeof(DBT)); td.data = oData.begin(); td.size = oData.tell();
- int ret = m_curp->put(m_curp, &tk, &td, DB_CURRENT);
- if (0 != ret)
- {
- std::ostringstream oss;
- oss << db_strerror(ret)
- << "... at: " << func;
- throw std::runtime_error(oss.str());
- }
- }
-
- void dbmap_iterator_impl_base::remove(const char* func)
- {
- FEBIRD_RT_assert(0 == m_ret, std::logic_error);
- int ret = m_curp->del(m_curp, 0);
- if (0 != ret)
- {
- std::ostringstream oss;
- oss << db_strerror(ret)
- << "... at: " << func;
- throw std::runtime_error(oss.str());
- }
- }
-
-
-
- dbmap_base::dbmap_base(DB_ENV* env, const char* dbname
- , DB_TXN* txn
- , bt_compare_fcn_type bt_comp
- , const char* func
- )
- : m_bt_comp(0)
- {
- m_bulkSize = 512*1024;
- m_db = 0;
- int ret = db_create(&m_db, env, 0);
- if (0 == ret)
- {
- if (bt_comp) {
- m_bt_comp = bt_comp;
- m_db->set_bt_compare(m_db, bt_comp);
- }
- m_db->app_private = (this);
- int flags = env->open_flags & (DB_THREAD|DB_MULTIVERSION|DB_AUTO_COMMIT);
- ret = m_db->open(m_db, txn, dbname, dbname, DB_BTREE, DB_CREATE|flags, 0);
- }
-
- if (0 != ret)
- {
- std::ostringstream oss;
- oss << db_strerror(ret)
- << "... at: " << func;
- throw std::runtime_error(oss.str());
- }
- }
-
- dbmap_base::~dbmap_base()
- {
- if (m_db)
- m_db->close(m_db, 0);
- }
-
- dbmap_iterator_impl_base* dbmap_base::begin_impl(DB_TXN* txn, const char* func)
- {
- dbmap_iterator_impl_base* iter = make_iter();
- iter->init(m_db, txn, func);
- DBT tk; memset(&tk, 0, sizeof(DBT));
- DBT td; memset(&td, 0, sizeof(DBT));
- iter->m_ret = iter->m_curp->get(iter->m_curp, &tk, &td, DB_FIRST);
- if (0 == iter->m_ret)
- {
- iter->load_key(tk.data, tk.size);
- iter->load_val(td.data, td.size);
- }
- else if (DB_NOTFOUND != iter->m_ret)
- {
- std::ostringstream oss;
- oss << db_strerror(iter->m_ret)
- << "... at: " << func;
- delete iter; iter = 0;
- throw std::runtime_error(oss.str());
- }
- return iter;
- }
-
- dbmap_iterator_impl_base* dbmap_base::end_impl(DB_TXN* txn, const char* func)
- {
- dbmap_iterator_impl_base* iter = make_iter();
- iter->init(m_db, txn, func);
-
- return iter;
- }
-
- dbmap_iterator_impl_base* dbmap_base::find_impl(const void* k, DB_TXN* txn, u_int32_t flags, const char* func)
- {
- PortableDataOutput<AutoGrownMemIO> oKey1;
- save_key(oKey1, k);
- DBT tk; memset(&tk, 0, sizeof(DBT)); tk.data = oKey1.begin(); tk.size = oKey1.tell();
- DBT td; memset(&td, 0, sizeof(DBT));
- dbmap_iterator_impl_base* iter = make_iter();
- iter->init(m_db, txn, func);
- iter->m_ret = iter->m_curp->get(iter->m_curp, &tk, &td, flags);
- if (0 == iter->m_ret)
- {
- iter->load_key(tk.data, tk.size);
- iter->load_val(td.data, td.size);
- }
- else if (DB_NOTFOUND != iter->m_ret && DB_KEYEMPTY != iter->m_ret)
- {
- std::ostringstream oss;
- oss << db_strerror(iter->m_ret)
- << "... at: " << func
- << "/n"
- << "flags=" << flags
- ;
- throw std::runtime_error(oss.str());
- }
- return iter;
- }
-
-
-
-
-
-
-
- bool dbmap_base::insert_impl(const void* k, const void* d, u_int32_t flags, DB_TXN* txn, const char* func)
- {
- PortableDataOutput<AutoGrownMemIO> oKey1, oData;
- try {
- save_key(oKey1, k);
- save_val(oData, d);
- }
- catch (const IOException& exp)
- {
- std::ostringstream oss;
- oss << exp.what() << "... at: " << func;
- throw std::runtime_error(oss.str());
- }
- DBT tk; memset(&tk, 0, sizeof(DBT)); tk.data = oKey1.begin(); tk.size = oKey1.tell();
- DBT td; memset(&td, 0, sizeof(DBT)); td.data = oData.begin(); td.size = oData.tell();
- int ret = m_db->put(m_db, txn, &tk, &td, flags);
- if (DB_KEYEXIST == ret)
- return false;
- if (0 == ret)
- return true;
- std::ostringstream oss;
- oss << db_strerror(ret)
- << "... at: " << func
- << "/n"
- ;
- throw std::runtime_error(oss.str());
- }
-
-
-
-
-
-
- bool dbmap_base::remove_impl(const void* k, DB_TXN* txn, const char* func)
- {
- PortableDataOutput<AutoGrownMemIO> oKey1;
- save_key(oKey1, k);
- DBT tk; memset(&tk, 0, sizeof(DBT)); tk.data = oKey1.begin(); tk.size = oKey1.tell();
- int ret = m_db->del(m_db, txn, &tk, 0);
- if (DB_NOTFOUND == ret)
- return false;
- if (0 == ret)
- return true;
- std::ostringstream oss;
- oss << db_strerror(ret)
- << "... at: " << func
- << "/n"
- ;
- throw std::runtime_error(oss.str());
- }
-
- void dbmap_base::clear_impl(DB_TXN* txn, const char* func)
- {
- u_int32_t count;
- int ret = m_db->truncate(m_db, txn, &count, 0);
- if (0 != ret)
- {
- std::ostringstream oss;
- oss << db_strerror(ret)
- << "... at: " << func
- << "/n"
- ;
- throw std::runtime_error(oss.str());
- }
- }
-
- }