LCOV - code coverage report
Current view: top level - src/leveldb/db - version_set.cc (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 82.4 % 852 702
Test Date: 2026-06-07 07:49:58 Functions: 89.5 % 76 68
Branches: 51.2 % 1027 526

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
       2                 :             : // Use of this source code is governed by a BSD-style license that can be
       3                 :             : // found in the LICENSE file. See the AUTHORS file for names of contributors.
       4                 :             : 
       5                 :             : #include "db/version_set.h"
       6                 :             : 
       7                 :             : #include <stdio.h>
       8                 :             : 
       9                 :             : #include <algorithm>
      10                 :             : 
      11                 :             : #include "db/filename.h"
      12                 :             : #include "db/log_reader.h"
      13                 :             : #include "db/log_writer.h"
      14                 :             : #include "db/memtable.h"
      15                 :             : #include "db/table_cache.h"
      16                 :             : #include "leveldb/env.h"
      17                 :             : #include "leveldb/table_builder.h"
      18                 :             : #include "table/merger.h"
      19                 :             : #include "table/two_level_iterator.h"
      20                 :             : #include "util/coding.h"
      21                 :             : #include "util/logging.h"
      22                 :             : 
      23                 :             : namespace leveldb {
      24                 :             : 
      25                 :       73550 : static size_t TargetFileSize(const Options* options) {
      26                 :       73550 :   return options->max_file_size;
      27                 :             : }
      28                 :             : 
      29                 :             : // Maximum bytes of overlaps in grandparent (i.e., level+2) before we
      30                 :             : // stop building a single file in a level->level+1 compaction.
      31                 :       73325 : static int64_t MaxGrandParentOverlapBytes(const Options* options) {
      32                 :       73325 :   return 10 * TargetFileSize(options);
      33                 :             : }
      34                 :             : 
      35                 :             : // Maximum number of bytes in all compacted files.  We avoid expanding
      36                 :             : // the lower level file set of a compaction if it would make the
      37                 :             : // total compaction cover more than this many bytes.
      38                 :           0 : static int64_t ExpandedCompactionByteSizeLimit(const Options* options) {
      39                 :           0 :   return 25 * TargetFileSize(options);
      40                 :             : }
      41                 :             : 
      42                 :       30250 : static double MaxBytesForLevel(const Options* options, int level) {
      43                 :             :   // Note: the result for level zero is not really used since we set
      44                 :             :   // the level-0 compaction threshold based on number of files.
      45                 :             : 
      46                 :             :   // Result for both level-0 and level-1
      47                 :       30250 :   double result = 10. * 1048576.0;
      48         [ +  + ]:       90750 :   while (level > 1) {
      49                 :       60500 :     result *= 10;
      50                 :       60500 :     level--;
      51                 :             :   }
      52                 :       30250 :   return result;
      53                 :             : }
      54                 :             : 
      55                 :         225 : static uint64_t MaxFileSizeForLevel(const Options* options, int level) {
      56                 :             :   // We could vary per level to reduce number of files?
      57                 :         225 :   return TargetFileSize(options);
      58                 :             : }
      59                 :             : 
      60                 :       30623 : static int64_t TotalFileSize(const std::vector<FileMetaData*>& files) {
      61                 :       30623 :   int64_t sum = 0;
      62   [ -  +  +  + ]:       33126 :   for (size_t i = 0; i < files.size(); i++) {
      63                 :        2503 :     sum += files[i]->file_size;
      64                 :             :   }
      65                 :       30623 :   return sum;
      66                 :             : }
      67                 :             : 
      68         [ +  - ]:       94736 : Version::~Version() {
      69         [ -  + ]:       11842 :   assert(refs_ == 0);
      70                 :             : 
      71                 :             :   // Remove from linked list
      72                 :       11842 :   prev_->next_ = next_;
      73                 :       11842 :   next_->prev_ = prev_;
      74                 :             : 
      75                 :             :   // Drop references to files
      76         [ +  + ]:       94736 :   for (int level = 0; level < config::kNumLevels; level++) {
      77   [ -  +  +  + ]:       89852 :     for (size_t i = 0; i < files_[level].size(); i++) {
      78         [ -  + ]:        6958 :       FileMetaData* f = files_[level][i];
      79         [ -  + ]:        6958 :       assert(f->refs > 0);
      80                 :        6958 :       f->refs--;
      81         [ +  + ]:        6958 :       if (f->refs <= 0) {
      82                 :        8812 :         delete f;
      83                 :             :       }
      84                 :             :     }
      85                 :             :   }
      86         [ +  + ]:       94736 : }
      87                 :             : 
      88                 :     1061121 : int FindFile(const InternalKeyComparator& icmp,
      89                 :             :              const std::vector<FileMetaData*>& files, const Slice& key) {
      90                 :     1061121 :   uint32_t left = 0;
      91         [ -  + ]:     1061121 :   uint32_t right = files.size();
      92         [ +  + ]:     2122469 :   while (left < right) {
      93                 :     1061348 :     uint32_t mid = (left + right) / 2;
      94                 :     1061348 :     const FileMetaData* f = files[mid];
      95         [ +  + ]:     1061348 :     if (icmp.InternalKeyComparator::Compare(f->largest.Encode(), key) < 0) {
      96                 :             :       // Key at "mid.largest" is < "target".  Therefore all
      97                 :             :       // files at or before "mid" are uninteresting.
      98                 :        2394 :       left = mid + 1;
      99                 :             :     } else {
     100                 :             :       // Key at "mid.largest" is >= "target".  Therefore all files
     101                 :             :       // after "mid" are uninteresting.
     102                 :             :       right = mid;
     103                 :             :     }
     104                 :             :   }
     105                 :     1061121 :   return right;
     106                 :             : }
     107                 :             : 
     108                 :           8 : static bool AfterFile(const Comparator* ucmp, const Slice* user_key,
     109                 :             :                       const FileMetaData* f) {
     110                 :             :   // null user_key occurs before all keys and is therefore never after *f
     111   [ +  -  -  + ]:          16 :   return (user_key != nullptr &&
     112         [ -  + ]:          16 :           ucmp->Compare(*user_key, f->largest.user_key()) > 0);
     113                 :             : }
     114                 :             : 
     115                 :           3 : static bool BeforeFile(const Comparator* ucmp, const Slice* user_key,
     116                 :             :                        const FileMetaData* f) {
     117                 :             :   // null user_key occurs after all keys and is therefore never before *f
     118   [ +  -  +  - ]:           6 :   return (user_key != nullptr &&
     119         [ -  + ]:           6 :           ucmp->Compare(*user_key, f->smallest.user_key()) < 0);
     120                 :             : }
     121                 :             : 
     122                 :         143 : bool SomeFileOverlapsRange(const InternalKeyComparator& icmp,
     123                 :             :                            bool disjoint_sorted_files,
     124                 :             :                            const std::vector<FileMetaData*>& files,
     125                 :             :                            const Slice* smallest_user_key,
     126                 :             :                            const Slice* largest_user_key) {
     127         [ +  + ]:         143 :   const Comparator* ucmp = icmp.user_comparator();
     128         [ +  + ]:         143 :   if (!disjoint_sorted_files) {
     129                 :             :     // Need to check against all files
     130   [ -  +  +  + ]:          56 :     for (size_t i = 0; i < files.size(); i++) {
     131                 :           8 :       const FileMetaData* f = files[i];
     132   [ -  +  -  - ]:           8 :       if (AfterFile(ucmp, smallest_user_key, f) ||
     133                 :           0 :           BeforeFile(ucmp, largest_user_key, f)) {
     134                 :             :         // No overlap
     135                 :             :       } else {
     136                 :             :         return true;  // Overlap
     137                 :             :       }
     138                 :             :     }
     139                 :             :     return false;
     140                 :             :   }
     141                 :             : 
     142                 :             :   // Binary search over file list
     143                 :          95 :   uint32_t index = 0;
     144         [ +  - ]:          95 :   if (smallest_user_key != nullptr) {
     145                 :             :     // Find the earliest possible internal key for smallest_user_key
     146                 :          95 :     InternalKey small_key(*smallest_user_key, kMaxSequenceNumber,
     147                 :          95 :                           kValueTypeForSeek);
     148         [ +  - ]:          95 :     index = FindFile(icmp, files, small_key.Encode());
     149                 :          95 :   }
     150                 :             : 
     151   [ -  +  +  + ]:          95 :   if (index >= files.size()) {
     152                 :             :     // beginning of range is after all files, so no overlap.
     153                 :             :     return false;
     154                 :             :   }
     155                 :             : 
     156                 :           3 :   return !BeforeFile(ucmp, largest_user_key, files[index]);
     157                 :             : }
     158                 :             : 
     159                 :             : // An internal iterator.  For a given version/level pair, yields
     160                 :             : // information about the files in the level.  For a given entry, key()
     161                 :             : // is the largest key that occurs in the file, and value() is an
     162                 :             : // 16-byte value containing the file number and file size, both
     163                 :             : // encoded using EncodeFixed64.
     164                 :             : class Version::LevelFileNumIterator : public Iterator {
     165                 :             :  public:
     166                 :        1092 :   LevelFileNumIterator(const InternalKeyComparator& icmp,
     167                 :             :                        const std::vector<FileMetaData*>* flist)
     168         [ -  + ]:        1092 :       : icmp_(icmp), flist_(flist), index_(flist->size()) {  // Marks as invalid
     169                 :        1092 :   }
     170         [ -  + ]:        4054 :   bool Valid() const override { return index_ < flist_->size(); }
     171                 :         999 :   void Seek(const Slice& target) override {
     172                 :         999 :     index_ = FindFile(icmp_, *flist_, target);
     173                 :         999 :   }
     174                 :          93 :   void SeekToFirst() override { index_ = 0; }
     175                 :           0 :   void SeekToLast() override {
     176   [ #  #  #  # ]:           0 :     index_ = flist_->empty() ? 0 : flist_->size() - 1;
     177                 :           0 :   }
     178                 :         299 :   void Next() override {
     179         [ -  + ]:         299 :     assert(Valid());
     180                 :         299 :     index_++;
     181                 :         299 :   }
     182                 :           0 :   void Prev() override {
     183         [ #  # ]:           0 :     assert(Valid());
     184         [ #  # ]:           0 :     if (index_ == 0) {
     185         [ #  # ]:           0 :       index_ = flist_->size();  // Marks as invalid
     186                 :             :     } else {
     187                 :           0 :       index_--;
     188                 :             :     }
     189                 :           0 :   }
     190                 :         636 :   Slice key() const override {
     191         [ -  + ]:         636 :     assert(Valid());
     192                 :         636 :     return (*flist_)[index_]->largest.Encode();
     193                 :             :   }
     194                 :         636 :   Slice value() const override {
     195         [ -  + ]:         636 :     assert(Valid());
     196                 :         636 :     EncodeFixed64(value_buf_, (*flist_)[index_]->number);
     197                 :         636 :     EncodeFixed64(value_buf_ + 8, (*flist_)[index_]->file_size);
     198                 :         636 :     return Slice(value_buf_, sizeof(value_buf_));
     199                 :             :   }
     200                 :         186 :   Status status() const override { return Status::OK(); }
     201                 :             : 
     202                 :             :  private:
     203                 :             :   const InternalKeyComparator icmp_;
     204                 :             :   const std::vector<FileMetaData*>* const flist_;
     205                 :             :   uint32_t index_;
     206                 :             : 
     207                 :             :   // Backing store for value().  Holds the file number and size.
     208                 :             :   mutable char value_buf_[16];
     209                 :             : };
     210                 :             : 
     211                 :         636 : static Iterator* GetFileIterator(void* arg, const ReadOptions& options,
     212                 :             :                                  const Slice& file_value) {
     213                 :         636 :   TableCache* cache = reinterpret_cast<TableCache*>(arg);
     214         [ -  + ]:         636 :   if (file_value.size() != 16) {
     215         [ #  # ]:           0 :     return NewErrorIterator(
     216         [ #  # ]:           0 :         Status::Corruption("FileReader invoked with unexpected value"));
     217                 :             :   } else {
     218                 :         636 :     return cache->NewIterator(options, DecodeFixed64(file_value.data()),
     219                 :         636 :                               DecodeFixed64(file_value.data() + 8));
     220                 :             :   }
     221                 :             : }
     222                 :             : 
     223                 :         999 : Iterator* Version::NewConcatenatingIterator(const ReadOptions& options,
     224                 :             :                                             int level) const {
     225                 :         999 :   return NewTwoLevelIterator(
     226         [ +  - ]:         999 :       new LevelFileNumIterator(vset_->icmp_, &files_[level]), &GetFileIterator,
     227                 :        1998 :       vset_->table_cache_, options);
     228                 :             : }
     229                 :             : 
     230                 :        5087 : void Version::AddIterators(const ReadOptions& options,
     231                 :             :                            std::vector<Iterator*>* iters) {
     232                 :             :   // Merge all level zero files together since they may overlap
     233   [ -  +  +  + ]:        9299 :   for (size_t i = 0; i < files_[0].size(); i++) {
     234                 :        4212 :     iters->push_back(vset_->table_cache_->NewIterator(
     235                 :        4212 :         options, files_[0][i]->number, files_[0][i]->file_size));
     236                 :             :   }
     237                 :             : 
     238                 :             :   // For levels > 0, we can use a concatenating iterator that sequentially
     239                 :             :   // walks through the non-overlapping files in the level, opening them
     240                 :             :   // lazily.
     241         [ +  + ]:       35609 :   for (int level = 1; level < config::kNumLevels; level++) {
     242         [ +  + ]:       30522 :     if (!files_[level].empty()) {
     243                 :         999 :       iters->push_back(NewConcatenatingIterator(options, level));
     244                 :             :     }
     245                 :             :   }
     246                 :        5087 : }
     247                 :             : 
     248                 :             : // Callback from TableCache::Get()
     249                 :             : namespace {
     250                 :             : enum SaverState {
     251                 :             :   kNotFound,
     252                 :             :   kFound,
     253                 :             :   kDeleted,
     254                 :             :   kCorrupt,
     255                 :             : };
     256                 :     5951058 : struct Saver {
     257                 :             :   SaverState state;
     258                 :             :   const Comparator* ucmp;
     259                 :             :   Slice user_key;
     260                 :             :   std::string* value;
     261                 :             : };
     262                 :             : }  // namespace
     263                 :       61993 : static void SaveValue(void* arg, const Slice& ikey, const Slice& v) {
     264                 :       61993 :   Saver* s = reinterpret_cast<Saver*>(arg);
     265                 :       61993 :   ParsedInternalKey parsed_key;
     266         [ -  + ]:       61993 :   if (!ParseInternalKey(ikey, &parsed_key)) {
     267                 :           0 :     s->state = kCorrupt;
     268                 :             :   } else {
     269         [ +  + ]:       61993 :     if (s->ucmp->Compare(parsed_key.user_key, s->user_key) == 0) {
     270         [ +  + ]:       54329 :       s->state = (parsed_key.type == kTypeValue) ? kFound : kDeleted;
     271         [ +  + ]:       54329 :       if (s->state == kFound) {
     272                 :       31363 :         s->value->assign(v.data(), v.size());
     273                 :             :       }
     274                 :             :     }
     275                 :             :   }
     276                 :       61993 : }
     277                 :             : 
     278                 :      119800 : static bool NewestFirst(FileMetaData* a, FileMetaData* b) {
     279                 :      119800 :   return a->number > b->number;
     280                 :             : }
     281                 :             : 
     282                 :     5951712 : void Version::ForEachOverlapping(Slice user_key, Slice internal_key, void* arg,
     283                 :             :                                  bool (*func)(void*, int, FileMetaData*)) {
     284         [ -  + ]:     5951712 :   const Comparator* ucmp = vset_->icmp_.user_comparator();
     285                 :             : 
     286                 :             :   // Search level-0 in order from newest to oldest.
     287                 :     5951712 :   std::vector<FileMetaData*> tmp;
     288   [ -  +  +  - ]:     5951712 :   tmp.reserve(files_[0].size());
     289   [ -  +  +  + ]:     6923088 :   for (uint32_t i = 0; i < files_[0].size(); i++) {
     290         [ -  + ]:      971376 :     FileMetaData* f = files_[0][i];
     291   [ -  +  +  -  :     2907882 :     if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 &&
             +  +  +  + ]
     292   [ -  +  +  - ]:     1930260 :         ucmp->Compare(user_key, f->largest.user_key()) <= 0) {
     293         [ +  - ]:      964111 :       tmp.push_back(f);
     294                 :             :     }
     295                 :             :   }
     296         [ +  + ]:     5951712 :   if (!tmp.empty()) {
     297         [ +  - ]:      891826 :     std::sort(tmp.begin(), tmp.end(), NewestFirst);
     298   [ -  +  +  + ]:     1822598 :     for (uint32_t i = 0; i < tmp.size(); i++) {
     299   [ +  -  +  + ]:      950913 :       if (!(*func)(arg, 0, tmp[i])) {
     300                 :             :         return;
     301                 :             :       }
     302                 :             :     }
     303                 :             :   }
     304                 :             : 
     305                 :             :   // Search other levels.
     306         [ +  + ]:    41342487 :   for (int level = 1; level < config::kNumLevels; level++) {
     307         [ -  + ]:    35445282 :     size_t num_files = files_[level].size();
     308         [ +  + ]:    35445282 :     if (num_files == 0) continue;
     309                 :             : 
     310                 :             :     // Binary search to find earliest index whose largest key >= internal_key.
     311         [ +  - ]:     1060027 :     uint32_t index = FindFile(vset_->icmp_, files_[level], internal_key);
     312         [ +  + ]:     1060027 :     if (index < num_files) {
     313         [ -  + ]:     1058384 :       FileMetaData* f = files_[level][index];
     314   [ -  +  +  -  :     2116768 :       if (ucmp->Compare(user_key, f->smallest.user_key()) < 0) {
                   +  + ]
     315                 :             :         // All of "f" is past any data for user_key
     316                 :             :       } else {
     317   [ +  -  +  + ]:     1057503 :         if (!(*func)(arg, level, f)) {
     318                 :             :           return;
     319                 :             :         }
     320                 :             :       }
     321                 :             :     }
     322                 :             :   }
     323                 :     5951712 : }
     324                 :             : 
     325                 :     5951058 : Status Version::Get(const ReadOptions& options, const LookupKey& k,
     326                 :             :                     std::string* value, GetStats* stats) {
     327                 :     5951058 :   stats->seek_file = nullptr;
     328                 :     5951058 :   stats->seek_file_level = -1;
     329                 :             : 
     330         [ -  - ]:           0 :   struct State {
     331                 :             :     Saver saver;
     332                 :             :     GetStats* stats;
     333                 :             :     const ReadOptions* options;
     334                 :             :     Slice ikey;
     335                 :             :     FileMetaData* last_file_read;
     336                 :             :     int last_file_read_level;
     337                 :             : 
     338                 :             :     VersionSet* vset;
     339                 :             :     Status s;
     340                 :             :     bool found;
     341                 :             : 
     342                 :     2007594 :     static bool Match(void* arg, int level, FileMetaData* f) {
     343                 :     2007594 :       State* state = reinterpret_cast<State*>(arg);
     344                 :             : 
     345         [ +  + ]:     2007594 :       if (state->stats->seek_file == nullptr &&
     346         [ +  + ]:     1982786 :           state->last_file_read != nullptr) {
     347                 :             :         // We have had more than one seek for this read.  Charge the 1st file.
     348                 :       52370 :         state->stats->seek_file = state->last_file_read;
     349                 :       52370 :         state->stats->seek_file_level = state->last_file_read_level;
     350                 :             :       }
     351                 :             : 
     352                 :     2007594 :       state->last_file_read = f;
     353                 :     2007594 :       state->last_file_read_level = level;
     354                 :             : 
     355                 :     4015188 :       state->s = state->vset->table_cache_->Get(*state->options, f->number,
     356                 :     2007594 :                                                 f->file_size, state->ikey,
     357         [ -  + ]:     2007594 :                                                 &state->saver, SaveValue);
     358         [ +  + ]:     2007594 :       if (!state->s.ok()) {
     359                 :           1 :         state->found = true;
     360                 :           1 :         return false;
     361                 :             :       }
     362   [ +  +  -  -  :     2007593 :       switch (state->saver.state) {
                      + ]
     363                 :             :         case kNotFound:
     364                 :             :           return true;  // Keep searching in other files
     365                 :       31363 :         case kFound:
     366                 :       31363 :           state->found = true;
     367                 :       31363 :           return false;
     368                 :       22966 :         case kDeleted:
     369                 :       22966 :           return false;
     370                 :           0 :         case kCorrupt:
     371                 :           0 :           state->s =
     372         [ #  # ]:           0 :               Status::Corruption("corrupted key for ", state->saver.user_key);
     373                 :           0 :           state->found = true;
     374                 :           0 :           return false;
     375                 :             :       }
     376                 :             : 
     377                 :             :       // Not reached. Added to avoid false compilation warnings of
     378                 :             :       // "control reaches end of non-void function".
     379                 :           0 :       return false;
     380                 :             :     }
     381                 :             :   };
     382                 :             : 
     383         [ +  - ]:     5951058 :   State state;
     384                 :     5951058 :   state.found = false;
     385                 :     5951058 :   state.stats = stats;
     386                 :     5951058 :   state.last_file_read = nullptr;
     387                 :     5951058 :   state.last_file_read_level = -1;
     388                 :             : 
     389                 :     5951058 :   state.options = &options;
     390         [ +  - ]:     5951058 :   state.ikey = k.internal_key();
     391                 :     5951058 :   state.vset = vset_;
     392                 :             : 
     393                 :     5951058 :   state.saver.state = kNotFound;
     394         [ +  - ]:     5951058 :   state.saver.ucmp = vset_->icmp_.user_comparator();
     395         [ +  - ]:     5951058 :   state.saver.user_key = k.user_key();
     396                 :     5951058 :   state.saver.value = value;
     397                 :             : 
     398         [ +  - ]:     5951058 :   ForEachOverlapping(state.saver.user_key, state.ikey, &state, &State::Match);
     399                 :             : 
     400   [ +  +  +  -  :     5982422 :   return state.found ? state.s : Status::NotFound(Slice());
                   +  + ]
     401                 :     5951058 : }
     402                 :             : 
     403                 :     5951235 : bool Version::UpdateStats(const GetStats& /*stats*/) {
     404                 :             :   // Disable automatic compactions triggered by read seek counters.
     405                 :             :   // The heuristic was tuned for expensive random seeks and can create
     406                 :             :   // severe write amplification on large random-key databases.
     407                 :             :   // Size and manual compactions still run.
     408                 :     5951235 :   return false;
     409                 :             : }
     410                 :             : 
     411                 :         654 : bool Version::RecordReadSample(Slice internal_key) {
     412                 :         654 :   ParsedInternalKey ikey;
     413         [ +  - ]:         654 :   if (!ParseInternalKey(internal_key, &ikey)) {
     414                 :             :     return false;
     415                 :             :   }
     416                 :             : 
     417                 :         654 :   struct State {
     418                 :             :     GetStats stats;  // Holds first matching file
     419                 :             :     int matches;
     420                 :             : 
     421                 :         822 :     static bool Match(void* arg, int level, FileMetaData* f) {
     422                 :         822 :       State* state = reinterpret_cast<State*>(arg);
     423                 :         822 :       state->matches++;
     424         [ +  + ]:         822 :       if (state->matches == 1) {
     425                 :             :         // Remember first match.
     426                 :         645 :         state->stats.seek_file = f;
     427                 :         645 :         state->stats.seek_file_level = level;
     428                 :             :       }
     429                 :             :       // We can stop iterating once we have a second match.
     430                 :         822 :       return state->matches < 2;
     431                 :             :     }
     432                 :             :   };
     433                 :             : 
     434                 :         654 :   State state;
     435                 :         654 :   state.matches = 0;
     436                 :         654 :   ForEachOverlapping(ikey.user_key, internal_key, &state, &State::Match);
     437                 :             : 
     438                 :             :   // Must have at least two matches since we want to merge across
     439                 :             :   // files. But what if we have a single file that contains many
     440                 :             :   // overwrites and deletions?  Should we have another mechanism for
     441                 :             :   // finding such files?
     442         [ +  + ]:         654 :   if (state.matches >= 2) {
     443                 :             :     // 1MB cost is about 1 seek (see comment in Builder::Apply).
     444                 :         177 :     return UpdateStats(state.stats);
     445                 :             :   }
     446                 :             :   return false;
     447                 :             : }
     448                 :             : 
     449                 :     6180174 : void Version::Ref() { ++refs_; }
     450                 :             : 
     451                 :     6180173 : void Version::Unref() {
     452         [ -  + ]:     6180173 :   assert(this != &vset_->dummy_versions_);
     453         [ -  + ]:     6180173 :   assert(refs_ >= 1);
     454                 :     6180173 :   --refs_;
     455         [ +  + ]:     6180173 :   if (refs_ == 0) {
     456                 :        8946 :     delete this;
     457                 :             :   }
     458                 :     6180173 : }
     459                 :             : 
     460                 :         143 : bool Version::OverlapInLevel(int level, const Slice* smallest_user_key,
     461                 :             :                              const Slice* largest_user_key) {
     462                 :         143 :   return SomeFileOverlapsRange(vset_->icmp_, (level > 0), files_[level],
     463                 :         143 :                                smallest_user_key, largest_user_key);
     464                 :             : }
     465                 :             : 
     466                 :          48 : int Version::PickLevelForMemTableOutput(const Slice& smallest_user_key,
     467                 :             :                                         const Slice& largest_user_key) {
     468                 :          48 :   int level = 0;
     469         [ +  - ]:          48 :   if (!OverlapInLevel(0, &smallest_user_key, &largest_user_key)) {
     470                 :             :     // Push to next level if there is no overlap in next level,
     471                 :             :     // and the #bytes overlapping in the level after that are limited.
     472                 :          48 :     InternalKey start(smallest_user_key, kMaxSequenceNumber, kValueTypeForSeek);
     473         [ +  - ]:          48 :     InternalKey limit(largest_user_key, 0, static_cast<ValueType>(0));
     474                 :          48 :     std::vector<FileMetaData*> overlaps;
     475         [ +  + ]:         140 :     while (level < config::kMaxMemCompactLevel) {
     476   [ +  -  +  + ]:          95 :       if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) {
     477                 :             :         break;
     478                 :             :       }
     479         [ +  - ]:          92 :       if (level + 2 < config::kNumLevels) {
     480                 :             :         // Check that file does not overlap too many grandparent bytes.
     481         [ +  - ]:          92 :         GetOverlappingInputs(level + 2, &start, &limit, &overlaps);
     482                 :          92 :         const int64_t sum = TotalFileSize(overlaps);
     483         [ +  - ]:          92 :         if (sum > MaxGrandParentOverlapBytes(vset_->options_)) {
     484                 :             :           break;
     485                 :             :         }
     486                 :             :       }
     487                 :             :       level++;
     488                 :             :     }
     489                 :          48 :   }
     490                 :          48 :   return level;
     491                 :             : }
     492                 :             : 
     493                 :             : // Store in "*inputs" all files in "level" that overlap [begin,end]
     494                 :         860 : void Version::GetOverlappingInputs(int level, const InternalKey* begin,
     495                 :             :                                    const InternalKey* end,
     496                 :             :                                    std::vector<FileMetaData*>* inputs) {
     497         [ -  + ]:         860 :   assert(level >= 0);
     498         [ -  + ]:         860 :   assert(level < config::kNumLevels);
     499         [ +  + ]:         860 :   inputs->clear();
     500         [ +  - ]:         860 :   Slice user_begin, user_end;
     501         [ +  - ]:         860 :   if (begin != nullptr) {
     502         [ -  + ]:        1720 :     user_begin = begin->user_key();
     503                 :             :   }
     504         [ +  - ]:         860 :   if (end != nullptr) {
     505         [ -  + ]:        1720 :     user_end = end->user_key();
     506                 :             :   }
     507                 :         860 :   const Comparator* user_cmp = vset_->icmp_.user_comparator();
     508         [ +  + ]:        3249 :   for (size_t i = 0; i < files_[level].size();) {
     509         [ -  + ]:        1529 :     FileMetaData* f = files_[level][i++];
     510         [ -  + ]:        1529 :     const Slice file_start = f->smallest.user_key();
     511         [ -  + ]:        1529 :     const Slice file_limit = f->largest.user_key();
     512   [ +  -  +  + ]:        1529 :     if (begin != nullptr && user_cmp->Compare(file_limit, user_begin) < 0) {
     513                 :             :       // "f" is completely before specified range; skip it
     514   [ +  -  +  + ]:        1385 :     } else if (end != nullptr && user_cmp->Compare(file_start, user_end) > 0) {
     515                 :             :       // "f" is completely after specified range; skip it
     516                 :             :     } else {
     517                 :        1378 :       inputs->push_back(f);
     518         [ +  + ]:        1378 :       if (level == 0) {
     519                 :             :         // Level-0 files may overlap each other.  So check if the newly
     520                 :             :         // added file has expanded the range.  If so, restart search.
     521   [ +  -  +  - ]:        1282 :         if (begin != nullptr && user_cmp->Compare(file_start, user_begin) < 0) {
     522                 :           0 :           user_begin = file_start;
     523         [ #  # ]:           0 :           inputs->clear();
     524                 :             :           i = 0;
     525   [ +  -  +  + ]:        2564 :         } else if (end != nullptr &&
     526                 :        1282 :                    user_cmp->Compare(file_limit, user_end) > 0) {
     527                 :           6 :           user_end = file_limit;
     528   [ +  -  -  + ]:        2395 :           inputs->clear();
     529                 :             :           i = 0;
     530                 :             :         }
     531                 :             :       }
     532                 :             :     }
     533                 :             :   }
     534                 :         860 : }
     535                 :             : 
     536                 :           0 : std::string Version::DebugString() const {
     537                 :           0 :   std::string r;
     538         [ #  # ]:           0 :   for (int level = 0; level < config::kNumLevels; level++) {
     539                 :             :     // E.g.,
     540                 :             :     //   --- level 1 ---
     541                 :             :     //   17:123['a' .. 'd']
     542                 :             :     //   20:43['e' .. 'g']
     543         [ #  # ]:           0 :     r.append("--- level ");
     544         [ #  # ]:           0 :     AppendNumberTo(&r, level);
     545         [ #  # ]:           0 :     r.append(" ---\n");
     546                 :             :     const std::vector<FileMetaData*>& files = files_[level];
     547   [ #  #  #  # ]:           0 :     for (size_t i = 0; i < files.size(); i++) {
     548         [ #  # ]:           0 :       r.push_back(' ');
     549         [ #  # ]:           0 :       AppendNumberTo(&r, files[i]->number);
     550         [ #  # ]:           0 :       r.push_back(':');
     551         [ #  # ]:           0 :       AppendNumberTo(&r, files[i]->file_size);
     552         [ #  # ]:           0 :       r.append("[");
     553         [ #  # ]:           0 :       r.append(files[i]->smallest.DebugString());
     554         [ #  # ]:           0 :       r.append(" .. ");
     555         [ #  # ]:           0 :       r.append(files[i]->largest.DebugString());
     556         [ #  # ]:           0 :       r.append("]\n");
     557                 :             :     }
     558                 :             :   }
     559                 :           0 :   return r;
     560                 :           0 : }
     561                 :             : 
     562                 :             : // A helper class so we can efficiently apply a whole sequence
     563                 :             : // of edits to a particular state without creating intermediate
     564                 :             : // Versions that contain full copies of the intermediate state.
     565                 :             : class VersionSet::Builder {
     566                 :             :  private:
     567                 :             :   // Helper to sort by v->files_[file_number].smallest
     568                 :             :   struct BySmallestKey {
     569                 :             :     const InternalKeyComparator* internal_comparator;
     570                 :             : 
     571                 :        6239 :     bool operator()(FileMetaData* f1, FileMetaData* f2) const {
     572                 :        6239 :       int r = internal_comparator->Compare(f1->smallest, f2->smallest);
     573         [ +  + ]:        6239 :       if (r != 0) {
     574                 :        5922 :         return (r < 0);
     575                 :             :       } else {
     576                 :             :         // Break ties by file number
     577                 :         317 :         return (f1->number < f2->number);
     578                 :             :       }
     579                 :             :     }
     580                 :             :   };
     581                 :             : 
     582                 :             :   typedef std::set<FileMetaData*, BySmallestKey> FileSet;
     583                 :       42350 :   struct LevelState {
     584                 :             :     std::set<uint64_t> deleted_files;
     585                 :             :     FileSet* added_files;
     586                 :             :   };
     587                 :             : 
     588                 :             :   VersionSet* vset_;
     589                 :             :   Version* base_;
     590                 :             :   LevelState levels_[config::kNumLevels];
     591                 :             : 
     592                 :             :  public:
     593                 :             :   // Initialize a builder with the files from *base and other info from *vset
     594   [ +  +  -  - ]:       48400 :   Builder(VersionSet* vset, Version* base) : vset_(vset), base_(base) {
     595         [ +  - ]:        6050 :     base_->Ref();
     596                 :        6050 :     BySmallestKey cmp;
     597                 :        6050 :     cmp.internal_comparator = &vset_->icmp_;
     598         [ +  + ]:       48400 :     for (int level = 0; level < config::kNumLevels; level++) {
     599         [ +  - ]:       42350 :       levels_[level].added_files = new FileSet(cmp);
     600                 :             :     }
     601         [ -  - ]:        6050 :   }
     602                 :             : 
     603         [ +  - ]:       48400 :   ~Builder() {
     604         [ +  + ]:       48400 :     for (int level = 0; level < config::kNumLevels; level++) {
     605                 :       42350 :       const FileSet* added = levels_[level].added_files;
     606                 :       42350 :       std::vector<FileMetaData*> to_unref;
     607                 :       42350 :       to_unref.reserve(added->size());
     608         [ +  + ]:       47600 :       for (FileSet::const_iterator it = added->begin(); it != added->end();
     609                 :        5250 :            ++it) {
     610                 :        5250 :         to_unref.push_back(*it);
     611                 :             :       }
     612         [ +  - ]:       84700 :       delete added;
     613   [ -  +  +  + ]:       47600 :       for (uint32_t i = 0; i < to_unref.size(); i++) {
     614         [ +  + ]:        5250 :         FileMetaData* f = to_unref[i];
     615                 :        5250 :         f->refs--;
     616         [ +  + ]:        5250 :         if (f->refs <= 0) {
     617                 :        1680 :           delete f;
     618                 :             :         }
     619                 :             :       }
     620                 :       42350 :     }
     621                 :        6050 :     base_->Unref();
     622         [ +  + ]:       48400 :   }
     623                 :             : 
     624                 :             :   // Apply all of the edits in *edit to the current state.
     625                 :        8054 :   void Apply(VersionEdit* edit) {
     626                 :             :     // Update compaction pointers
     627   [ -  +  +  + ]:        8960 :     for (size_t i = 0; i < edit->compact_pointers_.size(); i++) {
     628                 :         906 :       const int level = edit->compact_pointers_[i].first;
     629                 :        1812 :       vset_->compact_pointer_[level] =
     630                 :         906 :           edit->compact_pointers_[i].second.Encode().ToString();
     631                 :             :     }
     632                 :             : 
     633                 :             :     // Delete files
     634         [ +  + ]:        9880 :     for (const auto& deleted_file_set_kvp : edit->deleted_files_) {
     635                 :        1826 :       const int level = deleted_file_set_kvp.first;
     636                 :        1826 :       const uint64_t number = deleted_file_set_kvp.second;
     637                 :        1826 :       levels_[level].deleted_files.insert(number);
     638                 :             :     }
     639                 :             : 
     640                 :             :     // Add new files
     641   [ -  +  +  + ]:       13304 :     for (size_t i = 0; i < edit->new_files_.size(); i++) {
     642                 :        5250 :       const int level = edit->new_files_[i].first;
     643         [ +  - ]:        5250 :       FileMetaData* f = new FileMetaData(edit->new_files_[i].second);
     644                 :        5250 :       f->refs = 1;
     645                 :             : 
     646                 :             :       // We arrange to automatically compact this file after
     647                 :             :       // a certain number of seeks.  Let's assume:
     648                 :             :       //   (1) One seek costs 10ms
     649                 :             :       //   (2) Writing or reading 1MB costs 10ms (100MB/s)
     650                 :             :       //   (3) A compaction of 1MB does 25MB of IO:
     651                 :             :       //         1MB read from this level
     652                 :             :       //         10-12MB read from next level (boundaries may be misaligned)
     653                 :             :       //         10-12MB written to next level
     654                 :             :       // This implies that 25 seeks cost the same as the compaction
     655                 :             :       // of 1MB of data.  I.e., one seek costs approximately the
     656                 :             :       // same as the compaction of 40KB of data.  We are a little
     657                 :             :       // conservative and allow approximately one seek for every 16KB
     658                 :             :       // of data before triggering a compaction.
     659                 :             :       //
     660                 :             :       // Note: seek compactions are disabled. See Version::UpdateStats.
     661                 :        5250 :       f->allowed_seeks = static_cast<int>((f->file_size / 16384U));
     662         [ +  - ]:        5250 :       if (f->allowed_seeks < 100) f->allowed_seeks = 100;
     663                 :             : 
     664                 :        5250 :       levels_[level].deleted_files.erase(f->number);
     665                 :        5250 :       levels_[level].added_files->insert(f);
     666                 :             :     }
     667                 :        8054 :   }
     668                 :             : 
     669                 :             :   // Save the current state in *v.
     670                 :        6050 :   void SaveTo(Version* v) {
     671                 :        6050 :     BySmallestKey cmp;
     672                 :        6050 :     cmp.internal_comparator = &vset_->icmp_;
     673         [ +  + ]:       48400 :     for (int level = 0; level < config::kNumLevels; level++) {
     674                 :             :       // Merge the set of added files with the set of pre-existing files.
     675                 :             :       // Drop any deleted files.  Store the result in *v.
     676                 :       42350 :       const std::vector<FileMetaData*>& base_files = base_->files_[level];
     677         [ -  + ]:       42350 :       std::vector<FileMetaData*>::const_iterator base_iter = base_files.begin();
     678         [ -  + ]:       42350 :       std::vector<FileMetaData*>::const_iterator base_end = base_files.end();
     679                 :       42350 :       const FileSet* added_files = levels_[level].added_files;
     680         [ -  + ]:       42350 :       v->files_[level].reserve(base_files.size() + added_files->size());
     681         [ +  + ]:       47600 :       for (const auto& added_file : *added_files) {
     682                 :             :         // Add all smaller files listed in base_
     683                 :        6130 :         for (std::vector<FileMetaData*>::const_iterator bpos =
     684                 :        5250 :                  std::upper_bound(base_iter, base_end, added_file, cmp);
     685         [ +  + ]:        6130 :              base_iter != bpos; ++base_iter) {
     686                 :         880 :           MaybeAddFile(v, level, *base_iter);
     687                 :             :         }
     688                 :             : 
     689                 :        5250 :         MaybeAddFile(v, level, added_file);
     690                 :             :       }
     691                 :             : 
     692                 :             :       // Add remaining base files
     693         [ +  + ]:       45008 :       for (; base_iter != base_end; ++base_iter) {
     694                 :        2658 :         MaybeAddFile(v, level, *base_iter);
     695                 :             :       }
     696                 :             : 
     697                 :             : #ifndef NDEBUG
     698                 :             :       // Make sure there is no overlap in levels > 0
     699         [ +  + ]:       42350 :       if (level > 0) {
     700   [ -  +  +  + ]:       36500 :         for (uint32_t i = 1; i < v->files_[level].size(); i++) {
     701                 :         200 :           const InternalKey& prev_end = v->files_[level][i - 1]->largest;
     702                 :         200 :           const InternalKey& this_begin = v->files_[level][i]->smallest;
     703         [ -  + ]:         200 :           if (vset_->icmp_.Compare(prev_end, this_begin) >= 0) {
     704         [ #  # ]:           0 :             fprintf(stderr, "overlapping ranges in same level %s vs. %s\n",
     705         [ #  # ]:           0 :                     prev_end.DebugString().c_str(),
     706         [ #  # ]:           0 :                     this_begin.DebugString().c_str());
     707                 :           0 :             abort();
     708                 :             :           }
     709                 :             :         }
     710                 :             :       }
     711                 :             : #endif
     712                 :             :     }
     713                 :        6050 :   }
     714                 :             : 
     715                 :        8788 :   void MaybeAddFile(Version* v, int level, FileMetaData* f) {
     716         [ +  + ]:        8788 :     if (levels_[level].deleted_files.count(f->number) > 0) {
     717                 :             :       // File is deleted: do nothing
     718                 :             :     } else {
     719                 :        6962 :       std::vector<FileMetaData*>* files = &v->files_[level];
     720   [ +  +  +  + ]:        6962 :       if (level > 0 && !files->empty()) {
     721                 :             :         // Must not overlap
     722   [ -  +  -  + ]:         200 :         assert(vset_->icmp_.Compare((*files)[files->size() - 1]->largest,
     723                 :             :                                     f->smallest) < 0);
     724                 :             :       }
     725                 :        6962 :       f->refs++;
     726                 :        6962 :       files->push_back(f);
     727                 :             :     }
     728                 :        8788 :   }
     729                 :             : };
     730                 :             : 
     731                 :        2897 : VersionSet::VersionSet(const std::string& dbname, const Options* options,
     732                 :             :                        TableCache* table_cache,
     733                 :        2897 :                        const InternalKeyComparator* cmp)
     734                 :        2897 :     : env_(options->env),
     735         [ -  + ]:        2897 :       dbname_(dbname),
     736                 :        2897 :       options_(options),
     737                 :        2897 :       table_cache_(table_cache),
     738                 :        2897 :       icmp_(*cmp),
     739                 :        2897 :       next_file_number_(2),
     740                 :        2897 :       manifest_file_number_(0),  // Filled by Recover()
     741                 :        2897 :       last_sequence_(0),
     742                 :        2897 :       log_number_(0),
     743                 :        2897 :       prev_log_number_(0),
     744                 :        2897 :       descriptor_file_(nullptr),
     745                 :        2897 :       descriptor_log_(nullptr),
     746                 :        2897 :       dummy_versions_(this),
     747         [ +  + ]:       23176 :       current_(nullptr) {
     748   [ +  -  +  - ]:        2897 :   AppendVersion(new Version(this));
     749         [ -  - ]:        2897 : }
     750                 :             : 
     751                 :       28960 : VersionSet::~VersionSet() {
     752                 :        2896 :   current_->Unref();
     753         [ -  + ]:        2896 :   assert(dummy_versions_.next_ == &dummy_versions_);  // List must be empty
     754         [ +  + ]:        2896 :   delete descriptor_log_;
     755         [ +  + ]:        2896 :   delete descriptor_file_;
     756         [ +  + ]:       28960 : }
     757                 :             : 
     758                 :        8947 : void VersionSet::AppendVersion(Version* v) {
     759                 :             :   // Make "v" current
     760         [ -  + ]:        8947 :   assert(v->refs_ == 0);
     761         [ -  + ]:        8947 :   assert(v != current_);
     762         [ +  + ]:        8947 :   if (current_ != nullptr) {
     763                 :        6050 :     current_->Unref();
     764                 :             :   }
     765                 :        8947 :   current_ = v;
     766                 :        8947 :   v->Ref();
     767                 :             : 
     768                 :             :   // Append to linked list
     769                 :        8947 :   v->prev_ = dummy_versions_.prev_;
     770                 :        8947 :   v->next_ = &dummy_versions_;
     771                 :        8947 :   v->prev_->next_ = v;
     772                 :        8947 :   v->next_->prev_ = v;
     773                 :        8947 : }
     774                 :             : 
     775                 :        3157 : Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) {
     776         [ +  + ]:        3157 :   if (edit->has_log_number_) {
     777         [ -  + ]:        2932 :     assert(edit->log_number_ >= log_number_);
     778         [ -  + ]:        2932 :     assert(edit->log_number_ < next_file_number_);
     779                 :             :   } else {
     780                 :         225 :     edit->SetLogNumber(log_number_);
     781                 :             :   }
     782                 :             : 
     783         [ +  + ]:        3157 :   if (!edit->has_prev_log_number_) {
     784                 :         225 :     edit->SetPrevLogNumber(prev_log_number_);
     785                 :             :   }
     786                 :             : 
     787                 :        3157 :   edit->SetNextFile(next_file_number_);
     788                 :        3157 :   edit->SetLastSequence(last_sequence_);
     789                 :             : 
     790                 :        3157 :   Version* v = new Version(this);
     791                 :        3157 :   {
     792                 :        3157 :     Builder builder(this, current_);
     793         [ +  - ]:        3157 :     builder.Apply(edit);
     794         [ +  - ]:        3157 :     builder.SaveTo(v);
     795                 :        3157 :   }
     796                 :        3157 :   Finalize(v);
     797                 :             : 
     798                 :             :   // Initialize new descriptor log file if necessary by creating
     799                 :             :   // a temporary file that contains a snapshot of the current version.
     800         [ +  + ]:        3157 :   std::string new_manifest_file;
     801         [ +  + ]:        3157 :   Status s;
     802         [ +  + ]:        3157 :   if (descriptor_log_ == nullptr) {
     803                 :             :     // No reason to unlock *mu here since we only hit this path in the
     804                 :             :     // first call to LogAndApply (when opening the database).
     805         [ -  + ]:        2888 :     assert(descriptor_file_ == nullptr);
     806         [ +  - ]:        2888 :     new_manifest_file = DescriptorFileName(dbname_, manifest_file_number_);
     807         [ +  - ]:        2888 :     edit->SetNextFile(next_file_number_);
     808   [ +  -  -  + ]:        2888 :     s = env_->NewWritableFile(new_manifest_file, &descriptor_file_);
     809         [ +  - ]:        2888 :     if (s.ok()) {
     810   [ +  -  +  - ]:        2888 :       descriptor_log_ = new log::Writer(descriptor_file_);
     811   [ +  -  -  + ]:        2888 :       s = WriteSnapshot(descriptor_log_);
     812                 :             :     }
     813                 :             :   }
     814                 :             : 
     815                 :             :   // Unlock during expensive MANIFEST log write
     816                 :        3157 :   {
     817                 :        3157 :     mu->Unlock();
     818                 :             : 
     819                 :             :     // Write new record to MANIFEST log
     820         [ +  - ]:        3157 :     if (s.ok()) {
     821         [ +  - ]:        3157 :       std::string record;
     822         [ +  - ]:        3157 :       edit->EncodeTo(&record);
     823   [ -  +  +  -  :        3157 :       s = descriptor_log_->AddRecord(record);
                   -  + ]
     824         [ +  - ]:        3157 :       if (s.ok()) {
     825   [ +  -  -  + ]:        3157 :         s = descriptor_file_->Sync();
     826                 :             :       }
     827         [ -  + ]:        3157 :       if (!s.ok()) {
     828   [ #  #  #  # ]:           0 :         Log(options_->info_log, "MANIFEST write: %s\n", s.ToString().c_str());
     829                 :             :       }
     830                 :        3157 :     }
     831                 :             : 
     832                 :             :     // If we just created a new descriptor file, install it by writing a
     833                 :             :     // new CURRENT file that points to it.
     834   [ +  -  +  + ]:        3157 :     if (s.ok() && !new_manifest_file.empty()) {
     835   [ +  -  -  + ]:        2888 :       s = SetCurrentFile(env_, dbname_, manifest_file_number_);
     836                 :             :     }
     837                 :             : 
     838         [ +  - ]:        3157 :     mu->Lock();
     839                 :             :   }
     840                 :             : 
     841                 :             :   // Install the new version
     842         [ +  - ]:        3157 :   if (s.ok()) {
     843         [ +  - ]:        3157 :     AppendVersion(v);
     844                 :        3157 :     log_number_ = edit->log_number_;
     845                 :        3157 :     prev_log_number_ = edit->prev_log_number_;
     846                 :             :   } else {
     847         [ #  # ]:           0 :     delete v;
     848         [ #  # ]:           0 :     if (!new_manifest_file.empty()) {
     849         [ #  # ]:           0 :       delete descriptor_log_;
     850         [ #  # ]:           0 :       delete descriptor_file_;
     851                 :           0 :       descriptor_log_ = nullptr;
     852                 :           0 :       descriptor_file_ = nullptr;
     853         [ #  # ]:           0 :       env_->DeleteFile(new_manifest_file);
     854                 :             :     }
     855                 :             :   }
     856                 :             : 
     857                 :        3157 :   return s;
     858                 :        3157 : }
     859                 :             : 
     860                 :        2897 : Status VersionSet::Recover(bool* save_manifest) {
     861                 :           0 :   struct LogReporter : public log::Reader::Reporter {
     862                 :             :     Status* status;
     863                 :           0 :     void Corruption(size_t bytes, const Status& s) override {
     864         [ #  # ]:           0 :       if (this->status->ok()) *this->status = s;
     865                 :           0 :     }
     866                 :             :   };
     867                 :             : 
     868                 :             :   // Read "CURRENT" file, which contains a pointer to the current manifest file
     869         [ +  - ]:        2897 :   std::string current;
     870   [ +  -  +  - ]:        2897 :   Status s = ReadFileToString(env_, CurrentFileName(dbname_), &current);
     871         [ -  + ]:        2897 :   if (!s.ok()) {
     872                 :           0 :     return s;
     873                 :             :   }
     874   [ +  -  +  + ]:        5794 :   if (current.empty() || current[current.size() - 1] != '\n') {
     875   [ +  -  +  + ]:        2897 :     return Status::Corruption("CURRENT file does not end with newline");
     876                 :             :   }
     877         [ +  - ]:        2895 :   current.resize(current.size() - 1);
     878                 :             : 
     879   [ +  -  +  - ]:        2895 :   std::string dscname = dbname_ + "/" + current;
     880                 :        2895 :   SequentialFile* file;
     881   [ +  -  -  + ]:        2895 :   s = env_->NewSequentialFile(dscname, &file);
     882         [ +  + ]:        2895 :   if (!s.ok()) {
     883         [ +  - ]:           2 :     if (s.IsNotFound()) {
     884         [ +  - ]:           2 :       return Status::Corruption("CURRENT points to a non-existent file",
     885   [ +  -  +  - ]:           4 :                                 s.ToString());
     886                 :             :     }
     887                 :           0 :     return s;
     888                 :             :   }
     889                 :             : 
     890                 :        2893 :   bool have_log_number = false;
     891                 :        2893 :   bool have_prev_log_number = false;
     892                 :        2893 :   bool have_next_file = false;
     893                 :        2893 :   bool have_last_sequence = false;
     894                 :        2893 :   uint64_t next_file = 0;
     895                 :        2893 :   uint64_t last_sequence = 0;
     896                 :        2893 :   uint64_t log_number = 0;
     897                 :        2893 :   uint64_t prev_log_number = 0;
     898         [ +  - ]:        2893 :   Builder builder(this, current_);
     899                 :             : 
     900                 :        2893 :   {
     901         [ +  - ]:        2893 :     LogReporter reporter;
     902                 :        2893 :     reporter.status = &s;
     903                 :        2893 :     log::Reader reader(file, &reporter, true /*checksum*/,
     904         [ +  - ]:        2893 :                        0 /*initial_offset*/);
     905                 :        2893 :     Slice record;
     906                 :        2893 :     std::string scratch;
     907   [ +  -  +  +  :        7790 :     while (reader.ReadRecord(&record, &scratch) && s.ok()) {
                   -  + ]
     908         [ +  - ]:        4897 :       VersionEdit edit;
     909   [ +  -  -  + ]:        4897 :       s = edit.DecodeFrom(record);
     910         [ +  - ]:        4897 :       if (s.ok()) {
     911         [ +  + ]:        4897 :         if (edit.has_comparator_ &&
     912   [ +  -  -  + ]:        2893 :             edit.comparator_ != icmp_.user_comparator()->Name()) {
     913         [ #  # ]:           0 :           s = Status::InvalidArgument(
     914   [ #  #  #  # ]:           0 :               edit.comparator_ + " does not match existing comparator ",
     915   [ #  #  #  #  :           0 :               icmp_.user_comparator()->Name());
                   #  # ]
     916                 :             :         }
     917                 :             :       }
     918                 :             : 
     919         [ +  - ]:        4897 :       if (s.ok()) {
     920         [ +  - ]:        4897 :         builder.Apply(&edit);
     921                 :             :       }
     922                 :             : 
     923         [ +  + ]:        4897 :       if (edit.has_log_number_) {
     924                 :        3097 :         log_number = edit.log_number_;
     925                 :        3097 :         have_log_number = true;
     926                 :             :       }
     927                 :             : 
     928         [ +  + ]:        4897 :       if (edit.has_prev_log_number_) {
     929                 :        2004 :         prev_log_number = edit.prev_log_number_;
     930                 :        2004 :         have_prev_log_number = true;
     931                 :             :       }
     932                 :             : 
     933         [ +  + ]:        4897 :       if (edit.has_next_file_number_) {
     934                 :        3097 :         next_file = edit.next_file_number_;
     935                 :        3097 :         have_next_file = true;
     936                 :             :       }
     937                 :             : 
     938         [ +  + ]:        4897 :       if (edit.has_last_sequence_) {
     939                 :        3097 :         last_sequence = edit.last_sequence_;
     940                 :        3097 :         have_last_sequence = true;
     941                 :             :       }
     942                 :        4897 :     }
     943                 :        2893 :   }
     944         [ +  - ]:        2893 :   delete file;
     945                 :        2893 :   file = nullptr;
     946                 :             : 
     947         [ +  - ]:        2893 :   if (s.ok()) {
     948         [ -  + ]:        2893 :     if (!have_next_file) {
     949   [ #  #  #  # ]:           0 :       s = Status::Corruption("no meta-nextfile entry in descriptor");
     950         [ -  + ]:        2893 :     } else if (!have_log_number) {
     951   [ #  #  #  # ]:           0 :       s = Status::Corruption("no meta-lognumber entry in descriptor");
     952         [ -  + ]:        2893 :     } else if (!have_last_sequence) {
     953   [ #  #  #  # ]:           0 :       s = Status::Corruption("no last-sequence-number entry in descriptor");
     954                 :             :     }
     955                 :             : 
     956         [ +  + ]:        2893 :     if (!have_prev_log_number) {
     957                 :        1093 :       prev_log_number = 0;
     958                 :             :     }
     959                 :             : 
     960         [ +  - ]:        2893 :     MarkFileNumberUsed(prev_log_number);
     961         [ +  - ]:        2893 :     MarkFileNumberUsed(log_number);
     962                 :             :   }
     963                 :             : 
     964         [ +  - ]:        2893 :   if (s.ok()) {
     965   [ +  -  +  - ]:        2893 :     Version* v = new Version(this);
     966         [ +  - ]:        2893 :     builder.SaveTo(v);
     967                 :             :     // Install recovered version
     968         [ +  - ]:        2893 :     Finalize(v);
     969         [ +  - ]:        2893 :     AppendVersion(v);
     970                 :        2893 :     manifest_file_number_ = next_file;
     971                 :        2893 :     next_file_number_ = next_file + 1;
     972                 :        2893 :     last_sequence_ = last_sequence;
     973                 :        2893 :     log_number_ = log_number;
     974                 :        2893 :     prev_log_number_ = prev_log_number;
     975                 :             : 
     976                 :             :     // See if we can reuse the existing MANIFEST file.
     977   [ +  -  +  - ]:        2893 :     if (ReuseManifest(dscname, current)) {
     978                 :             :       // No need to save new manifest
     979                 :             :     } else {
     980                 :        2893 :       *save_manifest = true;
     981                 :             :     }
     982                 :             :   }
     983                 :             : 
     984                 :        2893 :   return s;
     985                 :        8685 : }
     986                 :             : 
     987                 :        2893 : bool VersionSet::ReuseManifest(const std::string& dscname,
     988                 :             :                                const std::string& dscbase) {
     989         [ -  + ]:        2893 :   if (!options_->reuse_logs) {
     990                 :             :     return false;
     991                 :             :   }
     992                 :           0 :   FileType manifest_type;
     993                 :           0 :   uint64_t manifest_number;
     994                 :           0 :   uint64_t manifest_size = 0;
     995         [ #  # ]:           0 :   if (!ParseFileName(dscbase, &manifest_number, &manifest_type) ||
     996   [ #  #  #  # ]:           0 :       manifest_type != kDescriptorFile ||
     997   [ #  #  #  # ]:           0 :       !env_->GetFileSize(dscname, &manifest_size).ok() ||
     998                 :             :       // Make new compacted MANIFEST if old one is too big
     999         [ #  # ]:           0 :       manifest_size >= TargetFileSize(options_)) {
    1000                 :             :     return false;
    1001                 :             :   }
    1002                 :             : 
    1003         [ #  # ]:           0 :   assert(descriptor_file_ == nullptr);
    1004         [ #  # ]:           0 :   assert(descriptor_log_ == nullptr);
    1005                 :           0 :   Status r = env_->NewAppendableFile(dscname, &descriptor_file_);
    1006         [ #  # ]:           0 :   if (!r.ok()) {
    1007   [ #  #  #  # ]:           0 :     Log(options_->info_log, "Reuse MANIFEST: %s\n", r.ToString().c_str());
    1008         [ #  # ]:           0 :     assert(descriptor_file_ == nullptr);
    1009                 :             :     return false;
    1010                 :             :   }
    1011                 :             : 
    1012         [ #  # ]:           0 :   Log(options_->info_log, "Reusing MANIFEST %s\n", dscname.c_str());
    1013   [ #  #  #  # ]:           0 :   descriptor_log_ = new log::Writer(descriptor_file_, manifest_size);
    1014                 :           0 :   manifest_file_number_ = manifest_number;
    1015                 :           0 :   return true;
    1016                 :           0 : }
    1017                 :             : 
    1018                 :        7582 : void VersionSet::MarkFileNumberUsed(uint64_t number) {
    1019         [ +  + ]:        7582 :   if (next_file_number_ <= number) {
    1020                 :        1800 :     next_file_number_ = number + 1;
    1021                 :             :   }
    1022                 :        7582 : }
    1023                 :             : 
    1024                 :        6050 : void VersionSet::Finalize(Version* v) {
    1025                 :             :   // Precomputed best level for next compaction
    1026                 :        6050 :   int best_level = -1;
    1027                 :        6050 :   double best_score = -1;
    1028                 :             : 
    1029         [ +  + ]:       42350 :   for (int level = 0; level < config::kNumLevels - 1; level++) {
    1030                 :       36300 :     double score;
    1031         [ +  + ]:       36300 :     if (level == 0) {
    1032                 :             :       // We treat level-0 specially by bounding the number of files
    1033                 :             :       // instead of number of bytes for two reasons:
    1034                 :             :       //
    1035                 :             :       // (1) With larger write-buffer sizes, it is nice not to do too
    1036                 :             :       // many level-0 compactions.
    1037                 :             :       //
    1038                 :             :       // (2) The files in level-0 are merged on every read and
    1039                 :             :       // therefore we wish to avoid too many files when the individual
    1040                 :             :       // file size is small (perhaps because of a small write-buffer
    1041                 :             :       // setting, or very high compression ratios, or lots of
    1042                 :             :       // overwrites/deletions).
    1043         [ -  + ]:        6050 :       score = v->files_[level].size() /
    1044                 :             :               static_cast<double>(config::kL0_CompactionTrigger);
    1045                 :             :     } else {
    1046                 :             :       // Compute the ratio of current size to size limit.
    1047                 :       30250 :       const uint64_t level_bytes = TotalFileSize(v->files_[level]);
    1048                 :       30250 :       score =
    1049                 :       30250 :           static_cast<double>(level_bytes) / MaxBytesForLevel(options_, level);
    1050                 :             :     }
    1051                 :             : 
    1052         [ +  + ]:       36300 :     if (score > best_score) {
    1053                 :        6522 :       best_level = level;
    1054                 :        6522 :       best_score = score;
    1055                 :             :     }
    1056                 :             :   }
    1057                 :             : 
    1058                 :        6050 :   v->compaction_level_ = best_level;
    1059                 :        6050 :   v->compaction_score_ = best_score;
    1060                 :        6050 : }
    1061                 :             : 
    1062                 :        2888 : Status VersionSet::WriteSnapshot(log::Writer* log) {
    1063                 :             :   // TODO: Break up into multiple records to reduce memory usage on recovery?
    1064                 :             : 
    1065                 :             :   // Save metadata
    1066                 :        2888 :   VersionEdit edit;
    1067   [ +  -  +  - ]:        2888 :   edit.SetComparatorName(icmp_.user_comparator()->Name());
    1068                 :             : 
    1069                 :             :   // Save compaction pointers
    1070         [ +  + ]:       23104 :   for (int level = 0; level < config::kNumLevels; level++) {
    1071         [ +  + ]:       20216 :     if (!compact_pointer_[level].empty()) {
    1072         [ -  + ]:         584 :       InternalKey key;
    1073   [ -  +  +  - ]:         584 :       key.DecodeFrom(compact_pointer_[level]);
    1074         [ +  - ]:         584 :       edit.SetCompactPointer(level, key);
    1075                 :         584 :     }
    1076                 :             :   }
    1077                 :             : 
    1078                 :             :   // Save files
    1079         [ +  + ]:       23104 :   for (int level = 0; level < config::kNumLevels; level++) {
    1080                 :       20216 :     const std::vector<FileMetaData*>& files = current_->files_[level];
    1081   [ -  +  +  + ]:       22604 :     for (size_t i = 0; i < files.size(); i++) {
    1082         [ +  - ]:        2388 :       const FileMetaData* f = files[i];
    1083         [ +  - ]:        2388 :       edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest);
    1084                 :             :     }
    1085                 :             :   }
    1086                 :             : 
    1087         [ +  - ]:        2888 :   std::string record;
    1088         [ +  - ]:        2888 :   edit.EncodeTo(&record);
    1089   [ -  +  +  - ]:        5776 :   return log->AddRecord(record);
    1090                 :        2888 : }
    1091                 :             : 
    1092                 :       42970 : int VersionSet::NumLevelFiles(int level) const {
    1093         [ -  + ]:       42970 :   assert(level >= 0);
    1094         [ -  + ]:       42970 :   assert(level < config::kNumLevels);
    1095         [ -  + ]:       42970 :   return current_->files_[level].size();
    1096                 :             : }
    1097                 :             : 
    1098                 :         225 : const char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const {
    1099                 :             :   // Update code if kNumLevels changes
    1100                 :         225 :   static_assert(config::kNumLevels == 7, "");
    1101                 :        1800 :   snprintf(scratch->buffer, sizeof(scratch->buffer),
    1102                 :         450 :            "files[ %d %d %d %d %d %d %d ]", int(current_->files_[0].size()),
    1103   [ -  +  -  + ]:         225 :            int(current_->files_[1].size()), int(current_->files_[2].size()),
    1104   [ -  +  -  + ]:         225 :            int(current_->files_[3].size()), int(current_->files_[4].size()),
    1105   [ -  +  -  +  :         225 :            int(current_->files_[5].size()), int(current_->files_[6].size()));
                   -  + ]
    1106                 :         225 :   return scratch->buffer;
    1107                 :             : }
    1108                 :             : 
    1109                 :         208 : uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) {
    1110                 :         208 :   uint64_t result = 0;
    1111         [ +  + ]:        1664 :   for (int level = 0; level < config::kNumLevels; level++) {
    1112                 :             :     const std::vector<FileMetaData*>& files = v->files_[level];
    1113   [ -  +  +  + ]:        1730 :     for (size_t i = 0; i < files.size(); i++) {
    1114         [ +  + ]:         274 :       if (icmp_.Compare(files[i]->largest, ikey) <= 0) {
    1115                 :             :         // Entire file is before "ikey", so just add the file size
    1116                 :          39 :         result += files[i]->file_size;
    1117         [ -  + ]:         235 :       } else if (icmp_.Compare(files[i]->smallest, ikey) > 0) {
    1118                 :             :         // Entire file is after "ikey", so ignore
    1119         [ #  # ]:           0 :         if (level > 0) {
    1120                 :             :           // Files other than level 0 are sorted by meta->smallest, so
    1121                 :             :           // no further files in this level will contain data for
    1122                 :             :           // "ikey".
    1123                 :             :           break;
    1124                 :             :         }
    1125                 :             :       } else {
    1126                 :             :         // "ikey" falls in the range for this table.  Add the
    1127                 :             :         // approximate offset of "ikey" within the table.
    1128                 :         235 :         Table* tableptr;
    1129                 :         235 :         Iterator* iter = table_cache_->NewIterator(
    1130                 :         235 :             ReadOptions(), files[i]->number, files[i]->file_size, &tableptr);
    1131         [ +  - ]:         235 :         if (tableptr != nullptr) {
    1132                 :         235 :           result += tableptr->ApproximateOffsetOf(ikey.Encode());
    1133                 :             :         }
    1134         [ +  - ]:         235 :         delete iter;
    1135                 :             :       }
    1136                 :             :     }
    1137                 :             :   }
    1138                 :         208 :   return result;
    1139                 :             : }
    1140                 :             : 
    1141                 :        6048 : void VersionSet::AddLiveFiles(std::set<uint64_t>* live) {
    1142         [ +  + ]:       12099 :   for (Version* v = dummy_versions_.next_; v != &dummy_versions_;
    1143                 :        6051 :        v = v->next_) {
    1144         [ +  + ]:       48408 :     for (int level = 0; level < config::kNumLevels; level++) {
    1145                 :             :       const std::vector<FileMetaData*>& files = v->files_[level];
    1146   [ -  +  +  + ]:       49324 :       for (size_t i = 0; i < files.size(); i++) {
    1147                 :        6967 :         live->insert(files[i]->number);
    1148                 :             :       }
    1149                 :             :     }
    1150                 :             :   }
    1151                 :        6048 : }
    1152                 :             : 
    1153                 :           0 : int64_t VersionSet::NumLevelBytes(int level) const {
    1154         [ #  # ]:           0 :   assert(level >= 0);
    1155         [ #  # ]:           0 :   assert(level < config::kNumLevels);
    1156                 :           0 :   return TotalFileSize(current_->files_[level]);
    1157                 :             : }
    1158                 :             : 
    1159                 :           0 : int64_t VersionSet::MaxNextLevelOverlappingBytes() {
    1160                 :           0 :   int64_t result = 0;
    1161                 :           0 :   std::vector<FileMetaData*> overlaps;
    1162         [ #  # ]:           0 :   for (int level = 1; level < config::kNumLevels - 1; level++) {
    1163   [ #  #  #  # ]:           0 :     for (size_t i = 0; i < current_->files_[level].size(); i++) {
    1164         [ #  # ]:           0 :       const FileMetaData* f = current_->files_[level][i];
    1165         [ #  # ]:           0 :       current_->GetOverlappingInputs(level + 1, &f->smallest, &f->largest,
    1166                 :             :                                      &overlaps);
    1167                 :           0 :       const int64_t sum = TotalFileSize(overlaps);
    1168         [ #  # ]:           0 :       if (sum > result) {
    1169                 :           0 :         result = sum;
    1170                 :             :       }
    1171                 :             :     }
    1172                 :             :   }
    1173                 :           0 :   return result;
    1174                 :           0 : }
    1175                 :             : 
    1176                 :             : // Stores the minimal range that covers all entries in inputs in
    1177                 :             : // *smallest, *largest.
    1178                 :             : // REQUIRES: inputs is not empty
    1179                 :         675 : void VersionSet::GetRange(const std::vector<FileMetaData*>& inputs,
    1180                 :             :                           InternalKey* smallest, InternalKey* largest) {
    1181         [ -  + ]:         675 :   assert(!inputs.empty());
    1182                 :         675 :   smallest->Clear();
    1183                 :         675 :   largest->Clear();
    1184   [ -  +  +  + ]:        2779 :   for (size_t i = 0; i < inputs.size(); i++) {
    1185         [ +  + ]:        2104 :     FileMetaData* f = inputs[i];
    1186         [ +  + ]:        2104 :     if (i == 0) {
    1187                 :         675 :       *smallest = f->smallest;
    1188                 :         675 :       *largest = f->largest;
    1189                 :             :     } else {
    1190         [ +  + ]:        1429 :       if (icmp_.Compare(f->smallest, *smallest) < 0) {
    1191                 :          80 :         *smallest = f->smallest;
    1192                 :             :       }
    1193         [ +  + ]:        1429 :       if (icmp_.Compare(f->largest, *largest) > 0) {
    1194                 :         542 :         *largest = f->largest;
    1195                 :             :       }
    1196                 :             :     }
    1197                 :             :   }
    1198                 :         675 : }
    1199                 :             : 
    1200                 :             : // Stores the minimal range that covers all entries in inputs1 and inputs2
    1201                 :             : // in *smallest, *largest.
    1202                 :             : // REQUIRES: inputs is not empty
    1203                 :         225 : void VersionSet::GetRange2(const std::vector<FileMetaData*>& inputs1,
    1204                 :             :                            const std::vector<FileMetaData*>& inputs2,
    1205                 :             :                            InternalKey* smallest, InternalKey* largest) {
    1206                 :         225 :   std::vector<FileMetaData*> all = inputs1;
    1207         [ +  - ]:         225 :   all.insert(all.end(), inputs2.begin(), inputs2.end());
    1208         [ +  - ]:         225 :   GetRange(all, smallest, largest);
    1209                 :         225 : }
    1210                 :             : 
    1211                 :         223 : Iterator* VersionSet::MakeInputIterator(Compaction* c) {
    1212                 :         223 :   ReadOptions options;
    1213                 :         223 :   options.verify_checksums = options_->paranoid_checks;
    1214                 :         223 :   options.fill_cache = false;
    1215                 :             : 
    1216                 :             :   // Level-0 files have to be merged together.  For other levels,
    1217                 :             :   // we will make a concatenating iterator per level.
    1218                 :             :   // TODO(opt): use concatenating iterator for level-0 if there is no overlap
    1219   [ +  -  -  + ]:         223 :   const int space = (c->level() == 0 ? c->inputs_[0].size() + 1 : 2);
    1220         [ +  - ]:         223 :   Iterator** list = new Iterator*[space];
    1221                 :         223 :   int num = 0;
    1222         [ +  + ]:         669 :   for (int which = 0; which < 2; which++) {
    1223         [ +  + ]:         446 :     if (!c->inputs_[which].empty()) {
    1224         [ +  + ]:         316 :       if (c->level() + which == 0) {
    1225                 :             :         const std::vector<FileMetaData*>& files = c->inputs_[which];
    1226   [ -  +  +  + ]:        1114 :         for (size_t i = 0; i < files.size(); i++) {
    1227                 :         891 :           list[num++] = table_cache_->NewIterator(options, files[i]->number,
    1228                 :         891 :                                                   files[i]->file_size);
    1229                 :             :         }
    1230                 :             :       } else {
    1231                 :             :         // Create concatenating iterator for the files from this level
    1232   [ +  -  -  - ]:          93 :         list[num++] = NewTwoLevelIterator(
    1233         [ +  - ]:          93 :             new Version::LevelFileNumIterator(icmp_, &c->inputs_[which]),
    1234                 :          93 :             &GetFileIterator, table_cache_, options);
    1235                 :             :       }
    1236                 :             :     }
    1237                 :             :   }
    1238         [ -  + ]:         223 :   assert(num <= space);
    1239                 :         223 :   Iterator* result = NewMergingIterator(&icmp_, list, num);
    1240         [ +  - ]:         223 :   delete[] list;
    1241                 :         223 :   return result;
    1242                 :             : }
    1243                 :             : 
    1244                 :         225 : Compaction* VersionSet::PickCompaction() {
    1245                 :         225 :   Compaction* c;
    1246                 :         225 :   int level;
    1247                 :             : 
    1248                 :             :   // We prefer compactions triggered by too much data in a level over
    1249                 :             :   // the compactions triggered by seeks.
    1250                 :         225 :   const bool size_compaction = (current_->compaction_score_ >= 1);
    1251                 :         225 :   const bool seek_compaction = (current_->file_to_compact_ != nullptr);
    1252         [ +  - ]:         225 :   if (size_compaction) {
    1253                 :         225 :     level = current_->compaction_level_;
    1254         [ -  + ]:         225 :     assert(level >= 0);
    1255         [ -  + ]:         225 :     assert(level + 1 < config::kNumLevels);
    1256         [ +  - ]:         225 :     c = new Compaction(options_, level);
    1257                 :             : 
    1258                 :             :     // Pick the first file that comes after compact_pointer_[level]
    1259   [ -  +  +  + ]:         582 :     for (size_t i = 0; i < current_->files_[level].size(); i++) {
    1260         [ +  + ]:         494 :       FileMetaData* f = current_->files_[level][i];
    1261   [ +  +  +  + ]:         857 :       if (compact_pointer_[level].empty() ||
    1262         [ -  + ]:         363 :           icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) {
    1263                 :         137 :         c->inputs_[0].push_back(f);
    1264                 :         137 :         break;
    1265                 :             :       }
    1266                 :             :     }
    1267         [ +  + ]:         225 :     if (c->inputs_[0].empty()) {
    1268                 :             :       // Wrap-around to the beginning of the key space
    1269                 :          88 :       c->inputs_[0].push_back(current_->files_[level][0]);
    1270                 :             :     }
    1271         [ #  # ]:           0 :   } else if (seek_compaction) {
    1272                 :           0 :     level = current_->file_to_compact_level_;
    1273         [ #  # ]:           0 :     c = new Compaction(options_, level);
    1274                 :           0 :     c->inputs_[0].push_back(current_->file_to_compact_);
    1275                 :             :   } else {
    1276                 :             :     return nullptr;
    1277                 :             :   }
    1278                 :             : 
    1279                 :         225 :   c->input_version_ = current_;
    1280                 :         225 :   c->input_version_->Ref();
    1281                 :             : 
    1282                 :             :   // Files in level 0 may overlap each other, so pick up all overlapping ones
    1283         [ +  - ]:         225 :   if (level == 0) {
    1284         [ +  - ]:         225 :     InternalKey smallest, largest;
    1285         [ +  - ]:         225 :     GetRange(c->inputs_[0], &smallest, &largest);
    1286                 :             :     // Note that the next call will discard the file we placed in
    1287                 :             :     // c->inputs_[0] earlier and replace it with an overlapping set
    1288                 :             :     // which will include the picked file.
    1289         [ +  - ]:         225 :     current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]);
    1290         [ -  + ]:         225 :     assert(!c->inputs_[0].empty());
    1291                 :         225 :   }
    1292                 :             : 
    1293                 :         225 :   SetupOtherInputs(c);
    1294                 :             : 
    1295                 :         225 :   return c;
    1296                 :             : }
    1297                 :             : 
    1298                 :             : // Finds the largest key in a vector of files. Returns true if files it not
    1299                 :             : // empty.
    1300                 :         318 : bool FindLargestKey(const InternalKeyComparator& icmp,
    1301                 :             :                     const std::vector<FileMetaData*>& files,
    1302                 :             :                     InternalKey* largest_key) {
    1303         [ +  - ]:         318 :   if (files.empty()) {
    1304                 :             :     return false;
    1305                 :             :   }
    1306                 :         318 :   *largest_key = files[0]->largest;
    1307   [ -  +  +  + ]:        1265 :   for (size_t i = 1; i < files.size(); ++i) {
    1308                 :         947 :     FileMetaData* f = files[i];
    1309         [ +  + ]:         947 :     if (icmp.Compare(f->largest, *largest_key) > 0) {
    1310                 :         479 :       *largest_key = f->largest;
    1311                 :             :     }
    1312                 :             :   }
    1313                 :             :   return true;
    1314                 :             : }
    1315                 :             : 
    1316                 :             : // Finds minimum file b2=(l2, u2) in level file for which l2 > u1 and
    1317                 :             : // user_key(l2) = user_key(u1)
    1318                 :         318 : FileMetaData* FindSmallestBoundaryFile(
    1319                 :             :     const InternalKeyComparator& icmp,
    1320                 :             :     const std::vector<FileMetaData*>& level_files,
    1321                 :             :     const InternalKey& largest_key) {
    1322                 :         318 :   const Comparator* user_cmp = icmp.user_comparator();
    1323                 :         318 :   FileMetaData* smallest_boundary_file = nullptr;
    1324   [ -  +  +  + ]:        1590 :   for (size_t i = 0; i < level_files.size(); ++i) {
    1325                 :        1272 :     FileMetaData* f = level_files[i];
    1326   [ +  +  -  + ]:        1276 :     if (icmp.Compare(f->smallest, largest_key) > 0 &&
    1327   [ -  +  -  + ]:          12 :         user_cmp->Compare(f->smallest.user_key(), largest_key.user_key()) ==
    1328                 :             :             0) {
    1329   [ #  #  #  # ]:           0 :       if (smallest_boundary_file == nullptr ||
    1330                 :           0 :           icmp.Compare(f->smallest, smallest_boundary_file->smallest) < 0) {
    1331                 :             :         smallest_boundary_file = f;
    1332                 :             :       }
    1333                 :             :     }
    1334                 :             :   }
    1335                 :         318 :   return smallest_boundary_file;
    1336                 :             : }
    1337                 :             : 
    1338                 :             : // Extracts the largest file b1 from |compaction_files| and then searches for a
    1339                 :             : // b2 in |level_files| for which user_key(u1) = user_key(l2). If it finds such a
    1340                 :             : // file b2 (known as a boundary file) it adds it to |compaction_files| and then
    1341                 :             : // searches again using this new upper bound.
    1342                 :             : //
    1343                 :             : // If there are two blocks, b1=(l1, u1) and b2=(l2, u2) and
    1344                 :             : // user_key(u1) = user_key(l2), and if we compact b1 but not b2 then a
    1345                 :             : // subsequent get operation will yield an incorrect result because it will
    1346                 :             : // return the record from b2 in level i rather than from b1 because it searches
    1347                 :             : // level by level for records matching the supplied user key.
    1348                 :             : //
    1349                 :             : // parameters:
    1350                 :             : //   in     level_files:      List of files to search for boundary files.
    1351                 :             : //   in/out compaction_files: List of files to extend by adding boundary files.
    1352                 :         318 : void AddBoundaryInputs(const InternalKeyComparator& icmp,
    1353                 :             :                        const std::vector<FileMetaData*>& level_files,
    1354                 :             :                        std::vector<FileMetaData*>* compaction_files) {
    1355         [ +  - ]:         318 :   InternalKey largest_key;
    1356                 :             : 
    1357                 :             :   // Quick return if compaction_files is empty.
    1358   [ +  -  -  + ]:         318 :   if (!FindLargestKey(icmp, *compaction_files, &largest_key)) {
    1359                 :           0 :     return;
    1360                 :             :   }
    1361                 :             : 
    1362                 :             :   bool continue_searching = true;
    1363                 :         636 :   while (continue_searching) {
    1364                 :         318 :     FileMetaData* smallest_boundary_file =
    1365                 :         636 :         FindSmallestBoundaryFile(icmp, level_files, largest_key);
    1366                 :             : 
    1367                 :             :     // If a boundary file was found advance largest_key, otherwise we're done.
    1368         [ +  - ]:         318 :     if (smallest_boundary_file != NULL) {
    1369         [ #  # ]:           0 :       compaction_files->push_back(smallest_boundary_file);
    1370   [ -  -  +  - ]:         636 :       largest_key = smallest_boundary_file->largest;
    1371                 :             :     } else {
    1372                 :             :       continue_searching = false;
    1373                 :             :     }
    1374                 :             :   }
    1375                 :         318 : }
    1376                 :             : 
    1377                 :         225 : void VersionSet::SetupOtherInputs(Compaction* c) {
    1378         [ +  - ]:         225 :   const int level = c->level();
    1379         [ +  - ]:         225 :   InternalKey smallest, largest;
    1380                 :             : 
    1381         [ +  - ]:         225 :   AddBoundaryInputs(icmp_, current_->files_[level], &c->inputs_[0]);
    1382         [ +  - ]:         225 :   GetRange(c->inputs_[0], &smallest, &largest);
    1383                 :             : 
    1384         [ +  - ]:         225 :   current_->GetOverlappingInputs(level + 1, &smallest, &largest,
    1385                 :             :                                  &c->inputs_[1]);
    1386                 :             : 
    1387                 :             :   // Get entire range covered by compaction
    1388         [ +  - ]:         225 :   InternalKey all_start, all_limit;
    1389         [ +  - ]:         225 :   GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit);
    1390                 :             : 
    1391                 :             :   // See if we can grow the number of inputs in "level" without
    1392                 :             :   // changing the number of "level+1" files we pick up.
    1393         [ +  + ]:         225 :   if (!c->inputs_[1].empty()) {
    1394                 :          93 :     std::vector<FileMetaData*> expanded0;
    1395         [ +  - ]:          93 :     current_->GetOverlappingInputs(level, &all_start, &all_limit, &expanded0);
    1396         [ +  - ]:          93 :     AddBoundaryInputs(icmp_, current_->files_[level], &expanded0);
    1397                 :          93 :     const int64_t inputs0_size = TotalFileSize(c->inputs_[0]);
    1398                 :          93 :     const int64_t inputs1_size = TotalFileSize(c->inputs_[1]);
    1399                 :          93 :     const int64_t expanded0_size = TotalFileSize(expanded0);
    1400   [ -  +  -  +  :          93 :     if (expanded0.size() > c->inputs_[0].size() &&
                   -  + ]
    1401                 :           0 :         inputs1_size + expanded0_size <
    1402         [ #  # ]:           0 :             ExpandedCompactionByteSizeLimit(options_)) {
    1403         [ #  # ]:           0 :       InternalKey new_start, new_limit;
    1404         [ #  # ]:           0 :       GetRange(expanded0, &new_start, &new_limit);
    1405                 :           0 :       std::vector<FileMetaData*> expanded1;
    1406         [ #  # ]:           0 :       current_->GetOverlappingInputs(level + 1, &new_start, &new_limit,
    1407                 :             :                                      &expanded1);
    1408   [ #  #  #  #  :           0 :       if (expanded1.size() == c->inputs_[1].size()) {
                   #  # ]
    1409         [ #  # ]:           0 :         Log(options_->info_log,
    1410                 :             :             "Expanding@%d %d+%d (%ld+%ld bytes) to %d+%d (%ld+%ld bytes)\n",
    1411         [ #  # ]:           0 :             level, int(c->inputs_[0].size()), int(c->inputs_[1].size()),
    1412         [ #  # ]:           0 :             long(inputs0_size), long(inputs1_size), int(expanded0.size()),
    1413         [ #  # ]:           0 :             int(expanded1.size()), long(expanded0_size), long(inputs1_size));
    1414         [ #  # ]:           0 :         smallest = new_start;
    1415         [ #  # ]:           0 :         largest = new_limit;
    1416         [ #  # ]:           0 :         c->inputs_[0] = expanded0;
    1417         [ #  # ]:           0 :         c->inputs_[1] = expanded1;
    1418         [ #  # ]:           0 :         GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit);
    1419                 :             :       }
    1420                 :           0 :     }
    1421                 :          93 :   }
    1422                 :             : 
    1423                 :             :   // Compute the set of grandparent files that overlap this compaction
    1424                 :             :   // (parent == level+1; grandparent == level+2)
    1425         [ +  - ]:         225 :   if (level + 2 < config::kNumLevels) {
    1426         [ +  - ]:         225 :     current_->GetOverlappingInputs(level + 2, &all_start, &all_limit,
    1427                 :             :                                    &c->grandparents_);
    1428                 :             :   }
    1429                 :             : 
    1430                 :             :   // Update the place where we will do the next compaction for this level.
    1431                 :             :   // We update this immediately instead of waiting for the VersionEdit
    1432                 :             :   // to be applied so that if the compaction fails, we will try a different
    1433                 :             :   // key range next time.
    1434         [ +  - ]:         225 :   compact_pointer_[level] = largest.Encode().ToString();
    1435         [ +  - ]:         225 :   c->edit_.SetCompactPointer(level, largest);
    1436                 :         225 : }
    1437                 :             : 
    1438                 :           0 : Compaction* VersionSet::CompactRange(int level, const InternalKey* begin,
    1439                 :             :                                      const InternalKey* end) {
    1440                 :           0 :   std::vector<FileMetaData*> inputs;
    1441         [ #  # ]:           0 :   current_->GetOverlappingInputs(level, begin, end, &inputs);
    1442         [ #  # ]:           0 :   if (inputs.empty()) {
    1443                 :             :     return nullptr;
    1444                 :             :   }
    1445                 :             : 
    1446                 :             :   // Avoid compacting too much in one shot in case the range is large.
    1447                 :             :   // But we cannot do this for level-0 since level-0 files can overlap
    1448                 :             :   // and we must not pick one file and drop another older file if the
    1449                 :             :   // two files overlap.
    1450         [ #  # ]:           0 :   if (level > 0) {
    1451                 :           0 :     const uint64_t limit = MaxFileSizeForLevel(options_, level);
    1452                 :           0 :     uint64_t total = 0;
    1453   [ #  #  #  # ]:           0 :     for (size_t i = 0; i < inputs.size(); i++) {
    1454         [ #  # ]:           0 :       uint64_t s = inputs[i]->file_size;
    1455                 :           0 :       total += s;
    1456         [ #  # ]:           0 :       if (total >= limit) {
    1457         [ #  # ]:           0 :         inputs.resize(i + 1);
    1458                 :             :         break;
    1459                 :             :       }
    1460                 :             :     }
    1461                 :             :   }
    1462                 :             : 
    1463   [ #  #  #  # ]:           0 :   Compaction* c = new Compaction(options_, level);
    1464                 :           0 :   c->input_version_ = current_;
    1465         [ #  # ]:           0 :   c->input_version_->Ref();
    1466         [ #  # ]:           0 :   c->inputs_[0] = inputs;
    1467         [ #  # ]:           0 :   SetupOtherInputs(c);
    1468                 :             :   return c;
    1469                 :           0 : }
    1470                 :             : 
    1471                 :         225 : Compaction::Compaction(const Options* options, int level)
    1472                 :         225 :     : level_(level),
    1473                 :         225 :       max_output_file_size_(MaxFileSizeForLevel(options, level)),
    1474                 :         225 :       input_version_(nullptr),
    1475                 :         225 :       grandparent_index_(0),
    1476                 :         225 :       seen_key_(false),
    1477                 :         225 :       overlapped_bytes_(0) {
    1478         [ +  + ]:        1800 :   for (int i = 0; i < config::kNumLevels; i++) {
    1479                 :        1575 :     level_ptrs_[i] = 0;
    1480                 :             :   }
    1481                 :         225 : }
    1482                 :             : 
    1483                 :         675 : Compaction::~Compaction() {
    1484         [ +  + ]:         225 :   if (input_version_ != nullptr) {
    1485                 :           2 :     input_version_->Unref();
    1486                 :             :   }
    1487   [ +  -  +  + ]:        1125 : }
    1488                 :             : 
    1489                 :         225 : bool Compaction::IsTrivialMove() const {
    1490                 :         225 :   const VersionSet* vset = input_version_->vset_;
    1491                 :             :   // Avoid a move if there is lots of overlapping grandparent data.
    1492                 :             :   // Otherwise, the move could create a parent file that will require
    1493                 :             :   // a very expensive merge later on.
    1494   [ -  +  +  +  :         227 :   return (num_input_files(0) == 1 && num_input_files(1) == 0 &&
                   +  - ]
    1495                 :           2 :           TotalFileSize(grandparents_) <=
    1496         [ -  + ]:           2 :               MaxGrandParentOverlapBytes(vset->options_));
    1497                 :             : }
    1498                 :             : 
    1499                 :         223 : void Compaction::AddInputDeletions(VersionEdit* edit) {
    1500         [ +  + ]:         669 :   for (int which = 0; which < 2; which++) {
    1501   [ -  +  +  + ]:        1430 :     for (size_t i = 0; i < inputs_[which].size(); i++) {
    1502                 :         984 :       edit->DeleteFile(level_ + which, inputs_[which][i]->number);
    1503                 :             :     }
    1504                 :             :   }
    1505                 :         223 : }
    1506                 :             : 
    1507                 :         807 : bool Compaction::IsBaseLevelForKey(const Slice& user_key) {
    1508                 :             :   // Maybe use binary search to find right entry instead of linear search?
    1509                 :         807 :   const Comparator* user_cmp = input_version_->vset_->icmp_.user_comparator();
    1510         [ +  + ]:        4842 :   for (int lvl = level_ + 2; lvl < config::kNumLevels; lvl++) {
    1511                 :        4035 :     const std::vector<FileMetaData*>& files = input_version_->files_[lvl];
    1512   [ -  +  -  + ]:        4035 :     while (level_ptrs_[lvl] < files.size()) {
    1513         [ #  # ]:           0 :       FileMetaData* f = files[level_ptrs_[lvl]];
    1514   [ #  #  #  # ]:           0 :       if (user_cmp->Compare(user_key, f->largest.user_key()) <= 0) {
    1515                 :             :         // We've advanced far enough
    1516   [ #  #  #  # ]:           0 :         if (user_cmp->Compare(user_key, f->smallest.user_key()) >= 0) {
    1517                 :             :           // Key falls in this file's range, so definitely not base level
    1518                 :             :           return false;
    1519                 :             :         }
    1520                 :             :         break;
    1521                 :             :       }
    1522                 :           0 :       level_ptrs_[lvl]++;
    1523                 :             :     }
    1524                 :             :   }
    1525                 :             :   return true;
    1526                 :             : }
    1527                 :             : 
    1528                 :       73231 : bool Compaction::ShouldStopBefore(const Slice& internal_key) {
    1529                 :       73231 :   const VersionSet* vset = input_version_->vset_;
    1530                 :             :   // Scan to find earliest grandparent file that contains key.
    1531                 :       73231 :   const InternalKeyComparator* icmp = &vset->icmp_;
    1532   [ -  +  +  +  :       73451 :   while (grandparent_index_ < grandparents_.size() &&
                   +  + ]
    1533                 :         219 :          icmp->Compare(internal_key,
    1534                 :         219 :                        grandparents_[grandparent_index_]->largest.Encode()) >
    1535                 :             :              0) {
    1536         [ +  - ]:           1 :     if (seen_key_) {
    1537                 :           1 :       overlapped_bytes_ += grandparents_[grandparent_index_]->file_size;
    1538                 :             :     }
    1539                 :           1 :     grandparent_index_++;
    1540                 :             :   }
    1541                 :       73231 :   seen_key_ = true;
    1542                 :             : 
    1543         [ -  + ]:       73231 :   if (overlapped_bytes_ > MaxGrandParentOverlapBytes(vset->options_)) {
    1544                 :             :     // Too much overlap for current output; start new output
    1545                 :           0 :     overlapped_bytes_ = 0;
    1546                 :           0 :     return true;
    1547                 :             :   } else {
    1548                 :             :     return false;
    1549                 :             :   }
    1550                 :             : }
    1551                 :             : 
    1552                 :         223 : void Compaction::ReleaseInputs() {
    1553         [ +  - ]:         223 :   if (input_version_ != nullptr) {
    1554                 :         223 :     input_version_->Unref();
    1555                 :         223 :     input_version_ = nullptr;
    1556                 :             :   }
    1557                 :         223 : }
    1558                 :             : 
    1559                 :             : }  // namespace leveldb
        

Generated by: LCOV version 2.0-1