Version-levelDB源碼解析


【數據成員介紹】

compaction_level_:下一個需要做compact的層級;

compaction_score_:比分,如果比分小於1,就代表沒有那麼緊急去需要做compact;

那麼比分的規則是什麼呢?

void VersionSet::Finalize(Version* v) {

    int best_level = -1;

    double best_score = -1;

    for (int level = 0; levle < config::kNumberLevels - 1; level++) {

        double score;

        if (levle == 0) {

            score = v->files_[level].size() / static_cast<double>(config::kL0_CompactionTrigger);

        } else {

            const uint64_t level_bytes = TotalfileSize(v->files_[level]);

            score = static_cast<double>(level_byles) / MaxBylesForLevel(level);

        }   

        if (score > best_score) {

            best_level = level;

            best_score = score;

        }

    }

    v->compaction_levle_ = best_level;

    v->compaction_score = best_score;

}

從這個函數就可以看出,挑選出比分最高的層,就是下一個最需要做compact的層。從函數中可以看出,level 0的比分規則和其他層不一樣,level 0是按照已有的sst文件數/一個限制值(這裏是4),其它層是按照文件大小來比的,現有文件大小/該層文件大小限制。每層的文件大小限制versionset裏面有講,這裏就不囉嗦了。爲什麼採用不同的標準來比分呢?有兩個原因:一方面當write-buffer很大的時候,不用很頻繁的對level 0做compact,另一方面,當讀取的時候,文件太多會導致merge的成本變高,所以level 0的文件數要限制。


file_to_compact_;基於seek stats來決定下一個要compact的文件

file_to_compact_level_;file_to_compact_所在的層級;

那麼挑選下一個進行compact的規則又是什麼呢?這個放在後面說。


files_:該版本每個level的sst文件的FileMetaData

next_:指向下一個版本的指針;

prev_:指向上一個版本的指針;

refs_:引用計數;

vset_:指向一個versionset



【方法成員介紹】

Status Version::Get(const ReadOptions& options,const LookupKey& k,std::string* value,GetStats* stats)

作用:獲得要查詢key的值

Get方法,是在取數據的時候調用,如果能通過MemTable(Immutable Memtable、Memtable)找到,就不會調這個。下面分析下這個方法的邏輯。

step1:通過files_,循環每一層,根據leveldb的特性,如果這個key在上層能找到,就不用繼續往下層找了,因爲上層的數據一定比下層更新。

step2:level 0比較特殊,它的sst文件之間的key範圍是存在交疊的,所以首先要找出包含key的所有sst,然後將其排序,最新(文件編號越大越新)的放前面;其他level(大於0)存在一個特性,就是sst文件之間的key  range是沒有交疊的,這麼設計的目的就是爲了現在,在讀取的時候不用處理交疊的情況,提高讀的效率,所以只要找出一個包含要查找key的sst文件即可,就可以結束在該層的查找了。

step3:在sst中查找,先在table cache中找(table cache中採用的是LRU算法,後面詳細介紹),找不到再讀文件。



void Version::GetOverlappingInputs(int level,const InternalKey* begin,const InternalKey* end,std::vector<FileMetaData*>* inputs)

作用:獲得在某一個level中和key range[begin,end]有交疊的所有文件,結果保存在inputs,如果是level 0,並且有新增的文件,會擴大這個range,重新搜索。


bool Version::OverlapInLevel(int level,const Slice* smallest_user_key,const Slice* largest_user_key)

作用:判斷指定範圍的key range[smallest_user_key,largest_user_key]在指定的level是否有交疊。


int Version::PickLevelForMemTableOutput(const Slice& smallest_user_key,const Slice& largest_user_key)

作用:爲memTable的dump到sst挑選出一個合適的層。很多人以爲數據是從memtable直接dump到level 0 的,其實不然。讓我先分析下這個函數的邏輯吧。

step1:如果range[smallest_user_key,largest_user_key]和level 0有交疊,那麼就選level 0,這個時候判斷是否有交疊的函數(bool Version::OverlapInLevel)就派上用場了。

step2:當level < config::kMaxMemCompactLevel情況下進行循環,如果和level + 1層沒有交疊,和level + 2層交疊的sst文件大小沒有超過kMaxGrandParentOverlapBytes,那麼就往下一層進行選擇;config::kMaxMemCompactLevel=2,也就是說挑選出來的level要麼是level 0層,要麼是level 1層。

這麼做的目的,我覺得是一個折中的策略,一方面不直接放level 0,減少level 0的文件數,就可以提高讀取的效率,還可以減少compact;另一方面,kMaxMemCompactLevel=2,如果太大,在讀取的時候,會增加seek的次數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章