我们先看下面代码
1074 { 1075 mutex_.Unlock(); 1076 // First look in the memtable, then in the immutable memtable (if any). 1077 LookupKey lkey(key, snapshot); 1078 if (mem->Get(lkey, value, &s)) { 1079 // Done 1080 } else if (imm != NULL && imm->Get(lkey, value, &s)) { 1081 // Done 1082 } else { 1083 s = current->Get(options, lkey, value, &stats); 1084 have_stat_update = true; 1085 } 1086 mutex_.Lock(); 1087 }
从上面的代码可以看出,查询过程首先是在memTable不查找,如果找不到并且存在 immutable memtable,那么就在这里查找, 实在找不到,最后去ssTable中查找。
我们知道memTable 和immutable memTable都是使用跳表的结构实现,他们的查找就是在跳表中查找,这里就不介绍,我们主要来介绍下ssTable查找过程。
version_set.cc
Status Version::Get(const ReadOptions& options, const LookupKey& k, std::string* value, GetStats* stats) { Slice ikey = k.internal_key(); Slice user_key = k.user_key(); const Comparator* ucmp = vset_->icmp_.user_comparator(); Status s; stats->seek_file = NULL; stats->seek_file_level = -1; FileMetaData* last_file_read = NULL; int last_file_read_level = -1; // We can search level-by-level since entries never hop across // levels. Therefore we are guaranteed that if we find data // in an smaller level, later levels are irrelevant. std::vector<FileMetaData*> tmp; FileMetaData* tmp2; //从最底层开始,往上查找 for (int level = 0; level < config::kNumLevels; level++) { size_t num_files = files_[level].size(); if (num_files == 0) continue; // Get the list of files to search in this level FileMetaData* const* files = &files_[level][0]; if (level == 0) { // Level-0 files may overlap each other. Find all files that // overlap user_key and process them in order from newest to oldest. tmp.reserve(num_files); for (uint32_t i = 0; i < num_files; i++) { FileMetaData* f = files[i]; if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && ucmp->Compare(user_key, f->largest.user_key()) <= 0) { tmp.push_back(f); } } if (tmp.empty()) continue; std::sort(tmp.begin(), tmp.end(), NewestFirst); files = &tmp[0]; num_files = tmp.size(); } else { // Binary search to find earliest index whose largest key >= ikey. uint32_t index = FindFile(vset_->icmp_, files_[level], ikey); if (index >= num_files) { files = NULL; num_files = 0; } else { tmp2 = files[index]; if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0) { // All of "tmp2" is past any data for user_key files = NULL; num_files = 0; } else { files = &tmp2; num_files = 1; } } } for (uint32_t i = 0; i < num_files; ++i) { if (last_file_read != NULL && stats->seek_file == NULL) { // We have had more than one seek for this read. Charge the 1st file. stats->seek_file = last_file_read; stats->seek_file_level = last_file_read_level; } FileMetaData* f = files[i]; last_file_read = f; last_file_read_level = level; Saver saver; saver.state = kNotFound; saver.ucmp = ucmp; saver.user_key = user_key; saver.value = value; s = vset_->table_cache_->Get(options, f->number, f->file_size, ikey, &saver, SaveValue); if (!s.ok()) { return s; } switch (saver.state) { case kNotFound: break; // Keep searching in other files case kFound: return s; case kDeleted: s = Status::NotFound(Slice()); // Use empty error message for speed return s; case kCorrupt: s = Status::Corruption("corrupted key for ", user_key); return s; } } } return Status::NotFound(Slice()); // Use an empty error message for speed }
整个过程从level 0开始,逐层往上查找,找到就返回。 每层查找又分为查找候选文件和对候选文件内查找。查找候选文件除了level 0 是全部检测以后,其它都采用二分查找就可以。 文件内部查找调用
vset_->table_cache_->Get 实现。 最后对查到的结果进行类型判断(found, no found , corrupt)
最后我们再来看看这个table_cache中Get的实现