Thursday, October 28, 2004

Simple DB3 C++ Wrapper

為了寫程式方便順手包的 db3++.h,將操作 Berkeley DB ver.3[1]的 C API 稍作包裝,以便在 C++ 裡更好用。因為純粹以快速寫完為原則,所以一些成員函式的 prototype 設計就沒有仔細構思,error handling 也未盡完善,不過以下所展示的已足以說明如何包裝、使用 db3:

#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_;

};

[1] Berkeley DB 是睡貓公司出的資料庫軟體,網址為 http://www.sleepycat.com/

Comments: Post a Comment

Subscribe to Post Comments [Atom]





<< Home

This page is powered by Blogger. Isn't yours?

Subscribe to Comments [Atom]