Coverage Report

Created: 2026-07-14 18:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/bitcoin/src/leveldb/db/version_set.cc
Line
Count
Source
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
32
static size_t TargetFileSize(const Options* options) {
26
32
  return options->max_file_size;
27
32
}
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
32
static int64_t MaxGrandParentOverlapBytes(const Options* options) {
32
32
  return 10 * TargetFileSize(options);
33
32
}
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
0
}
41
42
890
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
890
  double result = 10. * 1048576.0;
48
2.67k
  while (level > 1) {
  Branch (48:10): [True: 1.78k, False: 890]
49
1.78k
    result *= 10;
50
1.78k
    level--;
51
1.78k
  }
52
890
  return result;
53
890
}
54
55
0
static uint64_t MaxFileSizeForLevel(const Options* options, int level) {
56
  // We could vary per level to reduce number of files?
57
0
  return TargetFileSize(options);
58
0
}
59
60
922
static int64_t TotalFileSize(const std::vector<FileMetaData*>& files) {
61
922
  int64_t sum = 0;
62
938
  for (size_t i = 0; i < files.size(); i++) {
  Branch (62:22): [True: 16, False: 922]
63
16
    sum += files[i]->file_size;
64
16
  }
65
922
  return sum;
66
922
}
67
68
900k
Version::~Version() {
69
900k
  assert(refs_ == 0);
  Branch (69:3): [True: 900k, False: 0]
70
71
  // Remove from linked list
72
900k
  prev_->next_ = next_;
73
900k
  next_->prev_ = prev_;
74
75
  // Drop references to files
76
7.20M
  for (int level = 0; level < config::kNumLevels; level++) {
  Branch (76:23): [True: 6.30M, False: 900k]
77
6.30M
    for (size_t i = 0; i < files_[level].size(); i++) {
  Branch (77:24): [True: 16, False: 6.30M]
78
16
      FileMetaData* f = files_[level][i];
79
16
      assert(f->refs > 0);
  Branch (79:7): [True: 16, False: 0]
80
16
      f->refs--;
81
16
      if (f->refs <= 0) {
  Branch (81:11): [True: 16, False: 0]
82
16
        delete f;
83
16
      }
84
16
    }
85
6.30M
  }
86
900k
}
87
88
int FindFile(const InternalKeyComparator& icmp,
89
438
             const std::vector<FileMetaData*>& files, const Slice& key) {
90
438
  uint32_t left = 0;
91
438
  uint32_t right = files.size();
92
844
  while (left < right) {
  Branch (92:10): [True: 406, False: 438]
93
406
    uint32_t mid = (left + right) / 2;
94
406
    const FileMetaData* f = files[mid];
95
406
    if (icmp.InternalKeyComparator::Compare(f->largest.Encode(), key) < 0) {
  Branch (95:9): [True: 0, False: 406]
96
      // Key at "mid.largest" is < "target".  Therefore all
97
      // files at or before "mid" are uninteresting.
98
0
      left = mid + 1;
99
406
    } else {
100
      // Key at "mid.largest" is >= "target".  Therefore all files
101
      // after "mid" are uninteresting.
102
406
      right = mid;
103
406
    }
104
406
  }
105
438
  return right;
106
438
}
107
108
static bool AfterFile(const Comparator* ucmp, const Slice* user_key,
109
0
                      const FileMetaData* f) {
110
  // null user_key occurs before all keys and is therefore never after *f
111
0
  return (user_key != nullptr &&
  Branch (111:11): [True: 0, False: 0]
112
0
          ucmp->Compare(*user_key, f->largest.user_key()) > 0);
  Branch (112:11): [True: 0, False: 0]
113
0
}
114
115
static bool BeforeFile(const Comparator* ucmp, const Slice* user_key,
116
0
                       const FileMetaData* f) {
117
  // null user_key occurs after all keys and is therefore never before *f
118
0
  return (user_key != nullptr &&
  Branch (118:11): [True: 0, False: 0]
119
0
          ucmp->Compare(*user_key, f->smallest.user_key()) < 0);
  Branch (119:11): [True: 0, False: 0]
120
0
}
121
122
bool SomeFileOverlapsRange(const InternalKeyComparator& icmp,
123
                           bool disjoint_sorted_files,
124
                           const std::vector<FileMetaData*>& files,
125
                           const Slice* smallest_user_key,
126
144
                           const Slice* largest_user_key) {
127
144
  const Comparator* ucmp = icmp.user_comparator();
128
144
  if (!disjoint_sorted_files) {
  Branch (128:7): [True: 16, False: 128]
129
    // Need to check against all files
130
16
    for (size_t i = 0; i < files.size(); i++) {
  Branch (130:24): [True: 0, False: 16]
131
0
      const FileMetaData* f = files[i];
132
0
      if (AfterFile(ucmp, smallest_user_key, f) ||
  Branch (132:11): [True: 0, False: 0]
133
0
          BeforeFile(ucmp, largest_user_key, f)) {
  Branch (133:11): [True: 0, False: 0]
134
        // No overlap
135
0
      } else {
136
0
        return true;  // Overlap
137
0
      }
138
0
    }
139
16
    return false;
140
16
  }
141
142
  // Binary search over file list
143
128
  uint32_t index = 0;
144
128
  if (smallest_user_key != nullptr) {
  Branch (144:7): [True: 32, False: 96]
145
    // Find the earliest possible internal key for smallest_user_key
146
32
    InternalKey small_key(*smallest_user_key, kMaxSequenceNumber,
147
32
                          kValueTypeForSeek);
148
32
    index = FindFile(icmp, files, small_key.Encode());
149
32
  }
150
151
128
  if (index >= files.size()) {
  Branch (151:7): [True: 128, False: 0]
152
    // beginning of range is after all files, so no overlap.
153
128
    return false;
154
128
  }
155
156
0
  return !BeforeFile(ucmp, largest_user_key, files[index]);
157
128
}
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
  LevelFileNumIterator(const InternalKeyComparator& icmp,
167
                       const std::vector<FileMetaData*>* flist)
168
0
      : icmp_(icmp), flist_(flist), index_(flist->size()) {  // Marks as invalid
169
0
  }
170
0
  bool Valid() const override { return index_ < flist_->size(); }
171
0
  void Seek(const Slice& target) override {
172
0
    index_ = FindFile(icmp_, *flist_, target);
173
0
  }
174
0
  void SeekToFirst() override { index_ = 0; }
175
0
  void SeekToLast() override {
176
0
    index_ = flist_->empty() ? 0 : flist_->size() - 1;
  Branch (176:14): [True: 0, False: 0]
177
0
  }
178
0
  void Next() override {
179
0
    assert(Valid());
  Branch (179:5): [True: 0, False: 0]
180
0
    index_++;
181
0
  }
182
0
  void Prev() override {
183
0
    assert(Valid());
  Branch (183:5): [True: 0, False: 0]
184
0
    if (index_ == 0) {
  Branch (184:9): [True: 0, False: 0]
185
0
      index_ = flist_->size();  // Marks as invalid
186
0
    } else {
187
0
      index_--;
188
0
    }
189
0
  }
190
0
  Slice key() const override {
191
0
    assert(Valid());
  Branch (191:5): [True: 0, False: 0]
192
0
    return (*flist_)[index_]->largest.Encode();
193
0
  }
194
0
  Slice value() const override {
195
0
    assert(Valid());
  Branch (195:5): [True: 0, False: 0]
196
0
    EncodeFixed64(value_buf_, (*flist_)[index_]->number);
197
0
    EncodeFixed64(value_buf_ + 8, (*flist_)[index_]->file_size);
198
0
    return Slice(value_buf_, sizeof(value_buf_));
199
0
  }
200
0
  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
static Iterator* GetFileIterator(void* arg, const ReadOptions& options,
212
0
                                 const Slice& file_value) {
213
0
  TableCache* cache = reinterpret_cast<TableCache*>(arg);
214
0
  if (file_value.size() != 16) {
  Branch (214:7): [True: 0, False: 0]
215
0
    return NewErrorIterator(
216
0
        Status::Corruption("FileReader invoked with unexpected value"));
217
0
  } else {
218
0
    return cache->NewIterator(options, DecodeFixed64(file_value.data()),
219
0
                              DecodeFixed64(file_value.data() + 8));
220
0
  }
221
0
}
222
223
Iterator* Version::NewConcatenatingIterator(const ReadOptions& options,
224
0
                                            int level) const {
225
0
  return NewTwoLevelIterator(
226
0
      new LevelFileNumIterator(vset_->icmp_, &files_[level]), &GetFileIterator,
227
0
      vset_->table_cache_, options);
228
0
}
229
230
void Version::AddIterators(const ReadOptions& options,
231
24.8k
                           std::vector<Iterator*>* iters) {
232
  // Merge all level zero files together since they may overlap
233
24.8k
  for (size_t i = 0; i < files_[0].size(); i++) {
  Branch (233:22): [True: 0, False: 24.8k]
234
0
    iters->push_back(vset_->table_cache_->NewIterator(
235
0
        options, files_[0][i]->number, files_[0][i]->file_size));
236
0
  }
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
173k
  for (int level = 1; level < config::kNumLevels; level++) {
  Branch (241:23): [True: 149k, False: 24.8k]
242
149k
    if (!files_[level].empty()) {
  Branch (242:9): [True: 0, False: 149k]
243
0
      iters->push_back(NewConcatenatingIterator(options, level));
244
0
    }
245
149k
  }
246
24.8k
}
247
248
// Callback from TableCache::Get()
249
namespace {
250
enum SaverState {
251
  kNotFound,
252
  kFound,
253
  kDeleted,
254
  kCorrupt,
255
};
256
struct Saver {
257
  SaverState state;
258
  const Comparator* ucmp;
259
  Slice user_key;
260
  std::string* value;
261
};
262
}  // namespace
263
20
static void SaveValue(void* arg, const Slice& ikey, const Slice& v) {
264
20
  Saver* s = reinterpret_cast<Saver*>(arg);
265
20
  ParsedInternalKey parsed_key;
266
20
  if (!ParseInternalKey(ikey, &parsed_key)) {
  Branch (266:7): [True: 0, False: 20]
267
0
    s->state = kCorrupt;
268
20
  } else {
269
20
    if (s->ucmp->Compare(parsed_key.user_key, s->user_key) == 0) {
  Branch (269:9): [True: 16, False: 4]
270
16
      s->state = (parsed_key.type == kTypeValue) ? kFound : kDeleted;
  Branch (270:18): [True: 16, False: 0]
271
16
      if (s->state == kFound) {
  Branch (271:11): [True: 16, False: 0]
272
16
        s->value->assign(v.data(), v.size());
273
16
      }
274
16
    }
275
20
  }
276
20
}
277
278
0
static bool NewestFirst(FileMetaData* a, FileMetaData* b) {
279
0
  return a->number > b->number;
280
0
}
281
282
void Version::ForEachOverlapping(Slice user_key, Slice internal_key, void* arg,
283
2.34M
                                 bool (*func)(void*, int, FileMetaData*)) {
284
2.34M
  const Comparator* ucmp = vset_->icmp_.user_comparator();
285
286
  // Search level-0 in order from newest to oldest.
287
2.34M
  std::vector<FileMetaData*> tmp;
288
2.34M
  tmp.reserve(files_[0].size());
289
2.34M
  for (uint32_t i = 0; i < files_[0].size(); i++) {
  Branch (289:24): [True: 0, False: 2.34M]
290
0
    FileMetaData* f = files_[0][i];
291
0
    if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 &&
  Branch (291:9): [True: 0, False: 0]
  Branch (291:9): [True: 0, False: 0]
292
0
        ucmp->Compare(user_key, f->largest.user_key()) <= 0) {
  Branch (292:9): [True: 0, False: 0]
293
0
      tmp.push_back(f);
294
0
    }
295
0
  }
296
2.34M
  if (!tmp.empty()) {
  Branch (296:7): [True: 0, False: 2.34M]
297
0
    std::sort(tmp.begin(), tmp.end(), NewestFirst);
298
0
    for (uint32_t i = 0; i < tmp.size(); i++) {
  Branch (298:26): [True: 0, False: 0]
299
0
      if (!(*func)(arg, 0, tmp[i])) {
  Branch (299:11): [True: 0, False: 0]
300
0
        return;
301
0
      }
302
0
    }
303
0
  }
304
305
  // Search other levels.
306
16.4M
  for (int level = 1; level < config::kNumLevels; level++) {
  Branch (306:23): [True: 14.0M, False: 2.34M]
307
14.0M
    size_t num_files = files_[level].size();
308
14.0M
    if (num_files == 0) continue;
  Branch (308:9): [True: 14.0M, False: 406]
309
310
    // Binary search to find earliest index whose largest key >= internal_key.
311
406
    uint32_t index = FindFile(vset_->icmp_, files_[level], internal_key);
312
406
    if (index < num_files) {
  Branch (312:9): [True: 406, False: 0]
313
406
      FileMetaData* f = files_[level][index];
314
406
      if (ucmp->Compare(user_key, f->smallest.user_key()) < 0) {
  Branch (314:11): [True: 0, False: 406]
315
        // All of "f" is past any data for user_key
316
406
      } else {
317
406
        if (!(*func)(arg, level, f)) {
  Branch (317:13): [True: 16, False: 390]
318
16
          return;
319
16
        }
320
406
      }
321
406
    }
322
406
  }
323
2.34M
}
324
325
Status Version::Get(const ReadOptions& options, const LookupKey& k,
326
2.34M
                    std::string* value, GetStats* stats) {
327
2.34M
  stats->seek_file = nullptr;
328
2.34M
  stats->seek_file_level = -1;
329
330
2.34M
  struct State {
331
2.34M
    Saver saver;
332
2.34M
    GetStats* stats;
333
2.34M
    const ReadOptions* options;
334
2.34M
    Slice ikey;
335
2.34M
    FileMetaData* last_file_read;
336
2.34M
    int last_file_read_level;
337
338
2.34M
    VersionSet* vset;
339
2.34M
    Status s;
340
2.34M
    bool found;
341
342
2.34M
    static bool Match(void* arg, int level, FileMetaData* f) {
343
406
      State* state = reinterpret_cast<State*>(arg);
344
345
406
      if (state->stats->seek_file == nullptr &&
  Branch (345:11): [True: 406, False: 0]
346
406
          state->last_file_read != nullptr) {
  Branch (346:11): [True: 0, False: 406]
347
        // We have had more than one seek for this read.  Charge the 1st file.
348
0
        state->stats->seek_file = state->last_file_read;
349
0
        state->stats->seek_file_level = state->last_file_read_level;
350
0
      }
351
352
406
      state->last_file_read = f;
353
406
      state->last_file_read_level = level;
354
355
406
      state->s = state->vset->table_cache_->Get(*state->options, f->number,
356
406
                                                f->file_size, state->ikey,
357
406
                                                &state->saver, SaveValue);
358
406
      if (!state->s.ok()) {
  Branch (358:11): [True: 0, False: 406]
359
0
        state->found = true;
360
0
        return false;
361
0
      }
362
406
      switch (state->saver.state) {
  Branch (362:15): [True: 0, False: 406]
363
390
        case kNotFound:
  Branch (363:9): [True: 390, False: 16]
364
390
          return true;  // Keep searching in other files
365
16
        case kFound:
  Branch (365:9): [True: 16, False: 390]
366
16
          state->found = true;
367
16
          return false;
368
0
        case kDeleted:
  Branch (368:9): [True: 0, False: 406]
369
0
          return false;
370
0
        case kCorrupt:
  Branch (370:9): [True: 0, False: 406]
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
406
      }
376
377
      // Not reached. Added to avoid false compilation warnings of
378
      // "control reaches end of non-void function".
379
0
      return false;
380
406
    }
381
2.34M
  };
382
383
2.34M
  State state;
384
2.34M
  state.found = false;
385
2.34M
  state.stats = stats;
386
2.34M
  state.last_file_read = nullptr;
387
2.34M
  state.last_file_read_level = -1;
388
389
2.34M
  state.options = &options;
390
2.34M
  state.ikey = k.internal_key();
391
2.34M
  state.vset = vset_;
392
393
2.34M
  state.saver.state = kNotFound;
394
2.34M
  state.saver.ucmp = vset_->icmp_.user_comparator();
395
2.34M
  state.saver.user_key = k.user_key();
396
2.34M
  state.saver.value = value;
397
398
2.34M
  ForEachOverlapping(state.saver.user_key, state.ikey, &state, &State::Match);
399
400
2.34M
  return state.found ? state.s : Status::NotFound(Slice());
  Branch (400:10): [True: 16, False: 2.34M]
401
2.34M
}
402
403
2.34M
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
2.34M
  return false;
409
2.34M
}
410
411
553
bool Version::RecordReadSample(Slice internal_key) {
412
553
  ParsedInternalKey ikey;
413
553
  if (!ParseInternalKey(internal_key, &ikey)) {
  Branch (413:7): [True: 0, False: 553]
414
0
    return false;
415
0
  }
416
417
553
  struct State {
418
553
    GetStats stats;  // Holds first matching file
419
553
    int matches;
420
421
553
    static bool Match(void* arg, int level, FileMetaData* f) {
422
0
      State* state = reinterpret_cast<State*>(arg);
423
0
      state->matches++;
424
0
      if (state->matches == 1) {
  Branch (424:11): [True: 0, False: 0]
425
        // Remember first match.
426
0
        state->stats.seek_file = f;
427
0
        state->stats.seek_file_level = level;
428
0
      }
429
      // We can stop iterating once we have a second match.
430
0
      return state->matches < 2;
431
0
    }
432
553
  };
433
434
553
  State state;
435
553
  state.matches = 0;
436
553
  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
553
  if (state.matches >= 2) {
  Branch (442:7): [True: 0, False: 553]
443
    // 1MB cost is about 1 seek (see comment in Builder::Apply).
444
0
    return UpdateStats(state.stats);
445
0
  }
446
553
  return false;
447
553
}
448
449
2.54M
void Version::Ref() { ++refs_; }
450
451
2.99M
void Version::Unref() {
452
2.99M
  assert(this != &vset_->dummy_versions_);
  Branch (452:3): [True: 2.99M, False: 0]
453
2.99M
  assert(refs_ >= 1);
  Branch (453:3): [True: 2.99M, False: 0]
454
2.99M
  --refs_;
455
2.99M
  if (refs_ == 0) {
  Branch (455:7): [True: 450k, False: 2.54M]
456
450k
    delete this;
457
450k
  }
458
2.99M
}
459
460
bool Version::OverlapInLevel(int level, const Slice* smallest_user_key,
461
144
                             const Slice* largest_user_key) {
462
144
  return SomeFileOverlapsRange(vset_->icmp_, (level > 0), files_[level],
463
144
                               smallest_user_key, largest_user_key);
464
144
}
465
466
int Version::PickLevelForMemTableOutput(const Slice& smallest_user_key,
467
16
                                        const Slice& largest_user_key) {
468
16
  int level = 0;
469
16
  if (!OverlapInLevel(0, &smallest_user_key, &largest_user_key)) {
  Branch (469:7): [True: 16, False: 0]
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
16
    InternalKey start(smallest_user_key, kMaxSequenceNumber, kValueTypeForSeek);
473
16
    InternalKey limit(largest_user_key, 0, static_cast<ValueType>(0));
474
16
    std::vector<FileMetaData*> overlaps;
475
48
    while (level < config::kMaxMemCompactLevel) {
  Branch (475:12): [True: 32, False: 16]
476
32
      if (OverlapInLevel(level + 1, &smallest_user_key, &largest_user_key)) {
  Branch (476:11): [True: 0, False: 32]
477
0
        break;
478
0
      }
479
32
      if (level + 2 < config::kNumLevels) {
  Branch (479:11): [True: 32, False: 0]
480
        // Check that file does not overlap too many grandparent bytes.
481
32
        GetOverlappingInputs(level + 2, &start, &limit, &overlaps);
482
32
        const int64_t sum = TotalFileSize(overlaps);
483
32
        if (sum > MaxGrandParentOverlapBytes(vset_->options_)) {
  Branch (483:13): [True: 0, False: 32]
484
0
          break;
485
0
        }
486
32
      }
487
32
      level++;
488
32
    }
489
16
  }
490
16
  return level;
491
16
}
492
493
// Store in "*inputs" all files in "level" that overlap [begin,end]
494
void Version::GetOverlappingInputs(int level, const InternalKey* begin,
495
                                   const InternalKey* end,
496
48
                                   std::vector<FileMetaData*>* inputs) {
497
48
  assert(level >= 0);
  Branch (497:3): [True: 48, False: 0]
498
48
  assert(level < config::kNumLevels);
  Branch (498:3): [True: 48, False: 0]
499
48
  inputs->clear();
500
48
  Slice user_begin, user_end;
501
48
  if (begin != nullptr) {
  Branch (501:7): [True: 32, False: 16]
502
32
    user_begin = begin->user_key();
503
32
  }
504
48
  if (end != nullptr) {
  Branch (504:7): [True: 32, False: 16]
505
32
    user_end = end->user_key();
506
32
  }
507
48
  const Comparator* user_cmp = vset_->icmp_.user_comparator();
508
48
  for (size_t i = 0; i < files_[level].size();) {
  Branch (508:22): [True: 0, False: 48]
509
0
    FileMetaData* f = files_[level][i++];
510
0
    const Slice file_start = f->smallest.user_key();
511
0
    const Slice file_limit = f->largest.user_key();
512
0
    if (begin != nullptr && user_cmp->Compare(file_limit, user_begin) < 0) {
  Branch (512:9): [True: 0, False: 0]
  Branch (512:29): [True: 0, False: 0]
513
      // "f" is completely before specified range; skip it
514
0
    } else if (end != nullptr && user_cmp->Compare(file_start, user_end) > 0) {
  Branch (514:16): [True: 0, False: 0]
  Branch (514:34): [True: 0, False: 0]
515
      // "f" is completely after specified range; skip it
516
0
    } else {
517
0
      inputs->push_back(f);
518
0
      if (level == 0) {
  Branch (518:11): [True: 0, False: 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
0
        if (begin != nullptr && user_cmp->Compare(file_start, user_begin) < 0) {
  Branch (521:13): [True: 0, False: 0]
  Branch (521:33): [True: 0, False: 0]
522
0
          user_begin = file_start;
523
0
          inputs->clear();
524
0
          i = 0;
525
0
        } else if (end != nullptr &&
  Branch (525:20): [True: 0, False: 0]
526
0
                   user_cmp->Compare(file_limit, user_end) > 0) {
  Branch (526:20): [True: 0, False: 0]
527
0
          user_end = file_limit;
528
0
          inputs->clear();
529
0
          i = 0;
530
0
        }
531
0
      }
532
0
    }
533
0
  }
534
48
}
535
536
0
std::string Version::DebugString() const {
537
0
  std::string r;
538
0
  for (int level = 0; level < config::kNumLevels; level++) {
  Branch (538:23): [True: 0, False: 0]
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
0
    const std::vector<FileMetaData*>& files = files_[level];
547
0
    for (size_t i = 0; i < files.size(); i++) {
  Branch (547:24): [True: 0, False: 0]
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
0
    }
558
0
  }
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
0
    bool operator()(FileMetaData* f1, FileMetaData* f2) const {
572
0
      int r = internal_comparator->Compare(f1->smallest, f2->smallest);
573
0
      if (r != 0) {
  Branch (573:11): [True: 0, False: 0]
574
0
        return (r < 0);
575
0
      } else {
576
        // Break ties by file number
577
0
        return (f1->number < f2->number);
578
0
      }
579
0
    }
580
  };
581
582
  typedef std::set<FileMetaData*, BySmallestKey> FileSet;
583
  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
178
  Builder(VersionSet* vset, Version* base) : vset_(vset), base_(base) {
595
178
    base_->Ref();
596
178
    BySmallestKey cmp;
597
178
    cmp.internal_comparator = &vset_->icmp_;
598
1.42k
    for (int level = 0; level < config::kNumLevels; level++) {
  Branch (598:25): [True: 1.24k, False: 178]
599
1.24k
      levels_[level].added_files = new FileSet(cmp);
600
1.24k
    }
601
178
  }
602
603
178
  ~Builder() {
604
1.42k
    for (int level = 0; level < config::kNumLevels; level++) {
  Branch (604:25): [True: 1.24k, False: 178]
605
1.24k
      const FileSet* added = levels_[level].added_files;
606
1.24k
      std::vector<FileMetaData*> to_unref;
607
1.24k
      to_unref.reserve(added->size());
608
1.26k
      for (FileSet::const_iterator it = added->begin(); it != added->end();
  Branch (608:57): [True: 16, False: 1.24k]
609
1.24k
           ++it) {
610
16
        to_unref.push_back(*it);
611
16
      }
612
1.24k
      delete added;
613
1.26k
      for (uint32_t i = 0; i < to_unref.size(); i++) {
  Branch (613:28): [True: 16, False: 1.24k]
614
16
        FileMetaData* f = to_unref[i];
615
16
        f->refs--;
616
16
        if (f->refs <= 0) {
  Branch (616:13): [True: 0, False: 16]
617
0
          delete f;
618
0
        }
619
16
      }
620
1.24k
    }
621
178
    base_->Unref();
622
178
  }
623
624
  // Apply all of the edits in *edit to the current state.
625
178
  void Apply(VersionEdit* edit) {
626
    // Update compaction pointers
627
178
    for (size_t i = 0; i < edit->compact_pointers_.size(); i++) {
  Branch (627:24): [True: 0, False: 178]
628
0
      const int level = edit->compact_pointers_[i].first;
629
0
      vset_->compact_pointer_[level] =
630
0
          edit->compact_pointers_[i].second.Encode().ToString();
631
0
    }
632
633
    // Delete files
634
178
    for (const auto& deleted_file_set_kvp : edit->deleted_files_) {
  Branch (634:43): [True: 0, False: 178]
635
0
      const int level = deleted_file_set_kvp.first;
636
0
      const uint64_t number = deleted_file_set_kvp.second;
637
0
      levels_[level].deleted_files.insert(number);
638
0
    }
639
640
    // Add new files
641
194
    for (size_t i = 0; i < edit->new_files_.size(); i++) {
  Branch (641:24): [True: 16, False: 178]
642
16
      const int level = edit->new_files_[i].first;
643
16
      FileMetaData* f = new FileMetaData(edit->new_files_[i].second);
644
16
      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
16
      f->allowed_seeks = static_cast<int>((f->file_size / 16384U));
662
16
      if (f->allowed_seeks < 100) f->allowed_seeks = 100;
  Branch (662:11): [True: 16, False: 0]
663
664
16
      levels_[level].deleted_files.erase(f->number);
665
16
      levels_[level].added_files->insert(f);
666
16
    }
667
178
  }
668
669
  // Save the current state in *v.
670
178
  void SaveTo(Version* v) {
671
178
    BySmallestKey cmp;
672
178
    cmp.internal_comparator = &vset_->icmp_;
673
1.42k
    for (int level = 0; level < config::kNumLevels; level++) {
  Branch (673:25): [True: 1.24k, False: 178]
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
1.24k
      const std::vector<FileMetaData*>& base_files = base_->files_[level];
677
1.24k
      std::vector<FileMetaData*>::const_iterator base_iter = base_files.begin();
678
1.24k
      std::vector<FileMetaData*>::const_iterator base_end = base_files.end();
679
1.24k
      const FileSet* added_files = levels_[level].added_files;
680
1.24k
      v->files_[level].reserve(base_files.size() + added_files->size());
681
1.24k
      for (const auto& added_file : *added_files) {
  Branch (681:35): [True: 16, False: 1.24k]
682
        // Add all smaller files listed in base_
683
16
        for (std::vector<FileMetaData*>::const_iterator bpos =
684
16
                 std::upper_bound(base_iter, base_end, added_file, cmp);
685
16
             base_iter != bpos; ++base_iter) {
  Branch (685:14): [True: 0, False: 16]
686
0
          MaybeAddFile(v, level, *base_iter);
687
0
        }
688
689
16
        MaybeAddFile(v, level, added_file);
690
16
      }
691
692
      // Add remaining base files
693
1.24k
      for (; base_iter != base_end; ++base_iter) {
  Branch (693:14): [True: 0, False: 1.24k]
694
0
        MaybeAddFile(v, level, *base_iter);
695
0
      }
696
697
1.24k
#ifndef NDEBUG
698
      // Make sure there is no overlap in levels > 0
699
1.24k
      if (level > 0) {
  Branch (699:11): [True: 1.06k, False: 178]
700
1.06k
        for (uint32_t i = 1; i < v->files_[level].size(); i++) {
  Branch (700:30): [True: 0, False: 1.06k]
701
0
          const InternalKey& prev_end = v->files_[level][i - 1]->largest;
702
0
          const InternalKey& this_begin = v->files_[level][i]->smallest;
703
0
          if (vset_->icmp_.Compare(prev_end, this_begin) >= 0) {
  Branch (703:15): [True: 0, False: 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
0
          }
709
0
        }
710
1.06k
      }
711
1.24k
#endif
712
1.24k
    }
713
178
  }
714
715
16
  void MaybeAddFile(Version* v, int level, FileMetaData* f) {
716
16
    if (levels_[level].deleted_files.count(f->number) > 0) {
  Branch (716:9): [True: 0, False: 16]
717
      // File is deleted: do nothing
718
16
    } else {
719
16
      std::vector<FileMetaData*>* files = &v->files_[level];
720
16
      if (level > 0 && !files->empty()) {
  Branch (720:11): [True: 16, False: 0]
  Branch (720:24): [True: 0, False: 16]
721
        // Must not overlap
722
0
        assert(vset_->icmp_.Compare((*files)[files->size() - 1]->largest,
  Branch (722:9): [True: 0, False: 0]
723
0
                                    f->smallest) < 0);
724
0
      }
725
16
      f->refs++;
726
16
      files->push_back(f);
727
16
    }
728
16
  }
729
};
730
731
VersionSet::VersionSet(const std::string& dbname, const Options* options,
732
                       TableCache* table_cache,
733
                       const InternalKeyComparator* cmp)
734
81
    : env_(options->env),
735
81
      dbname_(dbname),
736
81
      options_(options),
737
81
      table_cache_(table_cache),
738
81
      icmp_(*cmp),
739
81
      next_file_number_(2),
740
81
      manifest_file_number_(0),  // Filled by Recover()
741
81
      last_sequence_(0),
742
81
      log_number_(0),
743
81
      prev_log_number_(0),
744
81
      descriptor_file_(nullptr),
745
81
      descriptor_log_(nullptr),
746
81
      dummy_versions_(this),
747
81
      current_(nullptr) {
748
81
  AppendVersion(new Version(this));
749
81
}
750
751
450k
VersionSet::~VersionSet() {
752
450k
  current_->Unref();
753
450k
  assert(dummy_versions_.next_ == &dummy_versions_);  // List must be empty
  Branch (753:3): [True: 450k, False: 0]
754
450k
  delete descriptor_log_;
755
450k
  delete descriptor_file_;
756
450k
}
757
758
259
void VersionSet::AppendVersion(Version* v) {
759
  // Make "v" current
760
259
  assert(v->refs_ == 0);
  Branch (760:3): [True: 259, False: 0]
761
259
  assert(v != current_);
  Branch (761:3): [True: 259, False: 0]
762
259
  if (current_ != nullptr) {
  Branch (762:7): [True: 178, False: 81]
763
178
    current_->Unref();
764
178
  }
765
259
  current_ = v;
766
259
  v->Ref();
767
768
  // Append to linked list
769
259
  v->prev_ = dummy_versions_.prev_;
770
259
  v->next_ = &dummy_versions_;
771
259
  v->prev_->next_ = v;
772
259
  v->next_->prev_ = v;
773
259
}
774
775
97
Status VersionSet::LogAndApply(VersionEdit* edit, port::Mutex* mu) {
776
97
  if (edit->has_log_number_) {
  Branch (776:7): [True: 97, False: 0]
777
97
    assert(edit->log_number_ >= log_number_);
  Branch (777:5): [True: 97, False: 0]
778
97
    assert(edit->log_number_ < next_file_number_);
  Branch (778:5): [True: 97, False: 0]
779
97
  } else {
780
0
    edit->SetLogNumber(log_number_);
781
0
  }
782
783
97
  if (!edit->has_prev_log_number_) {
  Branch (783:7): [True: 0, False: 97]
784
0
    edit->SetPrevLogNumber(prev_log_number_);
785
0
  }
786
787
97
  edit->SetNextFile(next_file_number_);
788
97
  edit->SetLastSequence(last_sequence_);
789
790
97
  Version* v = new Version(this);
791
97
  {
792
97
    Builder builder(this, current_);
793
97
    builder.Apply(edit);
794
97
    builder.SaveTo(v);
795
97
  }
796
97
  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
97
  std::string new_manifest_file;
801
97
  Status s;
802
97
  if (descriptor_log_ == nullptr) {
  Branch (802:7): [True: 81, False: 16]
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
81
    assert(descriptor_file_ == nullptr);
  Branch (805:5): [True: 81, False: 0]
806
81
    new_manifest_file = DescriptorFileName(dbname_, manifest_file_number_);
807
81
    edit->SetNextFile(next_file_number_);
808
81
    s = env_->NewWritableFile(new_manifest_file, &descriptor_file_);
809
81
    if (s.ok()) {
  Branch (809:9): [True: 81, False: 0]
810
81
      descriptor_log_ = new log::Writer(descriptor_file_);
811
81
      s = WriteSnapshot(descriptor_log_);
812
81
    }
813
81
  }
814
815
  // Unlock during expensive MANIFEST log write
816
97
  {
817
97
    mu->Unlock();
818
819
    // Write new record to MANIFEST log
820
97
    if (s.ok()) {
  Branch (820:9): [True: 97, False: 0]
821
97
      std::string record;
822
97
      edit->EncodeTo(&record);
823
97
      s = descriptor_log_->AddRecord(record);
824
97
      if (s.ok()) {
  Branch (824:11): [True: 97, False: 0]
825
97
        s = descriptor_file_->Sync();
826
97
      }
827
97
      if (!s.ok()) {
  Branch (827:11): [True: 0, False: 97]
828
0
        Log(options_->info_log, "MANIFEST write: %s\n", s.ToString().c_str());
829
0
      }
830
97
    }
831
832
    // If we just created a new descriptor file, install it by writing a
833
    // new CURRENT file that points to it.
834
97
    if (s.ok() && !new_manifest_file.empty()) {
  Branch (834:9): [True: 97, False: 0]
  Branch (834:19): [True: 81, False: 16]
835
81
      s = SetCurrentFile(env_, dbname_, manifest_file_number_);
836
81
    }
837
838
97
    mu->Lock();
839
97
  }
840
841
  // Install the new version
842
97
  if (s.ok()) {
  Branch (842:7): [True: 97, False: 0]
843
97
    AppendVersion(v);
844
97
    log_number_ = edit->log_number_;
845
97
    prev_log_number_ = edit->prev_log_number_;
846
97
  } else {
847
0
    delete v;
848
0
    if (!new_manifest_file.empty()) {
  Branch (848:9): [True: 0, False: 0]
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
0
    }
855
0
  }
856
857
97
  return s;
858
97
}
859
860
81
Status VersionSet::Recover(bool* save_manifest) {
861
81
  struct LogReporter : public log::Reader::Reporter {
862
81
    Status* status;
863
81
    void Corruption(size_t bytes, const Status& s) override {
864
0
      if (this->status->ok()) *this->status = s;
  Branch (864:11): [True: 0, False: 0]
865
0
    }
866
81
  };
867
868
  // Read "CURRENT" file, which contains a pointer to the current manifest file
869
81
  std::string current;
870
81
  Status s = ReadFileToString(env_, CurrentFileName(dbname_), &current);
871
81
  if (!s.ok()) {
  Branch (871:7): [True: 0, False: 81]
872
0
    return s;
873
0
  }
874
81
  if (current.empty() || current[current.size() - 1] != '\n') {
  Branch (874:7): [True: 0, False: 81]
  Branch (874:26): [True: 0, False: 81]
875
0
    return Status::Corruption("CURRENT file does not end with newline");
876
0
  }
877
81
  current.resize(current.size() - 1);
878
879
81
  std::string dscname = dbname_ + "/" + current;
880
81
  SequentialFile* file;
881
81
  s = env_->NewSequentialFile(dscname, &file);
882
81
  if (!s.ok()) {
  Branch (882:7): [True: 0, False: 81]
883
0
    if (s.IsNotFound()) {
  Branch (883:9): [True: 0, False: 0]
884
0
      return Status::Corruption("CURRENT points to a non-existent file",
885
0
                                s.ToString());
886
0
    }
887
0
    return s;
888
0
  }
889
890
81
  bool have_log_number = false;
891
81
  bool have_prev_log_number = false;
892
81
  bool have_next_file = false;
893
81
  bool have_last_sequence = false;
894
81
  uint64_t next_file = 0;
895
81
  uint64_t last_sequence = 0;
896
81
  uint64_t log_number = 0;
897
81
  uint64_t prev_log_number = 0;
898
81
  Builder builder(this, current_);
899
900
81
  {
901
81
    LogReporter reporter;
902
81
    reporter.status = &s;
903
81
    log::Reader reader(file, &reporter, true /*checksum*/,
904
81
                       0 /*initial_offset*/);
905
81
    Slice record;
906
81
    std::string scratch;
907
162
    while (reader.ReadRecord(&record, &scratch) && s.ok()) {
  Branch (907:12): [True: 81, False: 81]
  Branch (907:52): [True: 81, False: 0]
908
81
      VersionEdit edit;
909
81
      s = edit.DecodeFrom(record);
910
81
      if (s.ok()) {
  Branch (910:11): [True: 81, False: 0]
911
81
        if (edit.has_comparator_ &&
  Branch (911:13): [True: 81, False: 0]
912
81
            edit.comparator_ != icmp_.user_comparator()->Name()) {
  Branch (912:13): [True: 0, False: 81]
913
0
          s = Status::InvalidArgument(
914
0
              edit.comparator_ + " does not match existing comparator ",
915
0
              icmp_.user_comparator()->Name());
916
0
        }
917
81
      }
918
919
81
      if (s.ok()) {
  Branch (919:11): [True: 81, False: 0]
920
81
        builder.Apply(&edit);
921
81
      }
922
923
81
      if (edit.has_log_number_) {
  Branch (923:11): [True: 81, False: 0]
924
81
        log_number = edit.log_number_;
925
81
        have_log_number = true;
926
81
      }
927
928
81
      if (edit.has_prev_log_number_) {
  Branch (928:11): [True: 0, False: 81]
929
0
        prev_log_number = edit.prev_log_number_;
930
0
        have_prev_log_number = true;
931
0
      }
932
933
81
      if (edit.has_next_file_number_) {
  Branch (933:11): [True: 81, False: 0]
934
81
        next_file = edit.next_file_number_;
935
81
        have_next_file = true;
936
81
      }
937
938
81
      if (edit.has_last_sequence_) {
  Branch (938:11): [True: 81, False: 0]
939
81
        last_sequence = edit.last_sequence_;
940
81
        have_last_sequence = true;
941
81
      }
942
81
    }
943
81
  }
944
81
  delete file;
945
81
  file = nullptr;
946
947
81
  if (s.ok()) {
  Branch (947:7): [True: 81, False: 0]
948
81
    if (!have_next_file) {
  Branch (948:9): [True: 0, False: 81]
949
0
      s = Status::Corruption("no meta-nextfile entry in descriptor");
950
81
    } else if (!have_log_number) {
  Branch (950:16): [True: 0, False: 81]
951
0
      s = Status::Corruption("no meta-lognumber entry in descriptor");
952
81
    } else if (!have_last_sequence) {
  Branch (952:16): [True: 0, False: 81]
953
0
      s = Status::Corruption("no last-sequence-number entry in descriptor");
954
0
    }
955
956
81
    if (!have_prev_log_number) {
  Branch (956:9): [True: 81, False: 0]
957
81
      prev_log_number = 0;
958
81
    }
959
960
81
    MarkFileNumberUsed(prev_log_number);
961
81
    MarkFileNumberUsed(log_number);
962
81
  }
963
964
81
  if (s.ok()) {
  Branch (964:7): [True: 81, False: 0]
965
81
    Version* v = new Version(this);
966
81
    builder.SaveTo(v);
967
    // Install recovered version
968
81
    Finalize(v);
969
81
    AppendVersion(v);
970
81
    manifest_file_number_ = next_file;
971
81
    next_file_number_ = next_file + 1;
972
81
    last_sequence_ = last_sequence;
973
81
    log_number_ = log_number;
974
81
    prev_log_number_ = prev_log_number;
975
976
    // See if we can reuse the existing MANIFEST file.
977
81
    if (ReuseManifest(dscname, current)) {
  Branch (977:9): [True: 0, False: 81]
978
      // No need to save new manifest
979
81
    } else {
980
81
      *save_manifest = true;
981
81
    }
982
81
  }
983
984
81
  return s;
985
81
}
986
987
bool VersionSet::ReuseManifest(const std::string& dscname,
988
81
                               const std::string& dscbase) {
989
81
  if (!options_->reuse_logs) {
  Branch (989:7): [True: 81, False: 0]
990
81
    return false;
991
81
  }
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) ||
  Branch (995:7): [True: 0, False: 0]
  Branch (995:7): [True: 0, False: 0]
996
0
      manifest_type != kDescriptorFile ||
  Branch (996:7): [True: 0, False: 0]
997
0
      !env_->GetFileSize(dscname, &manifest_size).ok() ||
  Branch (997:7): [True: 0, False: 0]
998
      // Make new compacted MANIFEST if old one is too big
999
0
      manifest_size >= TargetFileSize(options_)) {
  Branch (999:7): [True: 0, False: 0]
1000
0
    return false;
1001
0
  }
1002
1003
0
  assert(descriptor_file_ == nullptr);
  Branch (1003:3): [True: 0, False: 0]
1004
0
  assert(descriptor_log_ == nullptr);
  Branch (1004:3): [True: 0, False: 0]
1005
0
  Status r = env_->NewAppendableFile(dscname, &descriptor_file_);
1006
0
  if (!r.ok()) {
  Branch (1006:7): [True: 0, False: 0]
1007
0
    Log(options_->info_log, "Reuse MANIFEST: %s\n", r.ToString().c_str());
1008
0
    assert(descriptor_file_ == nullptr);
  Branch (1008:5): [True: 0, False: 0]
1009
0
    return false;
1010
0
  }
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
162
void VersionSet::MarkFileNumberUsed(uint64_t number) {
1019
162
  if (next_file_number_ <= number) {
  Branch (1019:7): [True: 0, False: 162]
1020
0
    next_file_number_ = number + 1;
1021
0
  }
1022
162
}
1023
1024
178
void VersionSet::Finalize(Version* v) {
1025
  // Precomputed best level for next compaction
1026
178
  int best_level = -1;
1027
178
  double best_score = -1;
1028
1029
1.24k
  for (int level = 0; level < config::kNumLevels - 1; level++) {
  Branch (1029:23): [True: 1.06k, False: 178]
1030
1.06k
    double score;
1031
1.06k
    if (level == 0) {
  Branch (1031:9): [True: 178, False: 890]
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
178
      score = v->files_[level].size() /
1044
178
              static_cast<double>(config::kL0_CompactionTrigger);
1045
890
    } else {
1046
      // Compute the ratio of current size to size limit.
1047
890
      const uint64_t level_bytes = TotalFileSize(v->files_[level]);
1048
890
      score =
1049
890
          static_cast<double>(level_bytes) / MaxBytesForLevel(options_, level);
1050
890
    }
1051
1052
1.06k
    if (score > best_score) {
  Branch (1052:9): [True: 194, False: 874]
1053
194
      best_level = level;
1054
194
      best_score = score;
1055
194
    }
1056
1.06k
  }
1057
1058
178
  v->compaction_level_ = best_level;
1059
178
  v->compaction_score_ = best_score;
1060
178
}
1061
1062
81
Status VersionSet::WriteSnapshot(log::Writer* log) {
1063
  // TODO: Break up into multiple records to reduce memory usage on recovery?
1064
1065
  // Save metadata
1066
81
  VersionEdit edit;
1067
81
  edit.SetComparatorName(icmp_.user_comparator()->Name());
1068
1069
  // Save compaction pointers
1070
648
  for (int level = 0; level < config::kNumLevels; level++) {
  Branch (1070:23): [True: 567, False: 81]
1071
567
    if (!compact_pointer_[level].empty()) {
  Branch (1071:9): [True: 0, False: 567]
1072
0
      InternalKey key;
1073
0
      key.DecodeFrom(compact_pointer_[level]);
1074
0
      edit.SetCompactPointer(level, key);
1075
0
    }
1076
567
  }
1077
1078
  // Save files
1079
648
  for (int level = 0; level < config::kNumLevels; level++) {
  Branch (1079:23): [True: 567, False: 81]
1080
567
    const std::vector<FileMetaData*>& files = current_->files_[level];
1081
567
    for (size_t i = 0; i < files.size(); i++) {
  Branch (1081:24): [True: 0, False: 567]
1082
0
      const FileMetaData* f = files[i];
1083
0
      edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest);
1084
0
    }
1085
567
  }
1086
1087
81
  std::string record;
1088
81
  edit.EncodeTo(&record);
1089
81
  return log->AddRecord(record);
1090
81
}
1091
1092
831k
int VersionSet::NumLevelFiles(int level) const {
1093
831k
  assert(level >= 0);
  Branch (1093:3): [True: 831k, False: 0]
1094
831k
  assert(level < config::kNumLevels);
  Branch (1094:3): [True: 831k, False: 0]
1095
831k
  return current_->files_[level].size();
1096
831k
}
1097
1098
0
const char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const {
1099
  // Update code if kNumLevels changes
1100
0
  static_assert(config::kNumLevels == 7, "");
1101
0
  snprintf(scratch->buffer, sizeof(scratch->buffer),
1102
0
           "files[ %d %d %d %d %d %d %d ]", int(current_->files_[0].size()),
1103
0
           int(current_->files_[1].size()), int(current_->files_[2].size()),
1104
0
           int(current_->files_[3].size()), int(current_->files_[4].size()),
1105
0
           int(current_->files_[5].size()), int(current_->files_[6].size()));
1106
0
  return scratch->buffer;
1107
0
}
1108
1109
0
uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) {
1110
0
  uint64_t result = 0;
1111
0
  for (int level = 0; level < config::kNumLevels; level++) {
  Branch (1111:23): [True: 0, False: 0]
1112
0
    const std::vector<FileMetaData*>& files = v->files_[level];
1113
0
    for (size_t i = 0; i < files.size(); i++) {
  Branch (1113:24): [True: 0, False: 0]
1114
0
      if (icmp_.Compare(files[i]->largest, ikey) <= 0) {
  Branch (1114:11): [True: 0, False: 0]
1115
        // Entire file is before "ikey", so just add the file size
1116
0
        result += files[i]->file_size;
1117
0
      } else if (icmp_.Compare(files[i]->smallest, ikey) > 0) {
  Branch (1117:18): [True: 0, False: 0]
1118
        // Entire file is after "ikey", so ignore
1119
0
        if (level > 0) {
  Branch (1119:13): [True: 0, False: 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
0
          break;
1124
0
        }
1125
0
      } else {
1126
        // "ikey" falls in the range for this table.  Add the
1127
        // approximate offset of "ikey" within the table.
1128
0
        Table* tableptr;
1129
0
        Iterator* iter = table_cache_->NewIterator(
1130
0
            ReadOptions(), files[i]->number, files[i]->file_size, &tableptr);
1131
0
        if (tableptr != nullptr) {
  Branch (1131:13): [True: 0, False: 0]
1132
0
          result += tableptr->ApproximateOffsetOf(ikey.Encode());
1133
0
        }
1134
0
        delete iter;
1135
0
      }
1136
0
    }
1137
0
  }
1138
0
  return result;
1139
0
}
1140
1141
178
void VersionSet::AddLiveFiles(std::set<uint64_t>* live) {
1142
356
  for (Version* v = dummy_versions_.next_; v != &dummy_versions_;
  Branch (1142:44): [True: 178, False: 178]
1143
178
       v = v->next_) {
1144
1.42k
    for (int level = 0; level < config::kNumLevels; level++) {
  Branch (1144:25): [True: 1.24k, False: 178]
1145
1.24k
      const std::vector<FileMetaData*>& files = v->files_[level];
1146
1.26k
      for (size_t i = 0; i < files.size(); i++) {
  Branch (1146:26): [True: 16, False: 1.24k]
1147
16
        live->insert(files[i]->number);
1148
16
      }
1149
1.24k
    }
1150
178
  }
1151
178
}
1152
1153
0
int64_t VersionSet::NumLevelBytes(int level) const {
1154
0
  assert(level >= 0);
  Branch (1154:3): [True: 0, False: 0]
1155
0
  assert(level < config::kNumLevels);
  Branch (1155:3): [True: 0, False: 0]
1156
0
  return TotalFileSize(current_->files_[level]);
1157
0
}
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++) {
  Branch (1162:23): [True: 0, False: 0]
1163
0
    for (size_t i = 0; i < current_->files_[level].size(); i++) {
  Branch (1163:24): [True: 0, False: 0]
1164
0
      const FileMetaData* f = current_->files_[level][i];
1165
0
      current_->GetOverlappingInputs(level + 1, &f->smallest, &f->largest,
1166
0
                                     &overlaps);
1167
0
      const int64_t sum = TotalFileSize(overlaps);
1168
0
      if (sum > result) {
  Branch (1168:11): [True: 0, False: 0]
1169
0
        result = sum;
1170
0
      }
1171
0
    }
1172
0
  }
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
void VersionSet::GetRange(const std::vector<FileMetaData*>& inputs,
1180
0
                          InternalKey* smallest, InternalKey* largest) {
1181
0
  assert(!inputs.empty());
  Branch (1181:3): [True: 0, False: 0]
1182
0
  smallest->Clear();
1183
0
  largest->Clear();
1184
0
  for (size_t i = 0; i < inputs.size(); i++) {
  Branch (1184:22): [True: 0, False: 0]
1185
0
    FileMetaData* f = inputs[i];
1186
0
    if (i == 0) {
  Branch (1186:9): [True: 0, False: 0]
1187
0
      *smallest = f->smallest;
1188
0
      *largest = f->largest;
1189
0
    } else {
1190
0
      if (icmp_.Compare(f->smallest, *smallest) < 0) {
  Branch (1190:11): [True: 0, False: 0]
1191
0
        *smallest = f->smallest;
1192
0
      }
1193
0
      if (icmp_.Compare(f->largest, *largest) > 0) {
  Branch (1193:11): [True: 0, False: 0]
1194
0
        *largest = f->largest;
1195
0
      }
1196
0
    }
1197
0
  }
1198
0
}
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
void VersionSet::GetRange2(const std::vector<FileMetaData*>& inputs1,
1204
                           const std::vector<FileMetaData*>& inputs2,
1205
0
                           InternalKey* smallest, InternalKey* largest) {
1206
0
  std::vector<FileMetaData*> all = inputs1;
1207
0
  all.insert(all.end(), inputs2.begin(), inputs2.end());
1208
0
  GetRange(all, smallest, largest);
1209
0
}
1210
1211
0
Iterator* VersionSet::MakeInputIterator(Compaction* c) {
1212
0
  ReadOptions options;
1213
0
  options.verify_checksums = options_->paranoid_checks;
1214
0
  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
0
  const int space = (c->level() == 0 ? c->inputs_[0].size() + 1 : 2);
  Branch (1219:22): [True: 0, False: 0]
1220
0
  Iterator** list = new Iterator*[space];
1221
0
  int num = 0;
1222
0
  for (int which = 0; which < 2; which++) {
  Branch (1222:23): [True: 0, False: 0]
1223
0
    if (!c->inputs_[which].empty()) {
  Branch (1223:9): [True: 0, False: 0]
1224
0
      if (c->level() + which == 0) {
  Branch (1224:11): [True: 0, False: 0]
1225
0
        const std::vector<FileMetaData*>& files = c->inputs_[which];
1226
0
        for (size_t i = 0; i < files.size(); i++) {
  Branch (1226:28): [True: 0, False: 0]
1227
0
          list[num++] = table_cache_->NewIterator(options, files[i]->number,
1228
0
                                                  files[i]->file_size);
1229
0
        }
1230
0
      } else {
1231
        // Create concatenating iterator for the files from this level
1232
0
        list[num++] = NewTwoLevelIterator(
1233
0
            new Version::LevelFileNumIterator(icmp_, &c->inputs_[which]),
1234
0
            &GetFileIterator, table_cache_, options);
1235
0
      }
1236
0
    }
1237
0
  }
1238
0
  assert(num <= space);
  Branch (1238:3): [True: 0, False: 0]
1239
0
  Iterator* result = NewMergingIterator(&icmp_, list, num);
1240
0
  delete[] list;
1241
0
  return result;
1242
0
}
1243
1244
0
Compaction* VersionSet::PickCompaction() {
1245
0
  Compaction* c;
1246
0
  int level;
1247
1248
  // We prefer compactions triggered by too much data in a level over
1249
  // the compactions triggered by seeks.
1250
0
  const bool size_compaction = (current_->compaction_score_ >= 1);
1251
0
  const bool seek_compaction = (current_->file_to_compact_ != nullptr);
1252
0
  if (size_compaction) {
  Branch (1252:7): [True: 0, False: 0]
1253
0
    level = current_->compaction_level_;
1254
0
    assert(level >= 0);
  Branch (1254:5): [True: 0, False: 0]
1255
0
    assert(level + 1 < config::kNumLevels);
  Branch (1255:5): [True: 0, False: 0]
1256
0
    c = new Compaction(options_, level);
1257
1258
    // Pick the first file that comes after compact_pointer_[level]
1259
0
    for (size_t i = 0; i < current_->files_[level].size(); i++) {
  Branch (1259:24): [True: 0, False: 0]
1260
0
      FileMetaData* f = current_->files_[level][i];
1261
0
      if (compact_pointer_[level].empty() ||
  Branch (1261:11): [True: 0, False: 0]
  Branch (1261:11): [True: 0, False: 0]
1262
0
          icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) {
  Branch (1262:11): [True: 0, False: 0]
1263
0
        c->inputs_[0].push_back(f);
1264
0
        break;
1265
0
      }
1266
0
    }
1267
0
    if (c->inputs_[0].empty()) {
  Branch (1267:9): [True: 0, False: 0]
1268
      // Wrap-around to the beginning of the key space
1269
0
      c->inputs_[0].push_back(current_->files_[level][0]);
1270
0
    }
1271
0
  } else if (seek_compaction) {
  Branch (1271:14): [True: 0, False: 0]
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
0
  } else {
1276
0
    return nullptr;
1277
0
  }
1278
1279
0
  c->input_version_ = current_;
1280
0
  c->input_version_->Ref();
1281
1282
  // Files in level 0 may overlap each other, so pick up all overlapping ones
1283
0
  if (level == 0) {
  Branch (1283:7): [True: 0, False: 0]
1284
0
    InternalKey smallest, largest;
1285
0
    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
0
    current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]);
1290
0
    assert(!c->inputs_[0].empty());
  Branch (1290:5): [True: 0, False: 0]
1291
0
  }
1292
1293
0
  SetupOtherInputs(c);
1294
1295
0
  return c;
1296
0
}
1297
1298
// Finds the largest key in a vector of files. Returns true if files it not
1299
// empty.
1300
bool FindLargestKey(const InternalKeyComparator& icmp,
1301
                    const std::vector<FileMetaData*>& files,
1302
0
                    InternalKey* largest_key) {
1303
0
  if (files.empty()) {
  Branch (1303:7): [True: 0, False: 0]
1304
0
    return false;
1305
0
  }
1306
0
  *largest_key = files[0]->largest;
1307
0
  for (size_t i = 1; i < files.size(); ++i) {
  Branch (1307:22): [True: 0, False: 0]
1308
0
    FileMetaData* f = files[i];
1309
0
    if (icmp.Compare(f->largest, *largest_key) > 0) {
  Branch (1309:9): [True: 0, False: 0]
1310
0
      *largest_key = f->largest;
1311
0
    }
1312
0
  }
1313
0
  return true;
1314
0
}
1315
1316
// Finds minimum file b2=(l2, u2) in level file for which l2 > u1 and
1317
// user_key(l2) = user_key(u1)
1318
FileMetaData* FindSmallestBoundaryFile(
1319
    const InternalKeyComparator& icmp,
1320
    const std::vector<FileMetaData*>& level_files,
1321
0
    const InternalKey& largest_key) {
1322
0
  const Comparator* user_cmp = icmp.user_comparator();
1323
0
  FileMetaData* smallest_boundary_file = nullptr;
1324
0
  for (size_t i = 0; i < level_files.size(); ++i) {
  Branch (1324:22): [True: 0, False: 0]
1325
0
    FileMetaData* f = level_files[i];
1326
0
    if (icmp.Compare(f->smallest, largest_key) > 0 &&
  Branch (1326:9): [True: 0, False: 0]
  Branch (1326:9): [True: 0, False: 0]
1327
0
        user_cmp->Compare(f->smallest.user_key(), largest_key.user_key()) ==
  Branch (1327:9): [True: 0, False: 0]
1328
0
            0) {
1329
0
      if (smallest_boundary_file == nullptr ||
  Branch (1329:11): [True: 0, False: 0]
1330
0
          icmp.Compare(f->smallest, smallest_boundary_file->smallest) < 0) {
  Branch (1330:11): [True: 0, False: 0]
1331
0
        smallest_boundary_file = f;
1332
0
      }
1333
0
    }
1334
0
  }
1335
0
  return smallest_boundary_file;
1336
0
}
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
void AddBoundaryInputs(const InternalKeyComparator& icmp,
1353
                       const std::vector<FileMetaData*>& level_files,
1354
0
                       std::vector<FileMetaData*>* compaction_files) {
1355
0
  InternalKey largest_key;
1356
1357
  // Quick return if compaction_files is empty.
1358
0
  if (!FindLargestKey(icmp, *compaction_files, &largest_key)) {
  Branch (1358:7): [True: 0, False: 0]
1359
0
    return;
1360
0
  }
1361
1362
0
  bool continue_searching = true;
1363
0
  while (continue_searching) {
  Branch (1363:10): [True: 0, False: 0]
1364
0
    FileMetaData* smallest_boundary_file =
1365
0
        FindSmallestBoundaryFile(icmp, level_files, largest_key);
1366
1367
    // If a boundary file was found advance largest_key, otherwise we're done.
1368
0
    if (smallest_boundary_file != NULL) {
  Branch (1368:9): [True: 0, False: 0]
1369
0
      compaction_files->push_back(smallest_boundary_file);
1370
0
      largest_key = smallest_boundary_file->largest;
1371
0
    } else {
1372
0
      continue_searching = false;
1373
0
    }
1374
0
  }
1375
0
}
1376
1377
0
void VersionSet::SetupOtherInputs(Compaction* c) {
1378
0
  const int level = c->level();
1379
0
  InternalKey smallest, largest;
1380
1381
0
  AddBoundaryInputs(icmp_, current_->files_[level], &c->inputs_[0]);
1382
0
  GetRange(c->inputs_[0], &smallest, &largest);
1383
1384
0
  current_->GetOverlappingInputs(level + 1, &smallest, &largest,
1385
0
                                 &c->inputs_[1]);
1386
1387
  // Get entire range covered by compaction
1388
0
  InternalKey all_start, all_limit;
1389
0
  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
0
  if (!c->inputs_[1].empty()) {
  Branch (1393:7): [True: 0, False: 0]
1394
0
    std::vector<FileMetaData*> expanded0;
1395
0
    current_->GetOverlappingInputs(level, &all_start, &all_limit, &expanded0);
1396
0
    AddBoundaryInputs(icmp_, current_->files_[level], &expanded0);
1397
0
    const int64_t inputs0_size = TotalFileSize(c->inputs_[0]);
1398
0
    const int64_t inputs1_size = TotalFileSize(c->inputs_[1]);
1399
0
    const int64_t expanded0_size = TotalFileSize(expanded0);
1400
0
    if (expanded0.size() > c->inputs_[0].size() &&
  Branch (1400:9): [True: 0, False: 0]
1401
0
        inputs1_size + expanded0_size <
  Branch (1401:9): [True: 0, False: 0]
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
0
                                     &expanded1);
1408
0
      if (expanded1.size() == c->inputs_[1].size()) {
  Branch (1408:11): [True: 0, False: 0]
1409
0
        Log(options_->info_log,
1410
0
            "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
0
      }
1420
0
    }
1421
0
  }
1422
1423
  // Compute the set of grandparent files that overlap this compaction
1424
  // (parent == level+1; grandparent == level+2)
1425
0
  if (level + 2 < config::kNumLevels) {
  Branch (1425:7): [True: 0, False: 0]
1426
0
    current_->GetOverlappingInputs(level + 2, &all_start, &all_limit,
1427
0
                                   &c->grandparents_);
1428
0
  }
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
0
  compact_pointer_[level] = largest.Encode().ToString();
1435
0
  c->edit_.SetCompactPointer(level, largest);
1436
0
}
1437
1438
Compaction* VersionSet::CompactRange(int level, const InternalKey* begin,
1439
16
                                     const InternalKey* end) {
1440
16
  std::vector<FileMetaData*> inputs;
1441
16
  current_->GetOverlappingInputs(level, begin, end, &inputs);
1442
16
  if (inputs.empty()) {
  Branch (1442:7): [True: 16, False: 0]
1443
16
    return nullptr;
1444
16
  }
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) {
  Branch (1450:7): [True: 0, False: 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++) {
  Branch (1453:24): [True: 0, False: 0]
1454
0
      uint64_t s = inputs[i]->file_size;
1455
0
      total += s;
1456
0
      if (total >= limit) {
  Branch (1456:11): [True: 0, False: 0]
1457
0
        inputs.resize(i + 1);
1458
0
        break;
1459
0
      }
1460
0
    }
1461
0
  }
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
0
  return c;
1469
16
}
1470
1471
Compaction::Compaction(const Options* options, int level)
1472
0
    : level_(level),
1473
0
      max_output_file_size_(MaxFileSizeForLevel(options, level)),
1474
0
      input_version_(nullptr),
1475
0
      grandparent_index_(0),
1476
0
      seen_key_(false),
1477
0
      overlapped_bytes_(0) {
1478
0
  for (int i = 0; i < config::kNumLevels; i++) {
  Branch (1478:19): [True: 0, False: 0]
1479
0
    level_ptrs_[i] = 0;
1480
0
  }
1481
0
}
1482
1483
0
Compaction::~Compaction() {
1484
0
  if (input_version_ != nullptr) {
  Branch (1484:7): [True: 0, False: 0]
1485
0
    input_version_->Unref();
1486
0
  }
1487
0
}
1488
1489
0
bool Compaction::IsTrivialMove() const {
1490
0
  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
0
  return (num_input_files(0) == 1 && num_input_files(1) == 0 &&
  Branch (1494:11): [True: 0, False: 0]
  Branch (1494:38): [True: 0, False: 0]
1495
0
          TotalFileSize(grandparents_) <=
  Branch (1495:11): [True: 0, False: 0]
1496
0
              MaxGrandParentOverlapBytes(vset->options_));
1497
0
}
1498
1499
0
void Compaction::AddInputDeletions(VersionEdit* edit) {
1500
0
  for (int which = 0; which < 2; which++) {
  Branch (1500:23): [True: 0, False: 0]
1501
0
    for (size_t i = 0; i < inputs_[which].size(); i++) {
  Branch (1501:24): [True: 0, False: 0]
1502
0
      edit->DeleteFile(level_ + which, inputs_[which][i]->number);
1503
0
    }
1504
0
  }
1505
0
}
1506
1507
0
bool Compaction::IsBaseLevelForKey(const Slice& user_key) {
1508
  // Maybe use binary search to find right entry instead of linear search?
1509
0
  const Comparator* user_cmp = input_version_->vset_->icmp_.user_comparator();
1510
0
  for (int lvl = level_ + 2; lvl < config::kNumLevels; lvl++) {
  Branch (1510:30): [True: 0, False: 0]
1511
0
    const std::vector<FileMetaData*>& files = input_version_->files_[lvl];
1512
0
    while (level_ptrs_[lvl] < files.size()) {
  Branch (1512:12): [True: 0, False: 0]
1513
0
      FileMetaData* f = files[level_ptrs_[lvl]];
1514
0
      if (user_cmp->Compare(user_key, f->largest.user_key()) <= 0) {
  Branch (1514:11): [True: 0, False: 0]
1515
        // We've advanced far enough
1516
0
        if (user_cmp->Compare(user_key, f->smallest.user_key()) >= 0) {
  Branch (1516:13): [True: 0, False: 0]
1517
          // Key falls in this file's range, so definitely not base level
1518
0
          return false;
1519
0
        }
1520
0
        break;
1521
0
      }
1522
0
      level_ptrs_[lvl]++;
1523
0
    }
1524
0
  }
1525
0
  return true;
1526
0
}
1527
1528
0
bool Compaction::ShouldStopBefore(const Slice& internal_key) {
1529
0
  const VersionSet* vset = input_version_->vset_;
1530
  // Scan to find earliest grandparent file that contains key.
1531
0
  const InternalKeyComparator* icmp = &vset->icmp_;
1532
0
  while (grandparent_index_ < grandparents_.size() &&
  Branch (1532:10): [True: 0, False: 0]
  Branch (1532:10): [True: 0, False: 0]
1533
0
         icmp->Compare(internal_key,
  Branch (1533:10): [True: 0, False: 0]
1534
0
                       grandparents_[grandparent_index_]->largest.Encode()) >
1535
0
             0) {
1536
0
    if (seen_key_) {
  Branch (1536:9): [True: 0, False: 0]
1537
0
      overlapped_bytes_ += grandparents_[grandparent_index_]->file_size;
1538
0
    }
1539
0
    grandparent_index_++;
1540
0
  }
1541
0
  seen_key_ = true;
1542
1543
0
  if (overlapped_bytes_ > MaxGrandParentOverlapBytes(vset->options_)) {
  Branch (1543:7): [True: 0, False: 0]
1544
    // Too much overlap for current output; start new output
1545
0
    overlapped_bytes_ = 0;
1546
0
    return true;
1547
0
  } else {
1548
0
    return false;
1549
0
  }
1550
0
}
1551
1552
0
void Compaction::ReleaseInputs() {
1553
0
  if (input_version_ != nullptr) {
  Branch (1553:7): [True: 0, False: 0]
1554
0
    input_version_->Unref();
1555
0
    input_version_ = nullptr;
1556
0
  }
1557
0
}
1558
1559
}  // namespace leveldb