先總的說一下:
類:LMDBCursor: 它干了點什么?它需要傳入參數為:mdb_txn(傳入它是因為用完它,把它absort掉), mdb_cursor;它應該是用來讀出數據的;
類:LMDBTransaction:
它主要是用來寫入數據的吧,,用put()函數 ,與commit()函數;
最終還是靠類:LMDB應該算是一個對上面兩個類的調用吧。它應該算是做了封裝吧,,干脆直接上代碼啦:
db_lmdb.hpp
1 #ifdef USE_LMDB 2 #ifndef CAFFE_UTIL_DB_LMDB_HPP 3 #define CAFFE_UTIL_DB_LMDB_HPP 4 5 #include <string> 6 #include <vector> 7 8 #include "lmdb.h" 9 10 #include "caffe/util/db.hpp" 11 12 namespace caffe { namespace db { 13 // 下面的MDB_SUCCESS為一個宏定義,為0,表示成功,如果失敗則對應不同的數值,表示不同的錯誤; 14 // mdb_strerror,輸出string,它的作用是根據不同的錯誤輸出不同的錯誤語句; 15 inline void MDB_CHECK(int mdb_status) { 16 CHECK_EQ(mdb_status, MDB_SUCCESS) << mdb_strerror(mdb_status); 17 } 18 19 //注意:MDB_cursor是與一個specific的transaction與database相關聯的; 20 class LMDBCursor : public Cursor { 21 public: 22 explicit LMDBCursor(MDB_txn* mdb_txn, MDB_cursor* mdb_cursor) //初始化時,給mdb_txn,與mdb_curcor賦值; 23 : mdb_txn_(mdb_txn), mdb_cursor_(mdb_cursor), valid_(false) { 24 SeekToFirst(); 25 } 26 virtual ~LMDBCursor() { 27 mdb_cursor_close(mdb_cursor_); //mdb_cursor_close函數的作用為:關閉一個cursor句柄; 28 mdb_txn_abort(mdb_txn_); //該函數的作用為:用於放棄所有對transaction的操作,並釋放掉transaction句柄; 29 } 30 virtual void SeekToFirst() { Seek(MDB_FIRST); } //把database里的第一個key/value的值放入變量:mdb_key_與mdb_value_; 31 virtual void Next() { Seek(MDB_NEXT); } //下一個;; 32 virtual string key() { 33 return string(static_cast<const char*>(mdb_key_.mv_data), mdb_key_.mv_size); //返回mdb_key_里的數據,以字符串形式; 34 } 35 virtual string value() { 36 return string(static_cast<const char*>(mdb_value_.mv_data), 37 mdb_value_.mv_size); //返回mdb_value_里的數據(以字符串的方式;,應該是用了strin的構造函數吧. 38 } 39 virtual bool valid() { return valid_; } 40 41 private: 42 void Seek(MDB_cursor_op op) { //注意,這里的MDB_cursor_op為枚舉類型,代表了curcor的相關操作; 43 int mdb_status = mdb_cursor_get(mdb_cursor_, &mdb_key_, &mdb_value_, op); //這個函數用於通過curcor恢復key與data; 44 if (mdb_status == MDB_NOTFOUND) { //當返回的狀態為MDB_NOTFOUND時,表明,沒有發現匹配的key; 45 valid_ = false; 46 } else { 47 MDB_CHECK(mdb_status); 48 valid_ = true; 49 } 50 } 51 52 MDB_txn* mdb_txn_; //初始化時,給mdb_txn,與mdb_curcor賦值; 53 MDB_cursor* mdb_cursor_; 54 MDB_val mdb_key_, mdb_value_; 55 bool valid_; 56 }; 57 58 class LMDBTransaction : public Transaction { 59 public: 60 explicit LMDBTransaction(MDB_env* mdb_env) //給一個環境handle賦值; 61 : mdb_env_(mdb_env) { } 62 virtual void Put(const string& key, const string& value); //把key與value的值分別push到對應的vector里; 63 virtual void Commit(); //它做的時,把keys 與 values里的數據提交 ,並清空它們; 64 65 private: 66 MDB_env* mdb_env_; //環境句柄; 67 vector<string> keys, values; //兩個vector容器; 68 69 void DoubleMapSize(); //把環境的mapsize擴大兩倍; 70 71 DISABLE_COPY_AND_ASSIGN(LMDBTransaction); 72 }; 73 74 class LMDB : public DB { 75 public: 76 LMDB() : mdb_env_(NULL) { } 77 virtual ~LMDB() { Close(); } 78 virtual void Open(const string& source, Mode mode); //它所做的事情就是創建一個操作環境,根據mode,來決定是讀還是NEW; 79 virtual void Close() { 80 if (mdb_env_ != NULL) { //它所做的就是:當所創建的環境的handle 不為空時,說明還沒有釋放掉; 81 mdb_dbi_close(mdb_env_, mdb_dbi_); //於是呢,把相關的如database的handle,以及mdb_env_釋放掉,釋放先前的內存; 82 mdb_env_close(mdb_env_); 83 mdb_env_ = NULL; 84 } 85 } 86 virtual LMDBCursor* NewCursor(); //根據mdb_env_,mdb_dbi_,創建了一個LMDBCursor的類; 87 virtual LMDBTransaction* NewTransaction(); //返回一個用mdb_env_初始化了的LMDBTransaction類的指針; 88 89 private: 90 MDB_env* mdb_env_; 91 MDB_dbi mdb_dbi_; 92 }; 93 94 } // namespace db 95 } // namespace caffe 96 97 #endif // CAFFE_UTIL_DB_LMDB_HPP 98 #endif // USE_LMDB
db_lmdb.cpp
1 #ifdef USE_LMDB 2 #include "caffe/util/db_lmdb.hpp" 3 4 #include <sys/stat.h> 5 6 #include <string> 7 8 namespace caffe { namespace db { 9 10 void LMDB::Open(const string& source, Mode mode) { 11 MDB_CHECK(mdb_env_create(&mdb_env_)); 12 if (mode == NEW) { 13 CHECK_EQ(mkdir(source.c_str(), 0744), 0) << "mkdir " << source << " failed"; //如果為NEW, 則創建一個source的路徑; 14 } 15 int flags = 0; 16 if (mode == READ) { 17 flags = MDB_RDONLY | MDB_NOTLS; //設置一下它的特別選項,一個是只讀,一個是不使用線程本地存儲; 18 } 19 int rc = mdb_env_open(mdb_env_, source.c_str(), flags, 0664); 20 #ifndef ALLOW_LMDB_NOLOCK 21 MDB_CHECK(rc); 22 #else 23 if (rc == EACCES) { //表示:the user didn't have permission to access the environment files. 24 LOG(WARNING) << "Permission denied. Trying with MDB_NOLOCK ..."; 25 // Close and re-open environment handle 26 mdb_env_close(mdb_env_); 27 MDB_CHECK(mdb_env_create(&mdb_env_)); 28 // Try again with MDB_NOLOCK 29 flags |= MDB_NOLOCK; //增加了一個選項,它的意思為不作任何鎖操作; 30 MDB_CHECK(mdb_env_open(mdb_env_, source.c_str(), flags, 0664)); 31 } else { 32 MDB_CHECK(rc); 33 } 34 #endif 35 LOG(INFO) << "Opened lmdb " << source; 36 } 37 38 LMDBCursor* LMDB::NewCursor() { 39 MDB_txn* mdb_txn; 40 MDB_cursor* mdb_cursor; 41 MDB_CHECK(mdb_txn_begin(mdb_env_, NULL, MDB_RDONLY, &mdb_txn)); 42 MDB_CHECK(mdb_dbi_open(mdb_txn, NULL, 0, &mdb_dbi_)); 43 MDB_CHECK(mdb_cursor_open(mdb_txn, mdb_dbi_, &mdb_cursor)); 44 return new LMDBCursor(mdb_txn, mdb_cursor); //不明白為什么把局部的mdb_txn返回去,在LMDBCursor類里面,也就析構函數用到了mdb_txn, 45 //可以就是為了去用函數mdb_txn_abort把它干掉吧;,似乎明白了呢,等用完它,把它干掉吧; 46 } 47 48 LMDBTransaction* LMDB::NewTransaction() { 49 return new LMDBTransaction(mdb_env_); 50 } 51 52 void LMDBTransaction::Put(const string& key, const string& value) { 53 keys.push_back(key); 54 values.push_back(value); 55 } 56 57 void LMDBTransaction::Commit() { 58 MDB_dbi mdb_dbi; 59 MDB_val mdb_key, mdb_data; 60 MDB_txn *mdb_txn; 61 62 // Initialize MDB variables 63 MDB_CHECK(mdb_txn_begin(mdb_env_, NULL, 0, &mdb_txn)); 64 MDB_CHECK(mdb_dbi_open(mdb_txn, NULL, 0, &mdb_dbi)); 65 66 for (int i = 0; i < keys.size(); i++) { 67 mdb_key.mv_size = keys[i].size(); 68 mdb_key.mv_data = const_cast<char*>(keys[i].data()); 69 mdb_data.mv_size = values[i].size(); 70 mdb_data.mv_data = const_cast<char*>(values[i].data()); 71 72 // Add data to the transaction 73 int put_rc = mdb_put(mdb_txn, mdb_dbi, &mdb_key, &mdb_data, 0); //即把key/data的值放入database里去; 74 if (put_rc == MDB_MAP_FULL) { 75 // Out of memory - double the map size and retry 76 mdb_txn_abort(mdb_txn); 77 mdb_dbi_close(mdb_env_, mdb_dbi); 78 DoubleMapSize(); 79 Commit(); //不明白 為什么能調用 Commit(),回去復習一下C++; 80 return; 81 } 82 // May have failed for some other reason 83 MDB_CHECK(put_rc); 84 } 85 86 // Commit the transaction 87 int commit_rc = mdb_txn_commit(mdb_txn); 88 if (commit_rc == MDB_MAP_FULL) { 89 // Out of memory - double the map size and retry 90 mdb_dbi_close(mdb_env_, mdb_dbi); 91 DoubleMapSize(); 92 Commit(); 93 return; 94 } 95 // May have failed for some other reason 96 MDB_CHECK(commit_rc); 97 98 // Cleanup after successful commit 99 mdb_dbi_close(mdb_env_, mdb_dbi); 100 keys.clear(); //清空keys and values; 101 values.clear(); 102 } 103 104 void LMDBTransaction::DoubleMapSize() { 105 struct MDB_envinfo current_info; 106 MDB_CHECK(mdb_env_info(mdb_env_, ¤t_info)); 107 size_t new_size = current_info.me_mapsize * 2; 108 DLOG(INFO) << "Doubling LMDB map size to " << (new_size>>20) << "MB ..."; 109 MDB_CHECK(mdb_env_set_mapsize(mdb_env_, new_size)); 110 } 111 112 } // namespace db 113 } // namespace caffe 114 #endif // USE_LMDB