levelDB Get过程



Status DBImpl::Get(const ReadOptions& options,
    const Slice& key,
    std::string* value) {
  Status s;
  MutexLock l(&mutex_); //这里初始化levelDB的锁, 默认把锁加上
  SequenceNumber snapshot; //这里就是定义一个最新的一个操作号, 有一个全局
  唯一的SequenceNumber
    if (options.snapshot != NULL) { //如果要求取的是某一个版本的数据
      snapshot = reinterpret_cast<const SnapshotImpl*>(options.snapshot)->number_;
    } else {
      snapshot = versions_->LastSequence(); //否则就是最新的数据, 也就是当
      versions_里面最大的SequenceNumber的数据
    }

  MemTable* mem = mem_; //mem table
  MemTable* imm = imm_; //imm table
  Version* current = versions_->current(); //当前的version
  mem->Ref(); //对mem的引用+1, 这个ref主要是用来删除文件的时候判断, 如果这
  ref引用为0, 那么就可以删除掉.
    if (imm != NULL) imm->Ref();
  current->Ref(); //同样对当前版本的ref引用+1

  bool have_stat_update = false; //用来是否有更新, 如果有更新再判断是否启动compaction线程
  Version::GetStats stats;

  // Unlock while reading from files and memtables
  {
    mutex_.Unlock(); //把锁放开, 可以看到 正真加锁部分只有获得当前版本号
    , 以及获得当前最新的版本这一部分, 也就是说在具体的get操作之前就已经
      可以支持多个线程进行读取了. 为什么可以这么做呢? 首先获得了当前最新的
      current以后, 并把这个current 的引用+1, 就可以保证当前的这个version
      是不会被删除的, 同样对于当前的这个imm, mem ref+1 以后可以保证是不会
      呗删除掉得. 所以只要在这段时间锁住就可以. 如果这个时候又有新的key
      , 那么他这个时候写入的key 是一个新的SequenceNumber. 不会影响我们接
      下来读的结果.

      // First look in the memtable, then in the immutable memtable (if any).
      LookupKey lkey(key, snapshot);
    if (mem->Get(lkey, value, &s)) { //从mem里面读取这个key的 value  这
      里要注意memtable里面的kv 是如何排序的. 这里面key的排序是 首先按照
        SquenceNumber排序, 然后是操作类型(删除排在最前面), 然后是key的大小(
            具体再看一下Compaction里面)
        // Done
    } else if (imm != NULL && imm->Get(lkey, value, &s)) {
      // Done
    } else {
      s = current->Get(options, lkey, value, &stats); //如果mem 和
      imm 都找不到, 那么这个时候我们要从一个一个level里面去找.
        have_stat_update = true;
    }
    mutex_.Lock();
  }

  if (have_stat_update && current->UpdateStats(stats)) { //
    这里如果有更新, 那么会判断是否启动后台的Compaction() 进程
      MaybeScheduleCompaction();
  }
  mem->Unref(); //分别把 mem, imm, current 的ref - 1
  if (imm != NULL) imm->Unref();
  current->Unref();
  return s;
}