2018年5月23日 星期三

Google LevelDB 原始碼解說 (三) LevelDB中不同Key的種類

在瀏覽LevelDB的資料時,會看到許多對key結構上的描述,應該有許多人會像我剛開始看時一樣,覺得LevelDB有那麼多種Key?其實這都是層層相關的,從下圖便可以看出其中結構。





User Key


我們先從最底層開始看起,User key就是用戶所傳入的鍵值數據

Slice user_key

ParsedInternalKey&InternalKey


InternalKey是有幾個部分組合成的一個key,ParsedInternalKey就是對InternalKey分拆後的結果,也就是說InternalKey是由User key + SequenceNumber + ValueType組合而成的
InternalKey的格式為: | User key (string) | sequence number (7 bytes) | value type (1 byte) |

  1. // ValueType代表這個數據是要插入還是刪除,0就刪除,1就保留
  2. enum ValueType {
  3. kTypeDeletion = 0x0,
  4. kTypeValue = 0x1
  5. };
  6. // kValueTypeForSeek defines the ValueType that should be passed when
  7. // constructing a ParsedInternalKey object for seeking to a particular
  8. // sequence number (since we sort sequence numbers in decreasing order
  9. // and the value type is embedded as the low 8 bits in the sequence
  10. // number in internal keys, we need to use the highest-numbered
  11. // ValueType, not the lowest).
  12. static const ValueType kValueTypeForSeek = kTypeValue;
  13.  
  14. typedef uint64_t SequenceNumber;
  15.  
  16. // We leave eight bits empty at the bottom so a type and sequence#
  17. // can be packed together into 64-bits.
  18. // 這裡定義SequenceNum可以取值的範圍[0,2^56-1)
  19. static const SequenceNumber kMaxSequenceNumber =
  20. ((0x1ull << 56) - 1);
  21. // ParsedInternalKey則是將InternalKey分拆的結果,由user_key,sequenceNum,type組成
  22. struct ParsedInternalKey {
  23. Slice user_key;
  24. SequenceNumber sequence;
  25. ValueType type;
  26.  
  27. ParsedInternalKey() { } // Intentionally left uninitialized (for speed)
  28. ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t)
  29. : user_key(u), sequence(seq), type(t) { }
  30. std::string DebugString() const;
  31. };
  32.  
  33. // Return the length of the encoding of "key".
  34. // 因為InternalKey是user_Key,sequenceNum,type組成,因為sequenceNum和type共64bit,
  35. // 也就是8bytes,所以長度就是user_key+8
  36. inline size_t InternalKeyEncodingLength(const ParsedInternalKey& key) {
  37. return key.user_key.size() + 8;
  38. }

LookupKey & Memtable Key


Memtable的查詢接口傳入的是LookupKey,它也是由User Key和Sequence Number組合而成的,從其函數:LookupKey(const Slice& user_key, SequenceNumber s)中分析出LookupKey的格式為

| Size (varint32)| User key (string) | sequence number (7 bytes) | value type (1 byte) |


  • start_為字串的開始地址
  • end_為字串的結束地址
  • kstart_紀錄user_key的起始地址
    *LookupKey的size是變長存儲的,因此它使用kstart_記錄了user key string的起始地址,否則將不能正確的獲取size和user key;

  1. class LookupKey {
  2. public:
  3. // Initialize *this for looking up user_key at a snapshot with
  4. // the specified sequence number.
  5. LookupKey(const Slice& user_key, SequenceNumber sequence);
  6.  
  7. ~LookupKey();
  8.  
  9. // Return a key suitable for lookup in a MemTable.
  10. // 從下方得知LookupKey為 Memtable Key 的 Slice 形式
  11. Slice memtable_key() const { return Slice(start_, end_ - start_); }
  12.  
  13. // Return an internal key (suitable for passing to an internal iterator)
  14. // 因為internalkey為user_key+sequenceNum+type,所以是 Slice(kstart_, end_-kstart_)
  15. Slice internal_key() const { return Slice(kstart_, end_ - kstart_); }
  16.  
  17. // Return the user key
  18. // user_key就是再扣掉sequenceNum跟type所以是8
  19. Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); }
  20.  
  21. private:
  22. // We construct a char array of the form:
  23. // klength varint32 <-- start_
  24. // userkey char[klength] <-- kstart_
  25. // tag uint64
  26. // <-- end_
  27. // The array is a suitable MemTable key.
  28. // The suffix starting with "userkey" can be used as an InternalKey.
  29. const char* start_;
  30. const char* kstart_;
  31. const char* end_;

下方為LookupKey的實作


  1. LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) {
  2. size_t usize = user_key.size();// user_key長度
  3. size_t needed = usize + 13; // A conservative estimate
  4. // +13是 sequenceNum+type=8 和 varint32最大為5bytes
  5.  
  6. char* dst;
  7. if (needed <= sizeof(space_)) {
  8. dst = space_;
  9. } else {
  10. dst = new char[needed];//若超過預留得space_就要重新分配
  11. }
  12. //下方為計算start_,kstart_,end_的實作
  13. start_ = dst;
  14. dst = EncodeVarint32(dst, usize + 8);
  15. kstart_ = dst;
  16. memcpy(dst, user_key.data(), usize);
  17. dst += usize;
  18. EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek));
  19. dst += 8;
  20. end_ = dst;
  21. }

沒有留言:

張貼留言

熱門文章