leveldb源碼學(xué)習(xí)--memtable之Key

leveldb中數(shù)據(jù)存儲(chǔ)過(guò)程

當(dāng)向leveldb寫入數(shù)據(jù)時(shí),首先將數(shù)據(jù)寫入log文件,然后在寫入memtable內(nèi)存中。log文件主要是用在當(dāng)斷電時(shí),內(nèi)存中數(shù)據(jù)會(huì)丟失,數(shù)據(jù)可以從log文件中恢復(fù)。當(dāng)memtable數(shù)據(jù)達(dá)到一定大小,會(huì)變?yōu)?code>immemtable,并自動(dòng)生成新的memtable,然后log文件也生成一個(gè)新的log文件。Immutable Memtable則被新的線程Dump到磁盤中,Dump結(jié)束則該Immutable Memtable就可以釋放了。memtable提供了寫入KV記錄,刪除以及讀取KV記錄的接口,但是事實(shí)上memtable并不執(zhí)行真正的刪除操作,刪除某個(gè)Key的Value在memtable內(nèi)是作為插入一條記錄實(shí)施的,但是會(huì)打上一個(gè)Key的刪除標(biāo)記,真正的刪除操作在后面的 Compaction過(guò)程中(是不是感覺(jué)和前面介紹的skiplist很相似,沒(méi)錯(cuò),memtable的核心結(jié)構(gòu)就是skiplist)

leveldb 中的 Key

user_key

Slice類,實(shí)質(zhì)上就是一個(gè)string,只不過(guò)稍微封裝了一下

class Slice {
 public:
   //something...和本文關(guān)系不大,不全部貼出來(lái)了
 private:
  const char* data_;
  size_t size_;
};

ParsedInternalKey

struct ParsedInternalKey {
  Slice user_key;
  SequenceNumber sequence;
  ValueType type;

  ParsedInternalKey() { }  // Intentionally left uninitialized (for speed)
  ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t)
      : user_key(u), sequence(seq), type(t) { }
  std::string DebugString() const;
};

ParsedInternalKey就是一個(gè)struct,其中SequenceNumberValueType定義如下:

enum ValueType {
  kTypeDeletion = 0x0,
  kTypeValue = 0x1
};
typedef uint64_t SequenceNumber;

InternalKey

class InternalKey {
 private:
  std::string rep_;
 public:
  InternalKey() { }   // Leave rep_ as empty to indicate it is invalid
  InternalKey(const Slice& user_key, SequenceNumber s, ValueType t) {
    AppendInternalKey(&rep_, ParsedInternalKey(user_key, s, t));
  }
  void DecodeFrom(const Slice& s) { rep_.assign(s.data(), s.size()); }
  Slice Encode() const {
    assert(!rep_.empty());
    return rep_;
  }
  Slice user_key() const { return ExtractUserKey(rep_); }
  void SetFrom(const ParsedInternalKey& p) {
    rep_.clear();
    AppendInternalKey(&rep_, p);
  }
  void Clear() { rep_.clear(); }

  std::string DebugString() const;
};

通過(guò)源碼我們可以看到InternalKey本質(zhì)上也是一個(gè)字符串,這個(gè)字符串是由ParsedInternalKey轉(zhuǎn)換而來(lái)的。下面看看具體的轉(zhuǎn)換函數(shù)

void AppendInternalKey(std::string* result, const ParsedInternalKey& key) {
  result->append(key.user_key.data(), key.user_key.size());
  PutFixed64(result, PackSequenceAndType(key.sequence, key.type));
}
static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) {
  assert(seq <= kMaxSequenceNumber);
  assert(t <= kValueTypeForSeek);
  return (seq << 8) | t;
}

實(shí)質(zhì)上就是一個(gè)字符串拼接的過(guò)程。(其中涉及到coding)

根據(jù)這個(gè)我們也能得到InternalKey的組成形式實(shí)際上就是

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

同樣從InternalKey中我們能獲得user_key,操作也十分簡(jiǎn)單

inline Slice ExtractUserKey(const Slice& internal_key) {
  assert(internal_key.size() >= 8);
  return Slice(internal_key.data(), internal_key.size() - 8);
}

InternalKey中我們能獲得TypeValue:

inline ValueType ExtractValueType(const Slice& internal_key) {
  assert(internal_key.size() >= 8);
  const size_t n = internal_key.size();
  uint64_t num = DecodeFixed64(internal_key.data() + n - 8);
  unsigned char c = num & 0xff;
  return static_cast<ValueType>(c);
}

LookupKey

memtable的查詢接口傳入的就是LookuoKey

bool Get(const LookupKey& key, std::string* value, Status* s);

先看一下LookupKey是怎么定義的

class LookupKey {
 public:
  LookupKey(const Slice& user_key, SequenceNumber sequence);
  ~LookupKey();
  Slice memtable_key() const { return Slice(start_, end_ - start_); }
  Slice internal_key() const { return Slice(kstart_, end_ - kstart_); }
  Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); }
 private:
  const char* start_;
  const char* kstart_;
  const char* end_;
  char space_[200];      // Avoid allocation for short keys
  // No copying allowed
  LookupKey(const LookupKey&);
  void operator=(const LookupKey&);
};

再看看構(gòu)造函數(shù)

LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) {
  size_t usize = user_key.size();
  size_t needed = usize + 13;  // A conservative estimate
  char* dst;
  if (needed <= sizeof(space_)) {
    dst = space_;
  } else {
    dst = new char[needed];
  }
  start_ = dst;
  dst = EncodeVarint32(dst, usize + 8);
  kstart_ = dst;
  memcpy(dst, user_key.data(), usize);
  dst += usize;
  EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek));
  dst += 8;
  end_ = dst;
}

這樣的話不難分析出,LookupKey的結(jié)構(gòu)如下:

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

這里的size其實(shí)就是user_key的長(zhǎng)度加8.
start_LookupKey字符串的開(kāi)始,end_是結(jié)束,kstart_user key字符串的起始地址

======
Key分析完了=。=明天再繼續(xù)分析memtable,啦啦啦啦啦啦啦

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • LevelDB是Google傳奇工程師Jeff Dean和Sanjay Ghemawat開(kāi)源的KV存儲(chǔ)引擎,無(wú)論從...
    CatKang閱讀 5,050評(píng)論 5 25
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,628評(píng)論 19 139
  • 你是什么鬼? leveldb : 老子是一個(gè)單機(jī)的KV數(shù)據(jù)庫(kù),適合寫多讀少,支持持久化,支持故障恢復(fù),咋樣,牛逼吧...
    戈風(fēng)閱讀 14,231評(píng)論 8 49
  • http://geek.csdn.net/news/detail/210469http://www.36dsj.c...
    Albert陳凱閱讀 5,635評(píng)論 1 21
  • 所有圖片點(diǎn)擊放大均清晰 脊髓 脊髓(spinal cord)是中樞神經(jīng)的低級(jí)部分,起源于胚胎時(shí)期神經(jīng)管的末端,原始...
    沫比閱讀 23,273評(píng)論 1 17

友情鏈接更多精彩內(nèi)容