From bc5dd19b141b1faaba28ac8b122dc5d3d6fa1f56 Mon Sep 17 00:00:00 2001 From: Siying Dong Date: Mon, 9 Dec 2013 14:28:26 -0800 Subject: [PATCH] [RocksDB Performance Branch] Avoid sorting in Version::Get() by presorting them in VersionSet::Builder::SaveTo() Summary: Pre-sort files in VersionSet::Builder::SaveTo() so that when getting the value, no need to sort them. It can avoid the costs of vector operations and sorting in Version::Get(). Test Plan: make all check Reviewers: haobo, kailiu, dhruba Reviewed By: dhruba CC: nkg-, igor, leveldb Differential Revision: https://reviews.facebook.net/D14409 --- db/version_set.cc | 76 +++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/db/version_set.cc b/db/version_set.cc index adee80d04..2ebb64adf 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -450,17 +450,12 @@ void Version::Get(const ReadOptions& options, // levels. Therefore we are guaranteed that if we find data // in an smaller level, later levels are irrelevant (unless we // are MergeInProgress). - std::vector important_files; for (int level = 0; level < vset_->NumberLevels(); 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]; - important_files.clear(); - if (level == 0) { - important_files.reserve(num_files); - } // Some files may overlap each other. We find // all files that overlap user_key and process them in order from @@ -478,44 +473,42 @@ void Version::Get(const ReadOptions& options, start_index = FindFile(vset_->icmp_, files_[level], ikey); } - // Traverse the list, finding all overlapping files. - for (uint32_t i = start_index; i < num_files; i++) { + // Traverse each relevant file to find the desired key +#ifndef NDEBUG + FileMetaData* prev_file = nullptr; +#endif + for (uint32_t i = start_index; 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) { - important_files.push_back(f); - } else if (level > 0) { - // If on Level-n (n>=1) then the files are sorted. - // So we can stop looking when we are past the ikey. - break; - } - } - - if (important_files.empty()) continue; - - if (level == 0) { - if (vset_->options_->compaction_style == kCompactionStyleUniversal) { - std::sort(important_files.begin(), important_files.end(), NewestFirstBySeqNo); - } else { - std::sort(important_files.begin(), important_files.end(), NewestFirst); + if (ucmp->Compare(user_key, f->smallest.user_key()) < 0 || + ucmp->Compare(user_key, f->largest.user_key()) > 0) { + // Only process overlapping files. + if (level > 0) { + // If on Level-n (n>=1) then the files are sorted. + // So we can stop looking when we are past the ikey. + break; + } + // TODO: do we want to check file ranges for level0 files at all? + // For new SST format where Get() is fast, we might want to consider + // to avoid those two comparisons, if it can filter out too few files. + continue; } - } else { - // Sanity check to make sure that the files are correctly sorted #ifndef NDEBUG - num_files = important_files.size(); - for (uint32_t i = 1; i < num_files; ++i) { - FileMetaData* a = important_files[i-1]; - FileMetaData* b = important_files[i]; - int comp_sign = vset_->icmp_.Compare(a->largest, b->smallest); - assert(comp_sign < 0); + // Sanity check to make sure that the files are correctly sorted + if (prev_file) { + if (level != 0) { + int comp_sign = vset_->icmp_.Compare(prev_file->largest, f->smallest); + assert(comp_sign < 0); + } else { + // level == 0, the current file cannot be newer than the previous one. + if (vset_->options_->compaction_style == kCompactionStyleUniversal) { + assert(!NewestFirstBySeqNo(f, prev_file)); + } else { + assert(!NewestFirst(f, prev_file)); + } + } } + prev_file = f; #endif - } - - // Traverse each relevant file to find the desired key - num_files = important_files.size(); - for (uint32_t i = 0; i < num_files; ++i) { - FileMetaData* f = important_files[i]; bool tableIO = false; *status = vset_->table_cache_->Get(options, f->number, f->file_size, ikey, &saver, SaveValue, &tableIO, @@ -1113,6 +1106,13 @@ class VersionSet::Builder { MaybeAddFile(v, level, *base_iter); } } + // Pre-sort level0 for Get() + if (vset_->options_->compaction_style == kCompactionStyleUniversal) { + std::sort(v->files_[0].begin(), v->files_[0].end(), NewestFirstBySeqNo); + } else { + std::sort(v->files_[0].begin(), v->files_[0].end(), NewestFirst); + } + CheckConsistency(v); }