FileMetaData* f =stats.seek_file; if (f != NULL) { f->allowed_seeks--; if (f->allowed_seeks <=0 && file_to_compact_ == NULL) { file_to_compact_ = f; file_to_compact_level_ =stats.seek_file_level; return true; } } return false;变量allowed_seeks的值在sstable文件加入到version时确定,也就是后面将遇到的VersionSet::Builder::Apply()函数。
inputs->clear(); Slice user_begin, user_end; if (begin != NULL) user_begin =begin->user_key(); if (end != NULL) user_end = end->user_key(); const Comparator* user_cmp =vset_->icmp_.user_comparator();
S2 遍历该层的sstable文件,比较sstable的{minkey,max key}和传入的[begin, end],如果有重合就记录文件到@inputs中,需要对level 0做特殊处理。
for (size_t i = 0; i <files_[level].size(); ) { FileMetaData* f =files_[level][i++]; const Slice file_start =f->smallest.user_key(); const Slice file_limit =f->largest.user_key(); if (begin != NULL &&user_cmp->Compare(file_limit, user_begin) < 0) { //"f" 中的k/v全部在指定范围之前; 跳过 } else if (end != NULL&& user_cmp->Compare(file_start, user_end) > 0) { //"f" 中的k/v全部在指定范围之后; 跳过 } else { inputs->push_back(f); // 有重合,记录 if (level == 0) { // 对于level 0,sstable文件可能相互有重叠,所以要检查新加的文件 // 是否范围更大,如果是则扩展范围重新开始搜索 if (begin != NULL&& user_cmp->Compare(file_start, user_begin) < 0) { user_begin = file_start; inputs->clear(); i = 0; } else if (end != NULL&& user_cmp->Compare(file_limit, user_end) > 0) { user_end = file_limit; inputs->clear(); i = 0; } } } }
// S1 乱序、可能相交的文件集合,依次查找 for (size_t i = 0; i <files.size(); i++) { const FileMetaData* f =files[i]; if(AfterFile(ucmp,smallest_user_key, f) || BeforeFile(ucmp, largest_user_key, f)){ } else return true; // 有重合 } return false; // 没找到 // S2 有序&互不相交,直接二分查找 uint32_t index = 0; if (smallest_user_key != NULL) { // Findthe earliest possible internal key smallest_user_key InternalKeysmall(*smallest_user_key, kMaxSequenceNumber,kValueTypeForSeek); index = FindFile(icmp, files,small.Encode()); } if (index >= files.size())return false; // 不存在比smallest_user_key小的key return !BeforeFile(ucmp,largest_user_key, files[index]); //保证在largest_user_key之后
上面的逻辑使用到了AfterFile()和BeforeFile()两个辅助函数,都很简单。
static bool AfterFile(const Comparator* ucmp, const Slice* user_key, constFileMetaData* f) { return (user_key!=NULL&& ucmp->Compare(*user_key, f->largest.user_key())>0); } static bool BeforeFile(const Comparator* ucmp, constSlice* user_key, const FileMetaData* f) { return (user_key!=NULL&& ucmp->Compare(*user_key, f->smallest.user_key())<0); }
函数实现:
int level = 0; if (!OverlapInLevel(0,&smallest_user_key, &largest_user_key)) { //level 0无重合 // 如果下一层没有重叠,就压到下一层, // andthe #bytes overlapping in the level after that are limited. InternalKeystart(smallest_user_key, kMaxSequenceNumber, kValueTypeForSeek); InternalKeylimit(largest_user_key, 0, static_cast<ValueType>(0)); std::vector<FileMetaData*> overlaps; while (level <config::kMaxMemCompactLevel) { if (OverlapInLevel(level +1, &smallest_user_key, &largest_user_key)) break; // 检查level + 1层,有重叠就跳出循环 GetOverlappingInputs(level +2, &start, &limit, &overlaps); // 没理解这个调用 const int64_t sum =TotalFileSize(overlaps); if (sum >kMaxGrandParentOverlapBytes) break; level++; } } return level;这个函数在整个compaction逻辑中的作用在分析DBImpl时再来结合整个流程分析,现在只需要了解它找到一个level存放新的compaction就行了。