1. 程式人生 > >Caffe 原始碼閱讀筆記 [DB] 儲存Caffe資料的LevelDB類

Caffe 原始碼閱讀筆記 [DB] 儲存Caffe資料的LevelDB類

概述

上一篇文章 描述Caffe如何從DB讀取訓練集資料。這篇要研究DB的具體實現是什麼樣子的。Caffe目前支援從LevelDB和lmdb兩種key-value store讀取和儲存資料。我個人認為rocksdb(leveldb的改進版)比lmdb效能會更好。因此我只對Caffe如何使用leveldb感興趣,lmdb的部分因為時間關係略過。

三個基本類Cursor, Transaction, DB

Caffe建立了三個基本類DB, Transaction, Cursor,如果開發者要引進新的資料庫,只需要繼承並實現這三個基本類的函式即可,非常方便。DB::GetDB(backend) 函式會根據backend的值初始化相應的資料庫型別,比如如果backend=”leveldb”,GetDB會返回new LevelDb();

enum Mode { READ, WRITE, NEW }; // 開啟資料庫的三種模式:只讀,寫,新建資料庫
// 類似於map的iterator
class Cursor { 
  virtual void SeekToFirst() = 0;
  virtual void Next() = 0;
  virtual string key() = 0;
  virtual string value() = 0;
  virtual bool valid() = 0;
};
// 批量寫操作。
class Transaction {
  virtual void Put(const string& key, const
string& value) = 0; virtual void Commit() = 0; }; // 資料庫定義 class DB { virtual void Open(const string& source, Mode mode) = 0; // 用指定模式開啟資料庫 virtual void Close() = 0; // 關閉資料庫 virtual Cursor* NewCursor() = 0; // 新建一個遍歷指標 virtual Transaction* NewTransaction() = 0; //新建一個寫事務 };

LevelDBCursor

只有一個iter_變數,Cursor內對應函式淺顯易懂分別是
iter_->SeekToFirst(),iter_->Next(),iter_->key().ToString(),iter_->value().ToString(),iter_->Valid()

LevelDBTransaction

void Put(const string& key, const string& value) {
  // leveldb::WriteBatch 型別,快取更新db[key] = value;
  batch_.Put(key, value);
}
void Commit() {
  // 持久化batch_內快取的資料
  leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch_);
}

LevelDB

void LevelDB::Open(const string& source, Mode mode) {
  leveldb::Options options;
  options.block_size = 65536; // leveldb最小讀取單位,即每讀取一對key-value,需要把64KB的資料讀入記憶體
  options.write_buffer_size = 268435456; // leveldb的memtable大小是256MB,一旦memtable超過256MB,它會變成只讀的memtable並持久化
  options.max_open_files = 100; // leveldb把開啟的檔案fd快取在table cache裡,讀操作會去table cache裡面找要讀的檔案進行讀取。Caffe只允許快取最多100個檔案的fd
  options.error_if_exists = mode == NEW;
  options.create_if_missing = mode != READ; // 如果不存在而且不是隻讀模式,建立新資料庫
  leveldb::Status status = leveldb::DB::Open(options, source, &db_);
  CHECK(status.ok()) << "Failed to open leveldb " << source
                     << std::endl << status.ToString();
}
NewCursor() : return new LevelDBCursor(db_->NewIterator(leveldb::ReadOptions()));
NewTransaction(): return new LevelDBTransaction(db_);