#include
#include
#include
#include
template
class BerkeleyDB3
{
public:
typedef K key_type;
typedef D data_type;
typedef ::std::pair value_type;
// 一般使用,type 請傳入 DB_BTREE 或是 DB_HASH,指底層資料儲存方式。然
// 後 flags 常會傳入 DB_CREATE 和/或 DB_RDONLY,前者指定若 fname 檔案
// 不在要不要建立新檔,後者指定是否唯讀。
BerkeleyDB3(const char* fname, DBTYPE type, u_int32_t flags)
{
int ret;
if ((ret = db_create(&db_, NULL, 0)) != 0) {
::std::cerr << "db_create: "
<< db_strerror(ret)
<< ::std::endl;
::std::exit(1);
}
if ((ret = db_->open(db_, fname, NULL, type, flags, 0664)) != 0) {
::std::cerr << "DB->open(\""
<< fname << \"") failed: "
<< db_strerror(ret)
<< ::std::endl;
::std::exit(1);
}
}
~BerkeleyDB3()
{
int ret;
if ((ret = db_->close(db_, 0)) != 0) {
::std::cerr << "db: db->close() failed: "
<< db_strerror(ret)
<< ::std::endl;
::std::exit(1);
}
}
bool put(K key, D data)
{
DBTType dbt_key(key);
DBTType dbt_data(data);
int ret;
if ((ret = db_->put(db_, NULL, dbt_key.dbt(), dbt_data.dbt(), 0)) != 0) {
::std::cerr << "DB->put("
<< key
<< ", "
<< data
<< ") failed: "
<< db_strerror(ret)
<< ::std::endl;
exit(1);
}
return true;
}
bool get(K key, D& data)
{
DBTType dbt_key(key);
DBTType dbt_data;
int ret;
if ((ret = db_->get(db_, NULL, dbt_key.dbt(), dbt_data.dbt(), 0)) != 0) {
switch (ret) {
case DB_NOTFOUND:
return false;
break;
default:
::std::cerr << "DB->get("
<< key
<< ") failed: "
<< db_strerror(ret)
<< ::std::endl;
exit(1);
}
}
data = dbt_data.get();
return true;
}
private:
// 這裡應該利用 template specialization 技術,針對幾種常見的 type 作偏
// 特化。好比說若 T 是 char*,很顯然地我們要存進資料庫的不是那個指標。
template
class DBTType
{
friend BerkeleyDB3;
public:
DBTType()
{
memset(&dbt_, 0, sizeof(DBT));
}
DBTType(const T& data)
: data_(data)
{
memset(&dbt_, 0, sizeof(DBT));
dbt_.data = &data_;
dbt_.size = sizeof(data_);
}
void set(const T& data)
{
data_ = data;
dbt_.data = &data_;
dbt_.size = sizeof(data_);
}
const T get()
{
return *((T*)(dbt_.data));
}
private:
DBT* dbt()
{
return &dbt_;
}
DBT dbt_;
T data_; // 用以作為資料的記憶體空間,好處是不必管理底層記憶體,壞
// 處是要負擔新建物件的成本,且 T 必須是 copyable。
}
DB* db_;
}; |