Coverage Report

Created: 2025-06-10 13:21

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