// A Compaction encapsulates information about a compaction. classCompaction { private: friendclassVersion; // 友元类和私有的构造函数 friendclassVersionSet; Compaction(const Options *options, int level);
int level_; // Compaction文件所在的Level uint64_t max_output_file_size_; // 生成文件最大值 Version *input_version_; // 输入的版本号 VersionEdit edit_; // Compaction结果保存的VersionEdit
// Each compaction reads inputs from "level_" and "level_+1" // 两个元素分别对应两层的sstable std::vector<FileMetaData *> inputs_[2]; // The two sets of inputs
// State used to check for number of overlapping grandparent files // (parent == level_ + 1, grandparent == level_ + 2) // 一些状态,用来检查是否存在重叠现象 std::vector<FileMetaData *> grandparents_; size_t grandparent_index_; // Index in grandparent_starts_ bool seen_key_; // Some output key has been seen int64_t overlapped_bytes_; // Bytes of overlap between current output // and grandparent files
// State for implementing IsBaseLevelForKey
// level_ptrs_ holds indices into input_version_->levels_: our state // is that we are positioned at one of the file ranges for each // higher level than the ones involved in this compaction (i.e. for // all L >= level_ + 2). size_t level_ptrs_[config::kNumLevels];
public: ~Compaction();
// Return the level that is being compacted. Inputs from "level" // and "level+1" will be merged to produce a set of "level+1" files. // 返回正在压缩的level intlevel()const{ return level_; }
// Return the object that holds the edits to the descriptor done // by this compaction. // 返回压缩完成后的VersionEdit VersionEdit *edit(){ return &edit_; }
// "which" must be either 0 or 1 // 输入的文件个数 intnum_input_files(int which)const{ return inputs_[which].size(); }
// Return the ith input file at "level()+which" ("which" must be 0 or 1). // 返回输入的文件 FileMetaData *input(int which, int i)const{ return inputs_[which][i]; }
// Maximum size of files to build during this compaction. // 压缩中最大的文件数目 uint64_tMaxOutputFileSize()const{ return max_output_file_size_; }
// Is this a trivial compaction that can be implemented by just // moving a single input file to the next level (no merging or splitting) // 是否是平凡移动,即不经过任何归并直接移动到下一层 boolIsTrivialMove()const;
// Add all inputs to this compaction as delete operations to *edit. // 把所有的输入文件在一个VersionEdit中删掉 voidAddInputDeletions(VersionEdit *edit);
// Returns true if the information we have available guarantees that // the compaction is producing data in "level+1" for which no data exists // in levels greater than "level+1". // 函数返回true表示user_key不存在于高层中 boolIsBaseLevelForKey(const Slice &user_key);
// Returns true iff we should stop building the current output // before processing "internal_key". // 在处理内部key之前需要停止构建当前输出的时候返回true boolShouldStopBefore(const Slice &internal_key);
// Release the input version for the compaction, once the compaction // is successful. // 压缩完成,释放输入版本 voidReleaseInputs(); };
if (status.ok()) { // Done } elseif (shutting_down_.load(std::memory_order_acquire)) { // Ignore compaction errors found during shutting down } else { Log(options_.info_log, "Compaction error: %s", status.ToString().c_str()); }
if (is_manual) { ManualCompaction *m = manual_compaction_; if (!status.ok()) { m->done = true; } if (!m->done) { // We only compacted part of the requested range. Update *m // to the range that is left to be compacted. m->tmp_storage = manual_end; m->begin = &m->tmp_storage; } manual_compaction_ = nullptr; } }
Compaction *VersionSet::PickCompaction() { Compaction *c; int level;
// We prefer compactions triggered by too much data in a level over // the compactions triggered by seeks. constbool size_compaction = (current_->compaction_score_ >= 1); constbool seek_compaction = (current_->file_to_compact_ != nullptr); if (size_compaction) { level = current_->compaction_level_; assert(level >= 0); assert(level + 1 < config::kNumLevels); c = newCompaction(options_, level);
// Pick the first file that comes after compact_pointer_[level] for (size_t i = 0; i < current_->files_[level].size(); i++) { FileMetaData *f = current_->files_[level][i]; if (compact_pointer_[level].empty() || icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) { c->inputs_[0].push_back(f); break; } } if (c->inputs_[0].empty()) { // Wrap-around to the beginning of the key space c->inputs_[0].push_back(current_->files_[level][0]); } } elseif (seek_compaction) { level = current_->file_to_compact_level_; c = newCompaction(options_, level); c->inputs_[0].push_back(current_->file_to_compact_); } else { returnnullptr; }
// Files in level 0 may overlap each other, so pick up all overlapping ones if (level == 0) { InternalKey smallest, largest; GetRange(c->inputs_[0], &smallest, &largest); // Note that the next call will discard the file we placed in // c->inputs_[0] earlier and replace it with an overlapping set // which will include the picked file. current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]); assert(!c->inputs_[0].empty()); }