LCOV - code coverage report
Current view: top level - src/leveldb/db - version_set.h (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 19 26 73.1 %
Date: 2022-04-21 14:51:19 Functions: 14 16 87.5 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 4 6 66.7 %

           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                 :            : // The representation of a DBImpl consists of a set of Versions.  The
#       6                 :            : // newest version is called "current".  Older versions may be kept
#       7                 :            : // around to provide a consistent view to live iterators.
#       8                 :            : //
#       9                 :            : // Each Version keeps track of a set of Table files per level.  The
#      10                 :            : // entire set of versions is maintained in a VersionSet.
#      11                 :            : //
#      12                 :            : // Version,VersionSet are thread-compatible, but require external
#      13                 :            : // synchronization on all accesses.
#      14                 :            : 
#      15                 :            : #ifndef STORAGE_LEVELDB_DB_VERSION_SET_H_
#      16                 :            : #define STORAGE_LEVELDB_DB_VERSION_SET_H_
#      17                 :            : 
#      18                 :            : #include <map>
#      19                 :            : #include <set>
#      20                 :            : #include <vector>
#      21                 :            : 
#      22                 :            : #include "db/dbformat.h"
#      23                 :            : #include "db/version_edit.h"
#      24                 :            : #include "port/port.h"
#      25                 :            : #include "port/thread_annotations.h"
#      26                 :            : 
#      27                 :            : namespace leveldb {
#      28                 :            : 
#      29                 :            : namespace log {
#      30                 :            : class Writer;
#      31                 :            : }
#      32                 :            : 
#      33                 :            : class Compaction;
#      34                 :            : class Iterator;
#      35                 :            : class MemTable;
#      36                 :            : class TableBuilder;
#      37                 :            : class TableCache;
#      38                 :            : class Version;
#      39                 :            : class VersionSet;
#      40                 :            : class WritableFile;
#      41                 :            : 
#      42                 :            : // Return the smallest index i such that files[i]->largest >= key.
#      43                 :            : // Return files.size() if there is no such file.
#      44                 :            : // REQUIRES: "files" contains a sorted list of non-overlapping files.
#      45                 :            : int FindFile(const InternalKeyComparator& icmp,
#      46                 :            :              const std::vector<FileMetaData*>& files, const Slice& key);
#      47                 :            : 
#      48                 :            : // Returns true iff some file in "files" overlaps the user key range
#      49                 :            : // [*smallest,*largest].
#      50                 :            : // smallest==nullptr represents a key smaller than all keys in the DB.
#      51                 :            : // largest==nullptr represents a key largest than all keys in the DB.
#      52                 :            : // REQUIRES: If disjoint_sorted_files, files[] contains disjoint ranges
#      53                 :            : //           in sorted order.
#      54                 :            : bool SomeFileOverlapsRange(const InternalKeyComparator& icmp,
#      55                 :            :                            bool disjoint_sorted_files,
#      56                 :            :                            const std::vector<FileMetaData*>& files,
#      57                 :            :                            const Slice* smallest_user_key,
#      58                 :            :                            const Slice* largest_user_key);
#      59                 :            : 
#      60                 :            : class Version {
#      61                 :            :  public:
#      62                 :            :   // Lookup the value for key.  If found, store it in *val and
#      63                 :            :   // return OK.  Else return a non-OK status.  Fills *stats.
#      64                 :            :   // REQUIRES: lock is not held
#      65                 :            :   struct GetStats {
#      66                 :            :     FileMetaData* seek_file;
#      67                 :            :     int seek_file_level;
#      68                 :            :   };
#      69                 :            : 
#      70                 :            :   // Append to *iters a sequence of iterators that will
#      71                 :            :   // yield the contents of this Version when merged together.
#      72                 :            :   // REQUIRES: This version has been saved (see VersionSet::SaveTo)
#      73                 :            :   void AddIterators(const ReadOptions&, std::vector<Iterator*>* iters);
#      74                 :            : 
#      75                 :            :   Status Get(const ReadOptions&, const LookupKey& key, std::string* val,
#      76                 :            :              GetStats* stats);
#      77                 :            : 
#      78                 :            :   // Adds "stats" into the current state.  Returns true if a new
#      79                 :            :   // compaction may need to be triggered, false otherwise.
#      80                 :            :   // REQUIRES: lock is held
#      81                 :            :   bool UpdateStats(const GetStats& stats);
#      82                 :            : 
#      83                 :            :   // Record a sample of bytes read at the specified internal key.
#      84                 :            :   // Samples are taken approximately once every config::kReadBytesPeriod
#      85                 :            :   // bytes.  Returns true if a new compaction may need to be triggered.
#      86                 :            :   // REQUIRES: lock is held
#      87                 :            :   bool RecordReadSample(Slice key);
#      88                 :            : 
#      89                 :            :   // Reference count management (so Versions do not disappear out from
#      90                 :            :   // under live iterators)
#      91                 :            :   void Ref();
#      92                 :            :   void Unref();
#      93                 :            : 
#      94                 :            :   void GetOverlappingInputs(
#      95                 :            :       int level,
#      96                 :            :       const InternalKey* begin,  // nullptr means before all keys
#      97                 :            :       const InternalKey* end,    // nullptr means after all keys
#      98                 :            :       std::vector<FileMetaData*>* inputs);
#      99                 :            : 
#     100                 :            :   // Returns true iff some file in the specified level overlaps
#     101                 :            :   // some part of [*smallest_user_key,*largest_user_key].
#     102                 :            :   // smallest_user_key==nullptr represents a key smaller than all the DB's keys.
#     103                 :            :   // largest_user_key==nullptr represents a key largest than all the DB's keys.
#     104                 :            :   bool OverlapInLevel(int level, const Slice* smallest_user_key,
#     105                 :            :                       const Slice* largest_user_key);
#     106                 :            : 
#     107                 :            :   // Return the level at which we should place a new memtable compaction
#     108                 :            :   // result that covers the range [smallest_user_key,largest_user_key].
#     109                 :            :   int PickLevelForMemTableOutput(const Slice& smallest_user_key,
#     110                 :            :                                  const Slice& largest_user_key);
#     111                 :            : 
#     112                 :          0 :   int NumFiles(int level) const { return files_[level].size(); }
#     113                 :            : 
#     114                 :            :   // Return a human readable string that describes this version's contents.
#     115                 :            :   std::string DebugString() const;
#     116                 :            : 
#     117                 :            :  private:
#     118                 :            :   friend class Compaction;
#     119                 :            :   friend class VersionSet;
#     120                 :            : 
#     121                 :            :   class LevelFileNumIterator;
#     122                 :            : 
#     123                 :            :   explicit Version(VersionSet* vset)
#     124                 :            :       : vset_(vset),
#     125                 :            :         next_(this),
#     126                 :            :         prev_(this),
#     127                 :            :         refs_(0),
#     128                 :            :         file_to_compact_(nullptr),
#     129                 :            :         file_to_compact_level_(-1),
#     130                 :            :         compaction_score_(-1),
#     131                 :       8881 :         compaction_level_(-1) {}
#     132                 :            : 
#     133                 :            :   Version(const Version&) = delete;
#     134                 :            :   Version& operator=(const Version&) = delete;
#     135                 :            : 
#     136                 :            :   ~Version();
#     137                 :            : 
#     138                 :            :   Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const;
#     139                 :            : 
#     140                 :            :   // Call func(arg, level, f) for every file that overlaps user_key in
#     141                 :            :   // order from newest to oldest.  If an invocation of func returns
#     142                 :            :   // false, makes no more calls.
#     143                 :            :   //
#     144                 :            :   // REQUIRES: user portion of internal_key == user_key.
#     145                 :            :   void ForEachOverlapping(Slice user_key, Slice internal_key, void* arg,
#     146                 :            :                           bool (*func)(void*, int, FileMetaData*));
#     147                 :            : 
#     148                 :            :   VersionSet* vset_;  // VersionSet to which this Version belongs
#     149                 :            :   Version* next_;     // Next version in linked list
#     150                 :            :   Version* prev_;     // Previous version in linked list
#     151                 :            :   int refs_;          // Number of live refs to this version
#     152                 :            : 
#     153                 :            :   // List of files per level
#     154                 :            :   std::vector<FileMetaData*> files_[config::kNumLevels];
#     155                 :            : 
#     156                 :            :   // Next file to compact based on seek stats.
#     157                 :            :   FileMetaData* file_to_compact_;
#     158                 :            :   int file_to_compact_level_;
#     159                 :            : 
#     160                 :            :   // Level that should be compacted next and its compaction score.
#     161                 :            :   // Score < 1 means compaction is not strictly needed.  These fields
#     162                 :            :   // are initialized by Finalize().
#     163                 :            :   double compaction_score_;
#     164                 :            :   int compaction_level_;
#     165                 :            : };
#     166                 :            : 
#     167                 :            : class VersionSet {
#     168                 :            :  public:
#     169                 :            :   VersionSet(const std::string& dbname, const Options* options,
#     170                 :            :              TableCache* table_cache, const InternalKeyComparator*);
#     171                 :            :   VersionSet(const VersionSet&) = delete;
#     172                 :            :   VersionSet& operator=(const VersionSet&) = delete;
#     173                 :            : 
#     174                 :            :   ~VersionSet();
#     175                 :            : 
#     176                 :            :   // Apply *edit to the current version to form a new descriptor that
#     177                 :            :   // is both saved to persistent state and installed as the new
#     178                 :            :   // current version.  Will release *mu while actually writing to the file.
#     179                 :            :   // REQUIRES: *mu is held on entry.
#     180                 :            :   // REQUIRES: no other thread concurrently calls LogAndApply()
#     181                 :            :   Status LogAndApply(VersionEdit* edit, port::Mutex* mu)
#     182                 :            :       EXCLUSIVE_LOCKS_REQUIRED(mu);
#     183                 :            : 
#     184                 :            :   // Recover the last saved descriptor from persistent storage.
#     185                 :            :   Status Recover(bool* save_manifest);
#     186                 :            : 
#     187                 :            :   // Return the current version.
#     188                 :   10094433 :   Version* current() const { return current_; }
#     189                 :            : 
#     190                 :            :   // Return the current manifest file number
#     191                 :       4493 :   uint64_t ManifestFileNumber() const { return manifest_file_number_; }
#     192                 :            : 
#     193                 :            :   // Allocate and return a new file number
#     194                 :       3271 :   uint64_t NewFileNumber() { return next_file_number_++; }
#     195                 :            : 
#     196                 :            :   // Arrange to reuse "file_number" unless a newer file number has
#     197                 :            :   // already been allocated.
#     198                 :            :   // REQUIRES: "file_number" was returned by a call to NewFileNumber().
#     199                 :          0 :   void ReuseFileNumber(uint64_t file_number) {
#     200         [ #  # ]:          0 :     if (next_file_number_ == file_number + 1) {
#     201                 :          0 :       next_file_number_ = file_number;
#     202                 :          0 :     }
#     203                 :          0 :   }
#     204                 :            : 
#     205                 :            :   // Return the number of Table files at the specified level.
#     206                 :            :   int NumLevelFiles(int level) const;
#     207                 :            : 
#     208                 :            :   // Return the combined file size of all files at the specified level.
#     209                 :            :   int64_t NumLevelBytes(int level) const;
#     210                 :            : 
#     211                 :            :   // Return the last sequence number.
#     212                 :   10103289 :   uint64_t LastSequence() const { return last_sequence_; }
#     213                 :            : 
#     214                 :            :   // Set the last sequence number to s.
#     215                 :      14644 :   void SetLastSequence(uint64_t s) {
#     216                 :      14644 :     assert(s >= last_sequence_);
#     217                 :          0 :     last_sequence_ = s;
#     218                 :      14644 :   }
#     219                 :            : 
#     220                 :            :   // Mark the specified file number as used.
#     221                 :            :   void MarkFileNumberUsed(uint64_t number);
#     222                 :            : 
#     223                 :            :   // Return the current log file number.
#     224                 :       5469 :   uint64_t LogNumber() const { return log_number_; }
#     225                 :            : 
#     226                 :            :   // Return the log file number for the log file that is currently
#     227                 :            :   // being compacted, or zero if there is no such log file.
#     228                 :       3170 :   uint64_t PrevLogNumber() const { return prev_log_number_; }
#     229                 :            : 
#     230                 :            :   // Pick level and inputs for a new compaction.
#     231                 :            :   // Returns nullptr if there is no compaction to be done.
#     232                 :            :   // Otherwise returns a pointer to a heap-allocated object that
#     233                 :            :   // describes the compaction.  Caller should delete the result.
#     234                 :            :   Compaction* PickCompaction();
#     235                 :            : 
#     236                 :            :   // Return a compaction object for compacting the range [begin,end] in
#     237                 :            :   // the specified level.  Returns nullptr if there is nothing in that
#     238                 :            :   // level that overlaps the specified range.  Caller should delete
#     239                 :            :   // the result.
#     240                 :            :   Compaction* CompactRange(int level, const InternalKey* begin,
#     241                 :            :                            const InternalKey* end);
#     242                 :            : 
#     243                 :            :   // Return the maximum overlapping data (in bytes) at next level for any
#     244                 :            :   // file at a level >= 1.
#     245                 :            :   int64_t MaxNextLevelOverlappingBytes();
#     246                 :            : 
#     247                 :            :   // Create an iterator that reads over the compaction inputs for "*c".
#     248                 :            :   // The caller should delete the iterator when no longer needed.
#     249                 :            :   Iterator* MakeInputIterator(Compaction* c);
#     250                 :            : 
#     251                 :            :   // Returns true iff some level needs a compaction.
#     252                 :       2326 :   bool NeedsCompaction() const {
#     253                 :       2326 :     Version* v = current_;
#     254 [ +  + ][ +  + ]:       2326 :     return (v->compaction_score_ >= 1) || (v->file_to_compact_ != nullptr);
#     255                 :       2326 :   }
#     256                 :            : 
#     257                 :            :   // Add all files listed in any live version to *live.
#     258                 :            :   // May also mutate some internal state.
#     259                 :            :   void AddLiveFiles(std::set<uint64_t>* live);
#     260                 :            : 
#     261                 :            :   // Return the approximate offset in the database of the data for
#     262                 :            :   // "key" as of version "v".
#     263                 :            :   uint64_t ApproximateOffsetOf(Version* v, const InternalKey& key);
#     264                 :            : 
#     265                 :            :   // Return a human-readable short (single-line) summary of the number
#     266                 :            :   // of files per level.  Uses *scratch as backing store.
#     267                 :            :   struct LevelSummaryStorage {
#     268                 :            :     char buffer[100];
#     269                 :            :   };
#     270                 :            :   const char* LevelSummary(LevelSummaryStorage* scratch) const;
#     271                 :            : 
#     272                 :            :  private:
#     273                 :            :   class Builder;
#     274                 :            : 
#     275                 :            :   friend class Compaction;
#     276                 :            :   friend class Version;
#     277                 :            : 
#     278                 :            :   bool ReuseManifest(const std::string& dscname, const std::string& dscbase);
#     279                 :            : 
#     280                 :            :   void Finalize(Version* v);
#     281                 :            : 
#     282                 :            :   void GetRange(const std::vector<FileMetaData*>& inputs, InternalKey* smallest,
#     283                 :            :                 InternalKey* largest);
#     284                 :            : 
#     285                 :            :   void GetRange2(const std::vector<FileMetaData*>& inputs1,
#     286                 :            :                  const std::vector<FileMetaData*>& inputs2,
#     287                 :            :                  InternalKey* smallest, InternalKey* largest);
#     288                 :            : 
#     289                 :            :   void SetupOtherInputs(Compaction* c);
#     290                 :            : 
#     291                 :            :   // Save current contents to *log
#     292                 :            :   Status WriteSnapshot(log::Writer* log);
#     293                 :            : 
#     294                 :            :   void AppendVersion(Version* v);
#     295                 :            : 
#     296                 :            :   Env* const env_;
#     297                 :            :   const std::string dbname_;
#     298                 :            :   const Options* const options_;
#     299                 :            :   TableCache* const table_cache_;
#     300                 :            :   const InternalKeyComparator icmp_;
#     301                 :            :   uint64_t next_file_number_;
#     302                 :            :   uint64_t manifest_file_number_;
#     303                 :            :   uint64_t last_sequence_;
#     304                 :            :   uint64_t log_number_;
#     305                 :            :   uint64_t prev_log_number_;  // 0 or backing store for memtable being compacted
#     306                 :            : 
#     307                 :            :   // Opened lazily
#     308                 :            :   WritableFile* descriptor_file_;
#     309                 :            :   log::Writer* descriptor_log_;
#     310                 :            :   Version dummy_versions_;  // Head of circular doubly-linked list of versions.
#     311                 :            :   Version* current_;        // == dummy_versions_.prev_
#     312                 :            : 
#     313                 :            :   // Per-level key at which the next compaction at that level should start.
#     314                 :            :   // Either an empty string, or a valid InternalKey.
#     315                 :            :   std::string compact_pointer_[config::kNumLevels];
#     316                 :            : };
#     317                 :            : 
#     318                 :            : // A Compaction encapsulates information about a compaction.
#     319                 :            : class Compaction {
#     320                 :            :  public:
#     321                 :            :   ~Compaction();
#     322                 :            : 
#     323                 :            :   // Return the level that is being compacted.  Inputs from "level"
#     324                 :            :   // and "level+1" will be merged to produce a set of "level+1" files.
#     325                 :       1221 :   int level() const { return level_; }
#     326                 :            : 
#     327                 :            :   // Return the object that holds the edits to the descriptor done
#     328                 :            :   // by this compaction.
#     329                 :        324 :   VersionEdit* edit() { return &edit_; }
#     330                 :            : 
#     331                 :            :   // "which" must be either 0 or 1
#     332                 :       1178 :   int num_input_files(int which) const { return inputs_[which].size(); }
#     333                 :            : 
#     334                 :            :   // Return the ith input file at "level()+which" ("which" must be 0 or 1).
#     335                 :        421 :   FileMetaData* input(int which, int i) const { return inputs_[which][i]; }
#     336                 :            : 
#     337                 :            :   // Maximum size of files to build during this compaction.
#     338                 :      32179 :   uint64_t MaxOutputFileSize() const { return max_output_file_size_; }
#     339                 :            : 
#     340                 :            :   // Is this a trivial compaction that can be implemented by just
#     341                 :            :   // moving a single input file to the next level (no merging or splitting)
#     342                 :            :   bool IsTrivialMove() const;
#     343                 :            : 
#     344                 :            :   // Add all inputs to this compaction as delete operations to *edit.
#     345                 :            :   void AddInputDeletions(VersionEdit* edit);
#     346                 :            : 
#     347                 :            :   // Returns true if the information we have available guarantees that
#     348                 :            :   // the compaction is producing data in "level+1" for which no data exists
#     349                 :            :   // in levels greater than "level+1".
#     350                 :            :   bool IsBaseLevelForKey(const Slice& user_key);
#     351                 :            : 
#     352                 :            :   // Returns true iff we should stop building the current output
#     353                 :            :   // before processing "internal_key".
#     354                 :            :   bool ShouldStopBefore(const Slice& internal_key);
#     355                 :            : 
#     356                 :            :   // Release the input version for the compaction, once the compaction
#     357                 :            :   // is successful.
#     358                 :            :   void ReleaseInputs();
#     359                 :            : 
#     360                 :            :  private:
#     361                 :            :   friend class Version;
#     362                 :            :   friend class VersionSet;
#     363                 :            : 
#     364                 :            :   Compaction(const Options* options, int level);
#     365                 :            : 
#     366                 :            :   int level_;
#     367                 :            :   uint64_t max_output_file_size_;
#     368                 :            :   Version* input_version_;
#     369                 :            :   VersionEdit edit_;
#     370                 :            : 
#     371                 :            :   // Each compaction reads inputs from "level_" and "level_+1"
#     372                 :            :   std::vector<FileMetaData*> inputs_[2];  // The two sets of inputs
#     373                 :            : 
#     374                 :            :   // State used to check for number of overlapping grandparent files
#     375                 :            :   // (parent == level_ + 1, grandparent == level_ + 2)
#     376                 :            :   std::vector<FileMetaData*> grandparents_;
#     377                 :            :   size_t grandparent_index_;  // Index in grandparent_starts_
#     378                 :            :   bool seen_key_;             // Some output key has been seen
#     379                 :            :   int64_t overlapped_bytes_;  // Bytes of overlap between current output
#     380                 :            :                               // and grandparent files
#     381                 :            : 
#     382                 :            :   // State for implementing IsBaseLevelForKey
#     383                 :            : 
#     384                 :            :   // level_ptrs_ holds indices into input_version_->levels_: our state
#     385                 :            :   // is that we are positioned at one of the file ranges for each
#     386                 :            :   // higher level than the ones involved in this compaction (i.e. for
#     387                 :            :   // all L >= level_ + 2).
#     388                 :            :   size_t level_ptrs_[config::kNumLevels];
#     389                 :            : };
#     390                 :            : 
#     391                 :            : }  // namespace leveldb
#     392                 :            : 
#     393                 :            : #endif  // STORAGE_LEVELDB_DB_VERSION_SET_H_

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a