leveldb当中所有kv都有一个版本号,通过版本号来实现快照功能,可以进行并发的读写操作。

Status DBImpl::Get(const ReadOptions& options, const Slice& key,  
                   std::string* value) {  
  Status s;  
  MutexLock l(&mutex_);  
  // 指定了快照那么就使用指定快照的版本号,没有指定则使用最新的版本号
  SequenceNumber snapshot;  
  if (options.snapshot != nullptr) {  
    snapshot =  
        static_cast<const SnapshotImpl*>(options.snapshot)->sequence_number();  
  } else {  
    snapshot = versions_->LastSequence();  
  }  
  // 引用mem_, imm_,当前版本current,避免读取过程中内存被释放
  MemTable* mem = mem_;  
  MemTable* imm = imm_;  
  Version* current = versions_->current();  
  mem->Ref();  
  if (imm != nullptr) imm->Ref();  
  current->Ref();  
  
  bool have_stat_update = false;  
  Version::GetStats stats;  
  
  // Unlock while reading from files and memtables 
  // 读取文件过程中不需要加锁,因为不涉及文件的修改 
  {  
    mutex_.Unlock();  
    // First look in the memtable, then in the immutable memtable (if any). 
    // 现在memtable中找,然后在immutable memtable中找 
    LookupKey lkey(key, snapshot);  
    if (mem->Get(lkey, value, &s)) {  
      // Done  
    } else if (imm != nullptr && imm->Get(lkey, value, &s)) {  
      // Done  
    } else {  
      // 到文件中找
      s = current->Get(options, lkey, value, &stats);  
      have_stat_update = true;  
    }  
    mutex_.Lock();  
  }  
  
  if (have_stat_update && current->UpdateStats(stats)) {  
    MaybeScheduleCompaction();  
  }  
  mem->Unref();  
  if (imm != nullptr) imm->Unref();  
  current->Unref();  
  return s;  
}

查找的流程就是memtable immutable memtable table文件集。

将k组装成memtable中entry里key的形式,然后可以进行比较判断key是否存在。前面两者都没有找到,那么就会版本对应的文件当中查找对应的key。