version_set.h 16.2 KB
Newer Older
J
jorlow@chromium.org 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
//
// The representation of a DBImpl consists of a set of Versions.  The
// newest version is called "current".  Older versions may be kept
// around to provide a consistent view to live iterators.
//
// Each Version keeps track of a set of Table files per level.  The
// entire set of versions is maintained in a VersionSet.
//
// Version,VersionSet are thread-compatible, but require external
// synchronization on all accesses.

#ifndef STORAGE_LEVELDB_DB_VERSION_SET_H_
#define STORAGE_LEVELDB_DB_VERSION_SET_H_

#include <map>
#include <set>
#include <vector>
21
#include <deque>
J
jorlow@chromium.org 已提交
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
#include "db/dbformat.h"
#include "db/version_edit.h"
#include "port/port.h"

namespace leveldb {

namespace log { class Writer; }

class Compaction;
class Iterator;
class MemTable;
class TableBuilder;
class TableCache;
class Version;
class VersionSet;
class WritableFile;

39 40 41 42 43 44 45
// Return the smallest index i such that files[i]->largest >= key.
// Return files.size() if there is no such file.
// REQUIRES: "files" contains a sorted list of non-overlapping files.
extern int FindFile(const InternalKeyComparator& icmp,
                    const std::vector<FileMetaData*>& files,
                    const Slice& key);

46
// Returns true iff some file in "files" overlaps the user key range
G
Gabor Cselle 已提交
47 48 49 50 51
// [*smallest,*largest].
// smallest==NULL represents a key smaller than all keys in the DB.
// largest==NULL represents a key largest than all keys in the DB.
// REQUIRES: If disjoint_sorted_files, files[] contains disjoint ranges
//           in sorted order.
52 53
extern bool SomeFileOverlapsRange(
    const InternalKeyComparator& icmp,
G
Gabor Cselle 已提交
54
    bool disjoint_sorted_files,
55
    const std::vector<FileMetaData*>& files,
G
Gabor Cselle 已提交
56 57
    const Slice* smallest_user_key,
    const Slice* largest_user_key);
58

J
jorlow@chromium.org 已提交
59 60 61 62 63 64 65
class Version {
 public:
  // Append to *iters a sequence of iterators that will
  // yield the contents of this Version when merged together.
  // REQUIRES: This version has been saved (see VersionSet::SaveTo)
  void AddIterators(const ReadOptions&, std::vector<Iterator*>* iters);

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
  // Lookup the value for key.  If found, store it in *val and
  // return OK.  Else return a non-OK status.  Fills *stats.
  // REQUIRES: lock is not held
  struct GetStats {
    FileMetaData* seek_file;
    int seek_file_level;
  };
  Status Get(const ReadOptions&, const LookupKey& key, std::string* val,
             GetStats* stats);

  // Adds "stats" into the current state.  Returns true if a new
  // compaction may need to be triggered, false otherwise.
  // REQUIRES: lock is held
  bool UpdateStats(const GetStats& stats);

J
jorlow@chromium.org 已提交
81 82 83 84 85
  // Reference count management (so Versions do not disappear out from
  // under live iterators)
  void Ref();
  void Unref();

G
Gabor Cselle 已提交
86 87 88 89 90 91
  void GetOverlappingInputs(
      int level,
      const InternalKey* begin,         // NULL means before all keys
      const InternalKey* end,           // NULL means after all keys
      std::vector<FileMetaData*>* inputs);

92
  // Returns true iff some file in the specified level overlaps
G
Gabor Cselle 已提交
93 94 95
  // some part of [*smallest_user_key,*largest_user_key].
  // smallest_user_key==NULL represents a key smaller than all keys in the DB.
  // largest_user_key==NULL represents a key largest than all keys in the DB.
96
  bool OverlapInLevel(int level,
G
Gabor Cselle 已提交
97 98 99 100 101 102 103
                      const Slice* smallest_user_key,
                      const Slice* largest_user_key);

  // Return the level at which we should place a new memtable compaction
  // result that covers the range [smallest_user_key,largest_user_key].
  int PickLevelForMemTableOutput(const Slice& smallest_user_key,
                                 const Slice& largest_user_key);
104 105 106

  int NumFiles(int level) const { return files_[level].size(); }

J
jorlow@chromium.org 已提交
107 108 109
  // Return a human readable string that describes this version's contents.
  std::string DebugString() const;

110 111 112 113 114
  // Returns the version nuber of this version
  uint64_t GetVersionNumber() {
    return version_number_;
  }

J
jorlow@chromium.org 已提交
115 116 117 118 119 120 121 122 123
 private:
  friend class Compaction;
  friend class VersionSet;

  class LevelFileNumIterator;
  Iterator* NewConcatenatingIterator(const ReadOptions&, int level) const;

  VersionSet* vset_;            // VersionSet to which this Version belongs
  Version* next_;               // Next version in linked list
124
  Version* prev_;               // Previous version in linked list
J
jorlow@chromium.org 已提交
125 126 127
  int refs_;                    // Number of live refs to this version

  // List of files per level
128
  std::vector<FileMetaData*>* files_;
J
jorlow@chromium.org 已提交
129

130 131 132 133
  // Next file to compact based on seek stats.
  FileMetaData* file_to_compact_;
  int file_to_compact_level_;

J
jorlow@chromium.org 已提交
134 135 136
  // Level that should be compacted next and its compaction score.
  // Score < 1 means compaction is not strictly needed.  These fields
  // are initialized by Finalize().
137 138 139 140
  // The most critical level to be compacted is listed first
  // These are used to pick the best compaction level
  std::vector<double> compaction_score_;
  std::vector<int> compaction_level_;
J
jorlow@chromium.org 已提交
141

142 143 144
  // The offset in the manifest file where this version is stored.
  uint64_t offset_manifest_file_;

145 146 147 148 149
  // A version number that uniquely represents this version. This is
  // used for debugging and logging purposes only.
  uint64_t version_number_;

  explicit Version(VersionSet* vset, uint64_t version_number = 0);
J
jorlow@chromium.org 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167

  ~Version();

  // No copying allowed
  Version(const Version&);
  void operator=(const Version&);
};

class VersionSet {
 public:
  VersionSet(const std::string& dbname,
             const Options* options,
             TableCache* table_cache,
             const InternalKeyComparator*);
  ~VersionSet();

  // Apply *edit to the current version to form a new descriptor that
  // is both saved to persistent state and installed as the new
168 169 170 171
  // current version.  Will release *mu while actually writing to the file.
  // REQUIRES: *mu is held on entry.
  // REQUIRES: no other thread concurrently calls LogAndApply()
  Status LogAndApply(VersionEdit* edit, port::Mutex* mu);
J
jorlow@chromium.org 已提交
172 173

  // Recover the last saved descriptor from persistent storage.
174
  Status Recover();
J
jorlow@chromium.org 已提交
175 176 177 178 179 180 181 182 183 184

  // Return the current version.
  Version* current() const { return current_; }

  // Return the current manifest file number
  uint64_t ManifestFileNumber() const { return manifest_file_number_; }

  // Allocate and return a new file number
  uint64_t NewFileNumber() { return next_file_number_++; }

H
heyongqiang 已提交
185 186 187 188 189 190 191 192 193
  // Arrange to reuse "file_number" unless a newer file number has
  // already been allocated.
  // REQUIRES: "file_number" was returned by a call to NewFileNumber().
  void ReuseFileNumber(uint64_t file_number) {
    if (next_file_number_ == file_number + 1) {
      next_file_number_ = file_number;
    }
  }

J
jorlow@chromium.org 已提交
194 195 196
  // Return the number of Table files at the specified level.
  int NumLevelFiles(int level) const;

197 198 199 200 201 202 203 204 205 206 207 208
  // Return the combined file size of all files at the specified level.
  int64_t NumLevelBytes(int level) const;

  // Return the last sequence number.
  uint64_t LastSequence() const { return last_sequence_; }

  // Set the last sequence number to s.
  void SetLastSequence(uint64_t s) {
    assert(s >= last_sequence_);
    last_sequence_ = s;
  }

209 210 211
  // Mark the specified file number as used.
  void MarkFileNumberUsed(uint64_t number);

212 213 214 215 216 217 218
  // Return the current log file number.
  uint64_t LogNumber() const { return log_number_; }

  // Return the log file number for the log file that is currently
  // being compacted, or zero if there is no such log file.
  uint64_t PrevLogNumber() const { return prev_log_number_; }

219 220
  int NumberLevels() const { return options_->num_levels; }

J
jorlow@chromium.org 已提交
221 222 223 224 225 226 227 228 229 230 231 232
  // Pick level and inputs for a new compaction.
  // Returns NULL if there is no compaction to be done.
  // Otherwise returns a pointer to a heap-allocated object that
  // describes the compaction.  Caller should delete the result.
  Compaction* PickCompaction();

  // Return a compaction object for compacting the range [begin,end] in
  // the specified level.  Returns NULL if there is nothing in that
  // level that overlaps the specified range.  Caller should delete
  // the result.
  Compaction* CompactRange(
      int level,
G
Gabor Cselle 已提交
233 234
      const InternalKey* begin,
      const InternalKey* end);
J
jorlow@chromium.org 已提交
235

236 237
  // Return the maximum overlapping data (in bytes) at next level for any
  // file at a level >= 1.
J
jorlow@chromium.org 已提交
238
  int64_t MaxNextLevelOverlappingBytes();
239

J
jorlow@chromium.org 已提交
240 241 242 243
  // Create an iterator that reads over the compaction inputs for "*c".
  // The caller should delete the iterator when no longer needed.
  Iterator* MakeInputIterator(Compaction* c);

244 245 246 247 248 249 250 251 252 253
  // Returns true iff some level needs a compaction because it has
  // exceeded its target size.
  bool NeedsSizeCompaction() const {
    for (int i = 0; i < NumberLevels()-1; i++) {
      if (current_->compaction_score_[i] >= 1) {
        return true;
      }
    }
    return false;
  }
J
jorlow@chromium.org 已提交
254
  // Returns true iff some level needs a compaction.
255
  bool NeedsCompaction() const {
256 257
    return ((current_->file_to_compact_ != NULL) ||
            NeedsSizeCompaction());
258
  }
J
jorlow@chromium.org 已提交
259 260 261 262 263

  // Add all files listed in any live version to *live.
  // May also mutate some internal state.
  void AddLiveFiles(std::set<uint64_t>* live);

264 265 266
  // Add all files listed in the current version to *live.
  void AddLiveFilesCurrentVersion(std::set<uint64_t>* live);

J
jorlow@chromium.org 已提交
267 268 269 270
  // Return the approximate offset in the database of the data for
  // "key" as of version "v".
  uint64_t ApproximateOffsetOf(Version* v, const InternalKey& key);

271 272 273 274 275 276 277
  // Return a human-readable short (single-line) summary of the number
  // of files per level.  Uses *scratch as backing store.
  struct LevelSummaryStorage {
    char buffer[100];
  };
  const char* LevelSummary(LevelSummaryStorage* scratch) const;

278 279 280
  // printf contents (for debugging)
  Status DumpManifest(Options& options, std::string& manifestFileName);

281 282 283 284
  // Return a human-readable short (single-line) summary of the data size
  // of files per level.  Uses *scratch as backing store.
  const char* LevelDataSizeSummary(LevelSummaryStorage* scratch) const;

285 286 287
  // Return the size of the current manifest file
  const uint64_t ManifestFileSize() { return current_->offset_manifest_file_; }

288 289 290 291 292 293 294 295 296 297 298 299 300
  // For the specfied level, pick a compaction.
  // Returns NULL if there is no compaction to be done.
  Compaction* PickCompactionBySize(int level);

  // Free up the files that were participated in a compaction
  void ReleaseCompactionFiles(Compaction* c);

  // verify that the files that we started with for a compaction
  // still exist in the current version and in the same original level.
  // This ensures that a concurrent compaction did not erroneously
  // pick the same files to compact.
  bool VerifyCompactionFileConsistency(Compaction* c);

J
jorlow@chromium.org 已提交
301 302
 private:
  class Builder;
303
  struct ManifestWriter;
J
jorlow@chromium.org 已提交
304 305 306 307

  friend class Compaction;
  friend class Version;

308
  void Finalize(Version* v);
J
jorlow@chromium.org 已提交
309 310 311 312 313

  void GetRange(const std::vector<FileMetaData*>& inputs,
                InternalKey* smallest,
                InternalKey* largest);

314 315 316 317 318 319 320
  void GetRange2(const std::vector<FileMetaData*>& inputs1,
                 const std::vector<FileMetaData*>& inputs2,
                 InternalKey* smallest,
                 InternalKey* largest);

  void SetupOtherInputs(Compaction* c);

321 322 323
  // Save current contents to *log
  Status WriteSnapshot(log::Writer* log);

324 325
  void AppendVersion(Version* v);

326 327 328 329
  double MaxBytesForLevel(int level);

  uint64_t MaxFileSizeForLevel(int level);

330
  int64_t ExpandedCompactionByteSizeLimit(int level);
331

332
  int64_t MaxGrandParentOverlapBytes(int level);
333

J
jorlow@chromium.org 已提交
334 335 336 337 338 339 340
  Env* const env_;
  const std::string dbname_;
  const Options* const options_;
  TableCache* const table_cache_;
  const InternalKeyComparator icmp_;
  uint64_t next_file_number_;
  uint64_t manifest_file_number_;
341 342 343
  uint64_t last_sequence_;
  uint64_t log_number_;
  uint64_t prev_log_number_;  // 0 or backing store for memtable being compacted
J
jorlow@chromium.org 已提交
344 345 346 347

  // Opened lazily
  WritableFile* descriptor_file_;
  log::Writer* descriptor_log_;
348 349
  Version dummy_versions_;  // Head of circular doubly-linked list of versions.
  Version* current_;        // == dummy_versions_.prev_
J
jorlow@chromium.org 已提交
350 351 352

  // Per-level key at which the next compaction at that level should start.
  // Either an empty string, or a valid InternalKey.
353 354 355 356 357 358 359
  std::string* compact_pointer_;

  // Per-level target file size.
  uint64_t* max_file_size_;

  // Per-level max bytes
  uint64_t* level_max_bytes_;
J
jorlow@chromium.org 已提交
360

361 362 363 364 365 366 367 368 369 370 371 372
  // record all the ongoing compactions for all levels
  std::vector<std::set<Compaction*> > compactions_in_progress_;

  // A lock that serialize writes to the manifest
  port::Mutex manifest_lock_;

  // generates a increasing version number for every new version
  uint64_t current_version_number_;

  // Queue of writers to the manifest file
  std::deque<ManifestWriter*> manifest_writers_;

J
jorlow@chromium.org 已提交
373 374 375
  // No copying allowed
  VersionSet(const VersionSet&);
  void operator=(const VersionSet&);
376 377 378 379 380 381 382 383 384 385 386 387 388

  // Return the total amount of data that is undergoing
  // compactions at this level
  uint64_t SizeBeingCompacted(int level);

  // Returns true if any one of the parent files are being compacted
  bool ParentFilesInCompaction(FileMetaData* f, int level);

  // Returns true if any one of the specified files are being compacted
  bool FilesInCompaction(std::vector<FileMetaData*>& files);

  void LogAndApplyHelper(Builder*b, Version* v,
                           VersionEdit* edit, port::Mutex* mu);
J
jorlow@chromium.org 已提交
389 390 391 392 393 394 395 396 397 398 399 400 401
};

// A Compaction encapsulates information about a compaction.
class Compaction {
 public:
  ~Compaction();

  // Return the level that is being compacted.  Inputs from "level"
  // and "level+1" will be merged to produce a set of "level+1" files.
  int level() const { return level_; }

  // Return the object that holds the edits to the descriptor done
  // by this compaction.
402
  VersionEdit* edit() { return edit_; }
J
jorlow@chromium.org 已提交
403 404 405 406 407 408 409 410 411 412

  // "which" must be either 0 or 1
  int num_input_files(int which) const { return inputs_[which].size(); }

  // Return the ith input file at "level()+which" ("which" must be 0 or 1).
  FileMetaData* input(int which, int i) const { return inputs_[which][i]; }

  // Maximum size of files to build during this compaction.
  uint64_t MaxOutputFileSize() const { return max_output_file_size_; }

413 414 415 416
  // Is this a trivial compaction that can be implemented by just
  // moving a single input file to the next level (no merging or splitting)
  bool IsTrivialMove() const;

J
jorlow@chromium.org 已提交
417 418 419 420 421 422 423 424
  // Add all inputs to this compaction as delete operations to *edit.
  void AddInputDeletions(VersionEdit* edit);

  // Returns true if the information we have available guarantees that
  // the compaction is producing data in "level+1" for which no data exists
  // in levels greater than "level+1".
  bool IsBaseLevelForKey(const Slice& user_key);

425
  // Returns true iff we should stop building the current output
426 427
  // before processing "internal_key".
  bool ShouldStopBefore(const Slice& internal_key);
428

J
jorlow@chromium.org 已提交
429 430 431 432
  // Release the input version for the compaction, once the compaction
  // is successful.
  void ReleaseInputs();

H
heyongqiang 已提交
433 434
  void Summary(char* output, int len);

J
jorlow@chromium.org 已提交
435 436 437 438
 private:
  friend class Version;
  friend class VersionSet;

439
  explicit Compaction(int level, uint64_t target_file_size,
440 441
    uint64_t max_grandparent_overlap_bytes, int number_levels,
    bool seek_compaction = false);
J
jorlow@chromium.org 已提交
442 443 444

  int level_;
  uint64_t max_output_file_size_;
445
  int64_t maxGrandParentOverlapBytes_;
J
jorlow@chromium.org 已提交
446
  Version* input_version_;
447 448
  VersionEdit* edit_;
  int number_levels_;
J
jorlow@chromium.org 已提交
449

450 451
  bool seek_compaction_;

J
jorlow@chromium.org 已提交
452 453 454
  // Each compaction reads inputs from "level_" and "level_+1"
  std::vector<FileMetaData*> inputs_[2];      // The two sets of inputs

455 456 457
  // State used to check for number of of overlapping grandparent files
  // (parent == level_ + 1, grandparent == level_ + 2)
  std::vector<FileMetaData*> grandparents_;
D
dgrogan@chromium.org 已提交
458
  size_t grandparent_index_;  // Index in grandparent_starts_
J
jorlow@chromium.org 已提交
459 460 461
  bool seen_key_;             // Some output key has been seen
  int64_t overlapped_bytes_;  // Bytes of overlap between current output
                              // and grandparent files
462

J
jorlow@chromium.org 已提交
463 464 465 466 467 468
  // State for implementing IsBaseLevelForKey

  // level_ptrs_ holds indices into input_version_->levels_: our state
  // is that we are positioned at one of the file ranges for each
  // higher level than the ones involved in this compaction (i.e. for
  // all L >= level_ + 2).
469
  size_t* level_ptrs_;
470 471 472

  // mark (or clear) all files that are being compacted
  void MarkFilesBeingCompacted(bool);
J
jorlow@chromium.org 已提交
473 474
};

H
Hans Wennborg 已提交
475
}  // namespace leveldb
J
jorlow@chromium.org 已提交
476 477

#endif  // STORAGE_LEVELDB_DB_VERSION_SET_H_