leveldb源碼學習——Cache

Leveldb中會使用cache來提高讀取性能,cache兩種數據,1,file meta信息,2,data block信息。
leveldb開放了cache的接口,用戶可以通過自定義cache類,完成對cache的定製化實現,另外leveldb定義了一個default cache,叫做LRU cache,在用戶未實現自定義cache類時,將使用此類作爲level的cache,本文脫離業務,單純分析LRU cache的實現.

首先概括此cache的特點,cache是爲了提高性能,用戶在獲取數據前(讀磁盤或者rpc)前,可以先通過在cache中查詢,用戶在存儲數據後,需要把最新數據寫入cache,或者失效之前的數據。

內存容量有限,所以cache需要限定capacity。如果插入的數據導致cache內存佔用超出了capacity,則需要選擇需要覆蓋的數據。這是內存cache設計最重要的方面之一。

LRUcache的特點是使用least recently used 策略來選擇需要覆蓋的數據,即,內存中優先保存最近使用過的數據,而覆蓋那些最久沒有使用過的數據

leveldb中的 LRUcache,關鍵點有

  • 使用hashtable 來實現查找節點
  • 使用兩個雙鏈表來區分數據新鮮度,in-use鏈表中保存新鮮數據,lru-list中保存已經很久沒有被使用的數據。通過節點的ref值來代表其新鮮度。

下面介紹具體類

LRUHandler

handler是cache中用到的基本存儲單元,有三個身份
- 保存了k-v數據
- 雙鏈表的節點
- hashtable的節點

// An entry is a variable length heap-allocated structure.  Entries
// are kept in a circular doubly linked list ordered by access time.
struct LRUHandle {
  void* value; //要cache的用戶數據
  void (*deleter)(const Slice&, void* value); //釋放數據的方法
  LRUHandle* next_hash;//hash表的指針
  LRUHandle* next;//雙鏈表的指針
  LRUHandle* prev;
  size_t charge;      // TODO(opt): Only allow uint32_t?
  size_t key_length;
  bool in_cache;      // Whether entry is in the cache.
  uint32_t refs;      // References, including cache reference, if present.
  uint32_t hash;      // Hash of key(); used for fast sharding and comparisons
  char key_data[1];   // Beginning of key

  Slice key() const {
    // For cheaper lookups, we allow a temporary Handle object
    // to store a pointer to a key in "value".
    if (next == this) {
      return *(reinterpret_cast<Slice*>(value));
    } else {
      return Slice(key_data, key_length);
    }                                                                                                                                                                              
  }
};

hash table

一個開鏈hash表。不同hash值的節點被組織在一條鏈表中保存,鏈表頭保存在一個數組中
hash table的主要方法包括
lookup
insert
remove

另外,當hash table中總的節點個數超過一定數值後,hash table將自動resize爲之前的兩倍大,並將舊數據重新hash到新table中,完成擴容。

LRUCache

LRU cache通過維護 hash table和兩個鏈表,來提供cache功能。
hash table和鏈表的節點是共享的,都是同一個LRU handler

這裏寫圖片描述

in-use鏈表中索引ref值大於1的節點, lru鏈表中索引ref=1的節點

每次lookup查到的節點,其ref值會增1,此時可能觸發lru鏈表中的節點進入in-use鏈表

用戶使用完節點後,會調用unref,ref值會減一,可能觸發in-use鏈表中的節點轉移到lru鏈表中。

ShardedLRUCache

多個LRUCache 均衡負擔一個名字空間的所有數據的cache任務,組成一個shardedLRU cache
這樣可以降低併發查詢cache時的競爭,查詢同一個LRUCache時需要上鎖, 如果所有的查詢都發往同一個Cache,造成的競爭會比較嚴重。

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