1.如果存在immutable memtable,将其dump成sstable,完成返回。
2.如果是外部触发的compact,根据manual_compaction指定的level/start_key/end_key,选出compaction(VersionSet::CompactRange())
3.如果不是manual compact,则根据db当前状态,选出compaction(VersionSet::PickCompaction()),考虑到level sstable的均衡性,提高查找效率。class compaction用于记录compact信息,包括compact的level和输入sstable文件等等,参见version_set.h。
4.对于非manual compact并且选出的sstable都处于level-n且不会造成过多的GrandparentOverrlap(Compaction::IsTrivialMove()),简单处理,将这些sstable推到level-n+1,更新db元信息即可(VersionSet::LogAndApply())。
5.其他情况,则一律根据确定出的Compaction,做具体的compact处理(DBImpl::DoCompactionWork()),最后做异常情况的清理(DBImpl::CleanupCompaction())。
DBimpl::DoCompactionWork(),实际的compact过程就是对多个已经排序的sstable做一次merge排序,丢弃掉相同的Key以及删除的数据。
Status DBImpl::DoCompactionWork(CompactionState* compact) { const uint64_t start_micros = env_->NowMicros(); //immutable compact时计时用 int64_t imm_micros = 0; // Micros spent doing imm_ compactions Log(options_.info_log, "Compacting %d@%d + %d@%d files", compact->compaction->num_input_files(0), compact->compaction->level(), compact->compaction->num_input_files(1), compact->compaction->level() + 1); assert(versions_->NumLevelFiles(compact->compaction->level()) > 0); assert(compact->builder == NULL); assert(compact->outfile == NULL); if (snapshots_.empty()) { compact->smallest_snapshot = versions_->LastSequence(); } else { compact->smallest_snapshot = snapshots_.oldest()->number_; } // Release mutex while we're actually doing the compaction work mutex_.Unlock(); //将选出的compaction中的sstable构造MergingIterator //对于level-0做归并排序,其他level的sstable做一个连接他们的iterator Iterator* input = versions_->MakeInputIterator(compact->compaction); //定位到每一个sstable的first,后面将遍历input sstable的entry input->SeekToFirst(); Status status; ParsedInternalKey ikey; std::string current_user_key; bool has_current_user_key = false; SequenceNumber last_sequence_for_key = kMaxSequenceNumber; for (; input->Valid() && !shutting_down_.Acquire_Load(); ) { // Prioritize immutable compaction work //优先完成immutable的compact if (has_imm_.NoBarrier_Load() != NULL) { const uint64_t imm_start = env_->NowMicros(); mutex_.Lock(); if (imm_ != NULL) { CompactMemTable(); bg_cv_.SignalAll(); // Wakeup MakeRoomForWrite() if necessary } mutex_.Unlock(); imm_micros +