RocksDB引擎載入

jesselyu發表於2017-04-05

RocksDB引擎的載入,具體操作是透過DB:Open()方法進行的,具體實現類是DBImpl類。 1.引擎載入call stack

Rocksdb引擎註冊和載入時call stack:

###Step 1.在storage engine plugin中的宣告,在ha_rocksdb.cc原始檔中

myrocks::rocksdb_init_func, /* Plugin Entry Point */

### Step 2.初始化plugin,在載入時被呼叫,在ha_rocksdb.cc原始檔中

static int rocksdb_init_func(void *p)

### Step 3.開啟TransactionDB,事務支援,在transaction_db.cc原始檔中

status= rocksdb::TransactionDB::Open(main_opts, tx_db_options,rocksdb_datadir, cf_descr,

&cf_handles, &rdb);

###4.最終呼叫DBImpl實現類的DB::Open方法,完成引擎載入,這裡面的

###dbname不是資料庫名,而是rocksdb的”data_dir”。在db_impl.cc原始檔中

s = DB::Open(db_options_2pc, dbname, column_families_copy, handles, &db);

s = ValidateOptions(db_options, column_families);

當DB::Open()方法被呼叫並載入引擎時,在此database中的所有CF將被初始化。 2.Column Families後設資料讀取

在上面的”Step 2”中,也就是初始化plugin時,會根據rocksdb的”data_dir”,list出所有的cf,也就是會呼叫下面的方法:

status= rocksdb::DB::ListColumnFamilies(rocksdb_db_options, rocksdb_datadir,&cf_names);

這裡,我們詳細看一下cf是如何被全部list出來的。

在rocksdb的”data_dir”目錄下面有一個“CURRENT”檔案。我們來strings一把,發現CURRENT檔案中存放的內容為“MANIFEST-000017”,這個內容剛好是當前最新的MANIFEST檔案。

clip_image002[4]

clip_image004[5]

clip_image005[5]

那麼,這是不是巧合呢?我們來看一下原始碼上的執行路徑:

###Step 1:找到CURRENT檔案

// Read "CURRENT" file, which contains a pointer to the current manifest file

std::string current;

Status s = ReadFileToString(env, CurrentFileName(dbname), ¤t);

###Step 2:讀取CURRENT檔案

std::string CurrentFileName(const std::string& dbname) {

return dbname + "/CURRENT";

}

###Step3: 從MANIFEST檔案中讀取column families,”default”放在“slot 0“中

std::map column_family_names;

// default column family is always implicitly there

column_family_names.insert({0, kDefaultColumnFamilyName});

從原始碼分析知道,這裡的讀取只是簡單的後設資料資訊而已,並沒有真正的生成記憶體handle物件。真正生成handle物件是在引擎開啟的時候,也就是呼叫DB::Open()方法的時候。

DB::Open方法是開啟rocksdb引擎的入口,它有多個方法的過載。其中有一個過載方法的引數中並沒有”column families”,它只有DB option,dbname(實際上是data_dir)以及DB的指標。這個方法,預設只初始化了”default” CF,隨後將cf以及空的cf handles傳給第二個同名過載方法進行其它非預設CF 初始化。

Status DB::Open(const Options& options, const std::string& dbname, DB** dbptr){

column_families.push_back(

ColumnFamilyDescriptor(kDefaultColumnFamilyName, cf_options));

std::vector handles;

Status s = DB::Open(db_options, dbname, column_families, &handles, dbptr);

…};

這第二個帶”column_families”和“handles”引數的DB:Open過載方法是初始化和載入所有CF的關鍵。

這裡值得一提的是,如果這個過載方法呼叫後,返回的handles中只有一個元素(handle[0]永遠指向”default” CF); 那麼這個元素將從handles中刪除,因為DBImpl類永遠有一個指標指向”default” CF,不需要再透過handles來獲取。

進入DB:Open()過載方法體後,會進行一系列的檢查,主要檢查db_option和cf option。

db_option主要檢查資料庫的db_path,這個db_path就是我們存放SST Table的物理位置。如果沒有特意配置db_path,那麼一個資料庫只允許存放到一個目錄下。另外,如果指定db_path時,不允許超過4個。

Cf主要檢查各個level 的SST Table當前配置的壓縮演算法是否支援,也就是在原始碼編譯的時候,是否已經link進來。如果沒有,則在open的時候就會報錯,導致rocksdb引擎載入失敗。 3.初始化Table Cache和memTable

進入DB:Open()之後,會new出實現類DBImpl。在DBImpl的構造方法中,主要完成以下幾個功能:

l 初始化table_cache_size

如果“max_open_files==-1“,那table_cache_size的值是” 4194304”,否則就是” max_open_files-10”,保留10個用於其它用途。並按此size初始化table LRU cache佇列。

l 初始化column families 的memTable

根據上面ListColumnFamilies()方法拿到的column families,初始對應的memTable

l DUMP資料庫資訊到日誌檔案

將各種檔案資訊DUMP到rocksdb的日誌檔案中,當然也包含option資訊,還包含SST當前Table所支援的壓縮演算法等

clip_image007[5] 4.執行recover

在recover之前,會對wal_dir以及archive_dir目錄進行檢查,如果沒有就會重新建立目錄,預設在db_path下面。

###這把是instrumented鎖,用於統計資訊之類

impl->mutex_.Lock();

// Handles create_if_missing, error_if_exists

###開始恢復操作

s = impl->Recover(column_families);

進入recover()方法後,會去檢查wal_dir和db_path目錄,並且檢查db_path目錄下的“CURRENT”,”IDENTITY”和“LOCK”檔案。

首先會檢查“LOCK”檔案;再檢查“CURRENT”檔案,此檔案主要指向當前最新的“MANIFEST”檔案,上文已經提到過;最後檢查“IDENTIFY”檔案,此檔案中存放當前rocksdb的唯一標識。

找到“MANIFEST”檔案後,讀取最近“MANIFEST“檔案中的內容。當然首先會判斷”MANIFEST”檔案是否損壞,是否以正常的”\n”結尾。如果”MANIFEST”檔案正常,則開始執行從”MANIFEST”檔案恢復操作。“MANIFEST“檔案類似於Oracle的控制檔案,因此在運維層面需要不斷的備份。

這裡的recover僅僅是檢查並恢復“MANIFEST”檔案中的記錄到記憶體中,這裡會再一次的讀取“MANIFEST”檔案中儲存的column families資訊,並跟前面ListColumnFamilies()方法中讀取到的column families做一個比對。

但是跟ListColumnFamilies()方法不同的是,這裡除了讀取column families資訊以外,還會讀取last_sequence,next_file_number,max_column_familiy等內容。

隨後在DBImpl::CheckConsistency()類中遍歷每個CF下的SST Table物理檔案,檢查實際檔案大小與“MANIFEST“檔案中的後設資料是否一致,如果不一致,則說明已經損壞。

接下來,將是recover的重要一步,就是獲取rocksdb的wal日誌進行回放,apply log的詳細過程,這需先不贅述,下次再展開。

s = RecoverLogFiles(logs, &next_sequence, read_only);

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30088583/viewspace-2136675/,如需轉載,請註明出處,否則將追究法律責任。

相關文章