leveldb-ruby 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/README +17 -0
  2. data/ext/leveldb/extconf.rb +10 -0
  3. data/ext/leveldb/leveldb.cc +181 -0
  4. data/leveldb/Makefile +172 -0
  5. data/leveldb/db/builder.cc +90 -0
  6. data/leveldb/db/builder.h +36 -0
  7. data/leveldb/db/corruption_test.cc +354 -0
  8. data/leveldb/db/db_bench.cc +677 -0
  9. data/leveldb/db/db_impl.cc +1236 -0
  10. data/leveldb/db/db_impl.h +180 -0
  11. data/leveldb/db/db_iter.cc +298 -0
  12. data/leveldb/db/db_iter.h +26 -0
  13. data/leveldb/db/db_test.cc +1192 -0
  14. data/leveldb/db/dbformat.cc +87 -0
  15. data/leveldb/db/dbformat.h +165 -0
  16. data/leveldb/db/dbformat_test.cc +112 -0
  17. data/leveldb/db/filename.cc +135 -0
  18. data/leveldb/db/filename.h +80 -0
  19. data/leveldb/db/filename_test.cc +122 -0
  20. data/leveldb/db/log_format.h +35 -0
  21. data/leveldb/db/log_reader.cc +254 -0
  22. data/leveldb/db/log_reader.h +108 -0
  23. data/leveldb/db/log_test.cc +500 -0
  24. data/leveldb/db/log_writer.cc +103 -0
  25. data/leveldb/db/log_writer.h +48 -0
  26. data/leveldb/db/memtable.cc +108 -0
  27. data/leveldb/db/memtable.h +85 -0
  28. data/leveldb/db/repair.cc +384 -0
  29. data/leveldb/db/skiplist.h +378 -0
  30. data/leveldb/db/skiplist_test.cc +378 -0
  31. data/leveldb/db/snapshot.h +66 -0
  32. data/leveldb/db/table_cache.cc +95 -0
  33. data/leveldb/db/table_cache.h +50 -0
  34. data/leveldb/db/version_edit.cc +268 -0
  35. data/leveldb/db/version_edit.h +106 -0
  36. data/leveldb/db/version_edit_test.cc +46 -0
  37. data/leveldb/db/version_set.cc +1060 -0
  38. data/leveldb/db/version_set.h +306 -0
  39. data/leveldb/db/write_batch.cc +138 -0
  40. data/leveldb/db/write_batch_internal.h +45 -0
  41. data/leveldb/db/write_batch_test.cc +89 -0
  42. data/leveldb/include/leveldb/cache.h +99 -0
  43. data/leveldb/include/leveldb/comparator.h +63 -0
  44. data/leveldb/include/leveldb/db.h +148 -0
  45. data/leveldb/include/leveldb/env.h +302 -0
  46. data/leveldb/include/leveldb/iterator.h +100 -0
  47. data/leveldb/include/leveldb/options.h +198 -0
  48. data/leveldb/include/leveldb/slice.h +109 -0
  49. data/leveldb/include/leveldb/status.h +100 -0
  50. data/leveldb/include/leveldb/table.h +70 -0
  51. data/leveldb/include/leveldb/table_builder.h +91 -0
  52. data/leveldb/include/leveldb/write_batch.h +64 -0
  53. data/leveldb/port/port.h +23 -0
  54. data/leveldb/port/port_android.cc +64 -0
  55. data/leveldb/port/port_android.h +150 -0
  56. data/leveldb/port/port_chromium.cc +80 -0
  57. data/leveldb/port/port_chromium.h +97 -0
  58. data/leveldb/port/port_example.h +115 -0
  59. data/leveldb/port/port_osx.cc +50 -0
  60. data/leveldb/port/port_osx.h +125 -0
  61. data/leveldb/port/port_posix.cc +50 -0
  62. data/leveldb/port/port_posix.h +94 -0
  63. data/leveldb/port/sha1_portable.cc +298 -0
  64. data/leveldb/port/sha1_portable.h +25 -0
  65. data/leveldb/port/sha1_test.cc +39 -0
  66. data/leveldb/port/win/stdint.h +24 -0
  67. data/leveldb/table/block.cc +263 -0
  68. data/leveldb/table/block.h +43 -0
  69. data/leveldb/table/block_builder.cc +109 -0
  70. data/leveldb/table/block_builder.h +57 -0
  71. data/leveldb/table/format.cc +131 -0
  72. data/leveldb/table/format.h +103 -0
  73. data/leveldb/table/iterator.cc +67 -0
  74. data/leveldb/table/iterator_wrapper.h +63 -0
  75. data/leveldb/table/merger.cc +197 -0
  76. data/leveldb/table/merger.h +26 -0
  77. data/leveldb/table/table.cc +175 -0
  78. data/leveldb/table/table_builder.cc +227 -0
  79. data/leveldb/table/table_test.cc +845 -0
  80. data/leveldb/table/two_level_iterator.cc +182 -0
  81. data/leveldb/table/two_level_iterator.h +34 -0
  82. data/leveldb/util/arena.cc +68 -0
  83. data/leveldb/util/arena.h +68 -0
  84. data/leveldb/util/arena_test.cc +68 -0
  85. data/leveldb/util/cache.cc +255 -0
  86. data/leveldb/util/cache_test.cc +169 -0
  87. data/leveldb/util/coding.cc +194 -0
  88. data/leveldb/util/coding.h +104 -0
  89. data/leveldb/util/coding_test.cc +173 -0
  90. data/leveldb/util/comparator.cc +72 -0
  91. data/leveldb/util/crc32c.cc +332 -0
  92. data/leveldb/util/crc32c.h +45 -0
  93. data/leveldb/util/crc32c_test.cc +72 -0
  94. data/leveldb/util/env.cc +77 -0
  95. data/leveldb/util/env_chromium.cc +612 -0
  96. data/leveldb/util/env_posix.cc +606 -0
  97. data/leveldb/util/env_test.cc +102 -0
  98. data/leveldb/util/hash.cc +45 -0
  99. data/leveldb/util/hash.h +19 -0
  100. data/leveldb/util/histogram.cc +128 -0
  101. data/leveldb/util/histogram.h +41 -0
  102. data/leveldb/util/logging.cc +81 -0
  103. data/leveldb/util/logging.h +47 -0
  104. data/leveldb/util/mutexlock.h +39 -0
  105. data/leveldb/util/options.cc +28 -0
  106. data/leveldb/util/random.h +59 -0
  107. data/leveldb/util/status.cc +75 -0
  108. data/leveldb/util/testharness.cc +65 -0
  109. data/leveldb/util/testharness.h +129 -0
  110. data/leveldb/util/testutil.cc +51 -0
  111. data/leveldb/util/testutil.h +53 -0
  112. data/lib/leveldb.rb +36 -0
  113. metadata +183 -0
@@ -0,0 +1,106 @@
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
+ #ifndef STORAGE_LEVELDB_DB_VERSION_EDIT_H_
6
+ #define STORAGE_LEVELDB_DB_VERSION_EDIT_H_
7
+
8
+ #include <set>
9
+ #include <utility>
10
+ #include <vector>
11
+ #include "db/dbformat.h"
12
+
13
+ namespace leveldb {
14
+
15
+ class VersionSet;
16
+
17
+ struct FileMetaData {
18
+ int refs;
19
+ uint64_t number;
20
+ uint64_t file_size; // File size in bytes
21
+ InternalKey smallest; // Smallest internal key served by table
22
+ InternalKey largest; // Largest internal key served by table
23
+
24
+ FileMetaData() : refs(0), file_size(0) { }
25
+ };
26
+
27
+ class VersionEdit {
28
+ public:
29
+ VersionEdit() { Clear(); }
30
+ ~VersionEdit() { }
31
+
32
+ void Clear();
33
+
34
+ void SetComparatorName(const Slice& name) {
35
+ has_comparator_ = true;
36
+ comparator_ = name.ToString();
37
+ }
38
+ void SetLogNumber(uint64_t num) {
39
+ has_log_number_ = true;
40
+ log_number_ = num;
41
+ }
42
+ void SetPrevLogNumber(uint64_t num) {
43
+ has_prev_log_number_ = true;
44
+ prev_log_number_ = num;
45
+ }
46
+ void SetNextFile(uint64_t num) {
47
+ has_next_file_number_ = true;
48
+ next_file_number_ = num;
49
+ }
50
+ void SetLastSequence(SequenceNumber seq) {
51
+ has_last_sequence_ = true;
52
+ last_sequence_ = seq;
53
+ }
54
+ void SetCompactPointer(int level, const InternalKey& key) {
55
+ compact_pointers_.push_back(std::make_pair(level, key));
56
+ }
57
+
58
+ // Add the specified file at the specified number.
59
+ // REQUIRES: This version has not been saved (see VersionSet::SaveTo)
60
+ // REQUIRES: "smallest" and "largest" are smallest and largest keys in file
61
+ void AddFile(int level, uint64_t file,
62
+ uint64_t file_size,
63
+ const InternalKey& smallest,
64
+ const InternalKey& largest) {
65
+ FileMetaData f;
66
+ f.number = file;
67
+ f.file_size = file_size;
68
+ f.smallest = smallest;
69
+ f.largest = largest;
70
+ new_files_.push_back(std::make_pair(level, f));
71
+ }
72
+
73
+ // Delete the specified "file" from the specified "level".
74
+ void DeleteFile(int level, uint64_t file) {
75
+ deleted_files_.insert(std::make_pair(level, file));
76
+ }
77
+
78
+ void EncodeTo(std::string* dst) const;
79
+ Status DecodeFrom(const Slice& src);
80
+
81
+ std::string DebugString() const;
82
+
83
+ private:
84
+ friend class VersionSet;
85
+
86
+ typedef std::set< std::pair<int, uint64_t> > DeletedFileSet;
87
+
88
+ std::string comparator_;
89
+ uint64_t log_number_;
90
+ uint64_t prev_log_number_;
91
+ uint64_t next_file_number_;
92
+ SequenceNumber last_sequence_;
93
+ bool has_comparator_;
94
+ bool has_log_number_;
95
+ bool has_prev_log_number_;
96
+ bool has_next_file_number_;
97
+ bool has_last_sequence_;
98
+
99
+ std::vector< std::pair<int, InternalKey> > compact_pointers_;
100
+ DeletedFileSet deleted_files_;
101
+ std::vector< std::pair<int, FileMetaData> > new_files_;
102
+ };
103
+
104
+ }
105
+
106
+ #endif // STORAGE_LEVELDB_DB_VERSION_EDIT_H_
@@ -0,0 +1,46 @@
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_edit.h"
6
+ #include "util/testharness.h"
7
+
8
+ namespace leveldb {
9
+
10
+ static void TestEncodeDecode(const VersionEdit& edit) {
11
+ std::string encoded, encoded2;
12
+ edit.EncodeTo(&encoded);
13
+ VersionEdit parsed;
14
+ Status s = parsed.DecodeFrom(encoded);
15
+ ASSERT_TRUE(s.ok()) << s.ToString();
16
+ parsed.EncodeTo(&encoded2);
17
+ ASSERT_EQ(encoded, encoded2);
18
+ }
19
+
20
+ class VersionEditTest { };
21
+
22
+ TEST(VersionEditTest, EncodeDecode) {
23
+ static const uint64_t kBig = 1ull << 50;
24
+
25
+ VersionEdit edit;
26
+ for (int i = 0; i < 4; i++) {
27
+ TestEncodeDecode(edit);
28
+ edit.AddFile(3, kBig + 300 + i, kBig + 400 + i,
29
+ InternalKey("foo", kBig + 500 + i, kTypeValue),
30
+ InternalKey("zoo", kBig + 600 + i, kTypeDeletion));
31
+ edit.DeleteFile(4, kBig + 700 + i);
32
+ edit.SetCompactPointer(i, InternalKey("x", kBig + 900 + i, kTypeValue));
33
+ }
34
+
35
+ edit.SetComparatorName("foo");
36
+ edit.SetLogNumber(kBig + 100);
37
+ edit.SetNextFile(kBig + 200);
38
+ edit.SetLastSequence(kBig + 1000);
39
+ TestEncodeDecode(edit);
40
+ }
41
+
42
+ }
43
+
44
+ int main(int argc, char** argv) {
45
+ return leveldb::test::RunAllTests();
46
+ }
@@ -0,0 +1,1060 @@
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 <algorithm>
8
+ #include <stdio.h>
9
+ #include "db/filename.h"
10
+ #include "db/log_reader.h"
11
+ #include "db/log_writer.h"
12
+ #include "db/memtable.h"
13
+ #include "db/table_cache.h"
14
+ #include "leveldb/env.h"
15
+ #include "leveldb/table_builder.h"
16
+ #include "table/merger.h"
17
+ #include "table/two_level_iterator.h"
18
+ #include "util/coding.h"
19
+ #include "util/logging.h"
20
+
21
+ namespace leveldb {
22
+
23
+ static const int kTargetFileSize = 2 * 1048576;
24
+
25
+ // Maximum bytes of overlaps in grandparent (i.e., level+2) before we
26
+ // stop building a single file in a level->level+1 compaction.
27
+ static const int64_t kMaxGrandParentOverlapBytes = 10 * kTargetFileSize;
28
+
29
+ static double MaxBytesForLevel(int level) {
30
+ // Note: the result for level zero is not really used since we set
31
+ // the level-0 compaction threshold based on number of files.
32
+ double result = 10 * 1048576.0; // Result for both level-0 and level-1
33
+ while (level > 1) {
34
+ result *= 10;
35
+ level--;
36
+ }
37
+ return result;
38
+ }
39
+
40
+ static uint64_t MaxFileSizeForLevel(int level) {
41
+ return kTargetFileSize; // We could vary per level to reduce number of files?
42
+ }
43
+
44
+ namespace {
45
+ std::string IntSetToString(const std::set<uint64_t>& s) {
46
+ std::string result = "{";
47
+ for (std::set<uint64_t>::const_iterator it = s.begin();
48
+ it != s.end();
49
+ ++it) {
50
+ result += (result.size() > 1) ? "," : "";
51
+ result += NumberToString(*it);
52
+ }
53
+ result += "}";
54
+ return result;
55
+ }
56
+ }
57
+
58
+ Version::~Version() {
59
+ assert(refs_ == 0);
60
+
61
+ // Remove from linked list
62
+ prev_->next_ = next_;
63
+ next_->prev_ = prev_;
64
+
65
+ // Drop references to files
66
+ for (int level = 0; level < config::kNumLevels; level++) {
67
+ for (size_t i = 0; i < files_[level].size(); i++) {
68
+ FileMetaData* f = files_[level][i];
69
+ assert(f->refs > 0);
70
+ f->refs--;
71
+ if (f->refs <= 0) {
72
+ delete f;
73
+ }
74
+ }
75
+ }
76
+ }
77
+
78
+ // An internal iterator. For a given version/level pair, yields
79
+ // information about the files in the level. For a given entry, key()
80
+ // is the largest key that occurs in the file, and value() is an
81
+ // 16-byte value containing the file number and file size, both
82
+ // encoded using EncodeFixed64.
83
+ class Version::LevelFileNumIterator : public Iterator {
84
+ public:
85
+ LevelFileNumIterator(const InternalKeyComparator& icmp,
86
+ const std::vector<FileMetaData*>* flist)
87
+ : icmp_(icmp),
88
+ flist_(flist),
89
+ index_(flist->size()) { // Marks as invalid
90
+ }
91
+ virtual bool Valid() const {
92
+ return index_ < flist_->size();
93
+ }
94
+ virtual void Seek(const Slice& target) {
95
+ uint32_t left = 0;
96
+ uint32_t right = flist_->size() - 1;
97
+ while (left < right) {
98
+ uint32_t mid = (left + right) / 2;
99
+ int cmp = icmp_.Compare((*flist_)[mid]->largest.Encode(), target);
100
+ if (cmp < 0) {
101
+ // Key at "mid.largest" is < than "target". Therefore all
102
+ // files at or before "mid" are uninteresting.
103
+ left = mid + 1;
104
+ } else {
105
+ // Key at "mid.largest" is >= "target". Therefore all files
106
+ // after "mid" are uninteresting.
107
+ right = mid;
108
+ }
109
+ }
110
+ index_ = left;
111
+ }
112
+ virtual void SeekToFirst() { index_ = 0; }
113
+ virtual void SeekToLast() {
114
+ index_ = flist_->empty() ? 0 : flist_->size() - 1;
115
+ }
116
+ virtual void Next() {
117
+ assert(Valid());
118
+ index_++;
119
+ }
120
+ virtual void Prev() {
121
+ assert(Valid());
122
+ if (index_ == 0) {
123
+ index_ = flist_->size(); // Marks as invalid
124
+ } else {
125
+ index_--;
126
+ }
127
+ }
128
+ Slice key() const {
129
+ assert(Valid());
130
+ return (*flist_)[index_]->largest.Encode();
131
+ }
132
+ Slice value() const {
133
+ assert(Valid());
134
+ EncodeFixed64(value_buf_, (*flist_)[index_]->number);
135
+ EncodeFixed64(value_buf_+8, (*flist_)[index_]->file_size);
136
+ return Slice(value_buf_, sizeof(value_buf_));
137
+ }
138
+ virtual Status status() const { return Status::OK(); }
139
+ private:
140
+ const InternalKeyComparator icmp_;
141
+ const std::vector<FileMetaData*>* const flist_;
142
+ uint32_t index_;
143
+
144
+ // Backing store for value(). Holds the file number and size.
145
+ mutable char value_buf_[16];
146
+ };
147
+
148
+ static Iterator* GetFileIterator(void* arg,
149
+ const ReadOptions& options,
150
+ const Slice& file_value) {
151
+ TableCache* cache = reinterpret_cast<TableCache*>(arg);
152
+ if (file_value.size() != 16) {
153
+ return NewErrorIterator(
154
+ Status::Corruption("FileReader invoked with unexpected value"));
155
+ } else {
156
+ return cache->NewIterator(options,
157
+ DecodeFixed64(file_value.data()),
158
+ DecodeFixed64(file_value.data() + 8));
159
+ }
160
+ }
161
+
162
+ Iterator* Version::NewConcatenatingIterator(const ReadOptions& options,
163
+ int level) const {
164
+ return NewTwoLevelIterator(
165
+ new LevelFileNumIterator(vset_->icmp_, &files_[level]),
166
+ &GetFileIterator, vset_->table_cache_, options);
167
+ }
168
+
169
+ void Version::AddIterators(const ReadOptions& options,
170
+ std::vector<Iterator*>* iters) {
171
+ // Merge all level zero files together since they may overlap
172
+ for (size_t i = 0; i < files_[0].size(); i++) {
173
+ iters->push_back(
174
+ vset_->table_cache_->NewIterator(
175
+ options, files_[0][i]->number, files_[0][i]->file_size));
176
+ }
177
+
178
+ // For levels > 0, we can use a concatenating iterator that sequentially
179
+ // walks through the non-overlapping files in the level, opening them
180
+ // lazily.
181
+ for (int level = 1; level < config::kNumLevels; level++) {
182
+ if (!files_[level].empty()) {
183
+ iters->push_back(NewConcatenatingIterator(options, level));
184
+ }
185
+ }
186
+ }
187
+
188
+ void Version::Ref() {
189
+ ++refs_;
190
+ }
191
+
192
+ void Version::Unref() {
193
+ assert(this != &vset_->dummy_versions_);
194
+ assert(refs_ >= 1);
195
+ --refs_;
196
+ if (refs_ == 0) {
197
+ delete this;
198
+ }
199
+ }
200
+
201
+ std::string Version::DebugString() const {
202
+ std::string r;
203
+ for (int level = 0; level < config::kNumLevels; level++) {
204
+ // E.g., level 1: 17:123['a' .. 'd'] 20:43['e' .. 'g']
205
+ r.append("level ");
206
+ AppendNumberTo(&r, level);
207
+ r.push_back(':');
208
+ const std::vector<FileMetaData*>& files = files_[level];
209
+ for (size_t i = 0; i < files.size(); i++) {
210
+ r.push_back(' ');
211
+ AppendNumberTo(&r, files[i]->number);
212
+ r.push_back(':');
213
+ AppendNumberTo(&r, files[i]->file_size);
214
+ r.append("['");
215
+ AppendEscapedStringTo(&r, files[i]->smallest.Encode());
216
+ r.append("' .. '");
217
+ AppendEscapedStringTo(&r, files[i]->largest.Encode());
218
+ r.append("']");
219
+ }
220
+ r.push_back('\n');
221
+ }
222
+ return r;
223
+ }
224
+
225
+ // A helper class so we can efficiently apply a whole sequence
226
+ // of edits to a particular state without creating intermediate
227
+ // Versions that contain full copies of the intermediate state.
228
+ class VersionSet::Builder {
229
+ private:
230
+ // Helper to sort by v->files_[file_number].smallest
231
+ struct BySmallestKey {
232
+ const InternalKeyComparator* internal_comparator;
233
+
234
+ bool operator()(FileMetaData* f1, FileMetaData* f2) const {
235
+ int r = internal_comparator->Compare(f1->smallest, f2->smallest);
236
+ if (r != 0) {
237
+ return (r < 0);
238
+ } else {
239
+ // Break ties by file number
240
+ return (f1->number < f2->number);
241
+ }
242
+ }
243
+ };
244
+
245
+ typedef std::set<FileMetaData*, BySmallestKey> FileSet;
246
+ struct LevelState {
247
+ std::set<uint64_t> deleted_files;
248
+ FileSet* added_files;
249
+ };
250
+
251
+ VersionSet* vset_;
252
+ Version* base_;
253
+ LevelState levels_[config::kNumLevels];
254
+
255
+ public:
256
+ // Initialize a builder with the files from *base and other info from *vset
257
+ Builder(VersionSet* vset, Version* base)
258
+ : vset_(vset),
259
+ base_(base) {
260
+ base_->Ref();
261
+ BySmallestKey cmp;
262
+ cmp.internal_comparator = &vset_->icmp_;
263
+ for (int level = 0; level < config::kNumLevels; level++) {
264
+ levels_[level].added_files = new FileSet(cmp);
265
+ }
266
+ }
267
+
268
+ ~Builder() {
269
+ for (int level = 0; level < config::kNumLevels; level++) {
270
+ std::vector<FileMetaData*> to_unref(levels_[level].added_files->begin(),
271
+ levels_[level].added_files->end());
272
+ delete levels_[level].added_files;
273
+ for (int i = 0; i < to_unref.size(); i++) {
274
+ FileMetaData* f = to_unref[i];
275
+ f->refs--;
276
+ if (f->refs <= 0) {
277
+ delete f;
278
+ }
279
+ }
280
+ }
281
+ base_->Unref();
282
+ }
283
+
284
+ // Apply all of the edits in *edit to the current state.
285
+ void Apply(VersionEdit* edit) {
286
+ // Update compaction pointers
287
+ for (size_t i = 0; i < edit->compact_pointers_.size(); i++) {
288
+ const int level = edit->compact_pointers_[i].first;
289
+ vset_->compact_pointer_[level] =
290
+ edit->compact_pointers_[i].second.Encode().ToString();
291
+ }
292
+
293
+ // Delete files
294
+ const VersionEdit::DeletedFileSet& del = edit->deleted_files_;
295
+ for (VersionEdit::DeletedFileSet::const_iterator iter = del.begin();
296
+ iter != del.end();
297
+ ++iter) {
298
+ const int level = iter->first;
299
+ const uint64_t number = iter->second;
300
+ levels_[level].deleted_files.insert(number);
301
+ }
302
+
303
+ // Add new files
304
+ for (size_t i = 0; i < edit->new_files_.size(); i++) {
305
+ const int level = edit->new_files_[i].first;
306
+ FileMetaData* f = new FileMetaData(edit->new_files_[i].second);
307
+ f->refs = 1;
308
+ levels_[level].deleted_files.erase(f->number);
309
+ levels_[level].added_files->insert(f);
310
+ }
311
+ }
312
+
313
+ // Save the current state in *v.
314
+ void SaveTo(Version* v) {
315
+ BySmallestKey cmp;
316
+ cmp.internal_comparator = &vset_->icmp_;
317
+ for (int level = 0; level < config::kNumLevels; level++) {
318
+ // Merge the set of added files with the set of pre-existing files.
319
+ // Drop any deleted files. Store the result in *v.
320
+ const std::vector<FileMetaData*>& base_files = base_->files_[level];
321
+ std::vector<FileMetaData*>::const_iterator base_iter = base_files.begin();
322
+ std::vector<FileMetaData*>::const_iterator base_end = base_files.end();
323
+ const FileSet* added = levels_[level].added_files;
324
+ v->files_[level].reserve(base_files.size() + added->size());
325
+ for (FileSet::const_iterator added_iter = added->begin();
326
+ added_iter != added->end();
327
+ ++added_iter) {
328
+ // Add all smaller files listed in base_
329
+ for (std::vector<FileMetaData*>::const_iterator bpos
330
+ = std::upper_bound(base_iter, base_end, *added_iter, cmp);
331
+ base_iter != bpos;
332
+ ++base_iter) {
333
+ MaybeAddFile(v, level, *base_iter);
334
+ }
335
+
336
+ MaybeAddFile(v, level, *added_iter);
337
+ }
338
+
339
+ // Add remaining base files
340
+ for (; base_iter != base_end; ++base_iter) {
341
+ MaybeAddFile(v, level, *base_iter);
342
+ }
343
+
344
+ #ifndef NDEBUG
345
+ // Make sure there is no overlap in levels > 0
346
+ if (level > 0) {
347
+ for (int i = 1; i < v->files_[level].size(); i++) {
348
+ const InternalKey& prev_end = v->files_[level][i-1]->largest;
349
+ const InternalKey& this_begin = v->files_[level][i]->smallest;
350
+ if (vset_->icmp_.Compare(prev_end, this_begin) >= 0) {
351
+ fprintf(stderr, "overlapping ranges in same level %s vs. %s\n",
352
+ EscapeString(prev_end.Encode()).c_str(),
353
+ EscapeString(this_begin.Encode()).c_str());
354
+ abort();
355
+ }
356
+ }
357
+ }
358
+ #endif
359
+ }
360
+ }
361
+
362
+ void MaybeAddFile(Version* v, int level, FileMetaData* f) {
363
+ if (levels_[level].deleted_files.count(f->number) > 0) {
364
+ // File is deleted: do nothing
365
+ } else {
366
+ f->refs++;
367
+ v->files_[level].push_back(f);
368
+ }
369
+ }
370
+ };
371
+
372
+ VersionSet::VersionSet(const std::string& dbname,
373
+ const Options* options,
374
+ TableCache* table_cache,
375
+ const InternalKeyComparator* cmp)
376
+ : env_(options->env),
377
+ dbname_(dbname),
378
+ options_(options),
379
+ table_cache_(table_cache),
380
+ icmp_(*cmp),
381
+ next_file_number_(2),
382
+ manifest_file_number_(0), // Filled by Recover()
383
+ last_sequence_(0),
384
+ log_number_(0),
385
+ prev_log_number_(0),
386
+ descriptor_file_(NULL),
387
+ descriptor_log_(NULL),
388
+ dummy_versions_(this),
389
+ current_(NULL) {
390
+ AppendVersion(new Version(this));
391
+ }
392
+
393
+ VersionSet::~VersionSet() {
394
+ current_->Unref();
395
+ assert(dummy_versions_.next_ == &dummy_versions_); // List must be empty
396
+ delete descriptor_log_;
397
+ delete descriptor_file_;
398
+ }
399
+
400
+ void VersionSet::AppendVersion(Version* v) {
401
+ // Make "v" current
402
+ assert(v->refs_ == 0);
403
+ assert(v != current_);
404
+ if (current_ != NULL) {
405
+ current_->Unref();
406
+ }
407
+ current_ = v;
408
+ v->Ref();
409
+
410
+ // Append to linked list
411
+ v->prev_ = dummy_versions_.prev_;
412
+ v->next_ = &dummy_versions_;
413
+ v->prev_->next_ = v;
414
+ v->next_->prev_ = v;
415
+ }
416
+
417
+ Status VersionSet::LogAndApply(VersionEdit* edit) {
418
+ if (edit->has_log_number_) {
419
+ assert(edit->log_number_ >= log_number_);
420
+ assert(edit->log_number_ < next_file_number_);
421
+ } else {
422
+ edit->SetLogNumber(log_number_);
423
+ }
424
+
425
+ if (!edit->has_prev_log_number_) {
426
+ edit->SetPrevLogNumber(prev_log_number_);
427
+ }
428
+
429
+ edit->SetNextFile(next_file_number_);
430
+ edit->SetLastSequence(last_sequence_);
431
+
432
+ Version* v = new Version(this);
433
+ {
434
+ Builder builder(this, current_);
435
+ builder.Apply(edit);
436
+ builder.SaveTo(v);
437
+ }
438
+ Finalize(v);
439
+
440
+ // Initialize new descriptor log file if necessary by creating
441
+ // a temporary file that contains a snapshot of the current version.
442
+ std::string new_manifest_file;
443
+ Status s;
444
+ if (descriptor_log_ == NULL) {
445
+ assert(descriptor_file_ == NULL);
446
+ new_manifest_file = DescriptorFileName(dbname_, manifest_file_number_);
447
+ edit->SetNextFile(next_file_number_);
448
+ s = env_->NewWritableFile(new_manifest_file, &descriptor_file_);
449
+ if (s.ok()) {
450
+ descriptor_log_ = new log::Writer(descriptor_file_);
451
+ s = WriteSnapshot(descriptor_log_);
452
+ }
453
+ }
454
+
455
+ // Write new record to MANIFEST log
456
+ if (s.ok()) {
457
+ std::string record;
458
+ edit->EncodeTo(&record);
459
+ s = descriptor_log_->AddRecord(record);
460
+ if (s.ok()) {
461
+ s = descriptor_file_->Sync();
462
+ }
463
+ }
464
+
465
+ // If we just created a new descriptor file, install it by writing a
466
+ // new CURRENT file that points to it.
467
+ if (s.ok() && !new_manifest_file.empty()) {
468
+ s = SetCurrentFile(env_, dbname_, manifest_file_number_);
469
+ }
470
+
471
+ // Install the new version
472
+ if (s.ok()) {
473
+ AppendVersion(v);
474
+ log_number_ = edit->log_number_;
475
+ prev_log_number_ = edit->prev_log_number_;
476
+ } else {
477
+ delete v;
478
+ if (!new_manifest_file.empty()) {
479
+ delete descriptor_log_;
480
+ delete descriptor_file_;
481
+ descriptor_log_ = NULL;
482
+ descriptor_file_ = NULL;
483
+ env_->DeleteFile(new_manifest_file);
484
+ }
485
+ }
486
+
487
+ return s;
488
+ }
489
+
490
+ Status VersionSet::Recover() {
491
+ struct LogReporter : public log::Reader::Reporter {
492
+ Status* status;
493
+ virtual void Corruption(size_t bytes, const Status& s) {
494
+ if (this->status->ok()) *this->status = s;
495
+ }
496
+ };
497
+
498
+ // Read "CURRENT" file, which contains a pointer to the current manifest file
499
+ std::string current;
500
+ Status s = ReadFileToString(env_, CurrentFileName(dbname_), &current);
501
+ if (!s.ok()) {
502
+ return s;
503
+ }
504
+ if (current.empty() || current[current.size()-1] != '\n') {
505
+ return Status::Corruption("CURRENT file does not end with newline");
506
+ }
507
+ current.resize(current.size() - 1);
508
+
509
+ std::string dscname = dbname_ + "/" + current;
510
+ SequentialFile* file;
511
+ s = env_->NewSequentialFile(dscname, &file);
512
+ if (!s.ok()) {
513
+ return s;
514
+ }
515
+
516
+ bool have_log_number = false;
517
+ bool have_prev_log_number = false;
518
+ bool have_next_file = false;
519
+ bool have_last_sequence = false;
520
+ uint64_t next_file = 0;
521
+ uint64_t last_sequence = 0;
522
+ uint64_t log_number = 0;
523
+ uint64_t prev_log_number = 0;
524
+ Builder builder(this, current_);
525
+
526
+ {
527
+ LogReporter reporter;
528
+ reporter.status = &s;
529
+ log::Reader reader(file, &reporter, true/*checksum*/, 0/*initial_offset*/);
530
+ Slice record;
531
+ std::string scratch;
532
+ while (reader.ReadRecord(&record, &scratch) && s.ok()) {
533
+ VersionEdit edit;
534
+ s = edit.DecodeFrom(record);
535
+ if (s.ok()) {
536
+ if (edit.has_comparator_ &&
537
+ edit.comparator_ != icmp_.user_comparator()->Name()) {
538
+ s = Status::InvalidArgument(
539
+ edit.comparator_ + "does not match existing comparator ",
540
+ icmp_.user_comparator()->Name());
541
+ }
542
+ }
543
+
544
+ if (s.ok()) {
545
+ builder.Apply(&edit);
546
+ }
547
+
548
+ if (edit.has_log_number_) {
549
+ log_number = edit.log_number_;
550
+ have_log_number = true;
551
+ }
552
+
553
+ if (edit.has_prev_log_number_) {
554
+ prev_log_number = edit.prev_log_number_;
555
+ have_prev_log_number = true;
556
+ }
557
+
558
+ if (edit.has_next_file_number_) {
559
+ next_file = edit.next_file_number_;
560
+ have_next_file = true;
561
+ }
562
+
563
+ if (edit.has_last_sequence_) {
564
+ last_sequence = edit.last_sequence_;
565
+ have_last_sequence = true;
566
+ }
567
+ }
568
+ }
569
+ delete file;
570
+ file = NULL;
571
+
572
+ if (s.ok()) {
573
+ if (!have_next_file) {
574
+ s = Status::Corruption("no meta-nextfile entry in descriptor");
575
+ } else if (!have_log_number) {
576
+ s = Status::Corruption("no meta-lognumber entry in descriptor");
577
+ } else if (!have_last_sequence) {
578
+ s = Status::Corruption("no last-sequence-number entry in descriptor");
579
+ }
580
+
581
+ if (!have_prev_log_number) {
582
+ prev_log_number = 0;
583
+ }
584
+ }
585
+
586
+ if (s.ok()) {
587
+ Version* v = new Version(this);
588
+ builder.SaveTo(v);
589
+ // Install recovered version
590
+ Finalize(v);
591
+ AppendVersion(v);
592
+ manifest_file_number_ = next_file;
593
+ next_file_number_ = next_file + 1;
594
+ last_sequence_ = last_sequence;
595
+ log_number_ = log_number;
596
+ prev_log_number_ = prev_log_number;
597
+ }
598
+
599
+ return s;
600
+ }
601
+
602
+ static int64_t TotalFileSize(const std::vector<FileMetaData*>& files) {
603
+ int64_t sum = 0;
604
+ for (size_t i = 0; i < files.size(); i++) {
605
+ sum += files[i]->file_size;
606
+ }
607
+ return sum;
608
+ }
609
+
610
+ void VersionSet::Finalize(Version* v) {
611
+ // Precomputed best level for next compaction
612
+ int best_level = -1;
613
+ double best_score = -1;
614
+
615
+ for (int level = 0; level < config::kNumLevels-1; level++) {
616
+ double score;
617
+ if (level == 0) {
618
+ // We treat level-0 specially by bounding the number of files
619
+ // instead of number of bytes for two reasons:
620
+ //
621
+ // (1) With larger write-buffer sizes, it is nice not to do too
622
+ // many level-0 compactions.
623
+ //
624
+ // (2) The files in level-0 are merged on every read and
625
+ // therefore we wish to avoid too many files when the individual
626
+ // file size is small (perhaps because of a small write-buffer
627
+ // setting, or very high compression ratios, or lots of
628
+ // overwrites/deletions).
629
+ score = v->files_[level].size() /
630
+ static_cast<double>(config::kL0_CompactionTrigger);
631
+ } else {
632
+ // Compute the ratio of current size to size limit.
633
+ const uint64_t level_bytes = TotalFileSize(v->files_[level]);
634
+ score = static_cast<double>(level_bytes) / MaxBytesForLevel(level);
635
+ }
636
+
637
+ if (score > best_score) {
638
+ best_level = level;
639
+ best_score = score;
640
+ }
641
+ }
642
+
643
+ v->compaction_level_ = best_level;
644
+ v->compaction_score_ = best_score;
645
+ }
646
+
647
+ Status VersionSet::WriteSnapshot(log::Writer* log) {
648
+ // TODO: Break up into multiple records to reduce memory usage on recovery?
649
+
650
+ // Save metadata
651
+ VersionEdit edit;
652
+ edit.SetComparatorName(icmp_.user_comparator()->Name());
653
+
654
+ // Save compaction pointers
655
+ for (int level = 0; level < config::kNumLevels; level++) {
656
+ if (!compact_pointer_[level].empty()) {
657
+ InternalKey key;
658
+ key.DecodeFrom(compact_pointer_[level]);
659
+ edit.SetCompactPointer(level, key);
660
+ }
661
+ }
662
+
663
+ // Save files
664
+ for (int level = 0; level < config::kNumLevels; level++) {
665
+ const std::vector<FileMetaData*>& files = current_->files_[level];
666
+ for (size_t i = 0; i < files.size(); i++) {
667
+ const FileMetaData* f = files[i];
668
+ edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest);
669
+ }
670
+ }
671
+
672
+ std::string record;
673
+ edit.EncodeTo(&record);
674
+ return log->AddRecord(record);
675
+ }
676
+
677
+ int VersionSet::NumLevelFiles(int level) const {
678
+ assert(level >= 0);
679
+ assert(level < config::kNumLevels);
680
+ return current_->files_[level].size();
681
+ }
682
+
683
+ const char* VersionSet::LevelSummary(LevelSummaryStorage* scratch) const {
684
+ // Update code if kNumLevels changes
685
+ assert(config::kNumLevels == 7);
686
+ snprintf(scratch->buffer, sizeof(scratch->buffer),
687
+ "files[ %d %d %d %d %d %d %d ]",
688
+ int(current_->files_[0].size()),
689
+ int(current_->files_[1].size()),
690
+ int(current_->files_[2].size()),
691
+ int(current_->files_[3].size()),
692
+ int(current_->files_[4].size()),
693
+ int(current_->files_[5].size()),
694
+ int(current_->files_[6].size()));
695
+ return scratch->buffer;
696
+ }
697
+
698
+ uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) {
699
+ uint64_t result = 0;
700
+ for (int level = 0; level < config::kNumLevels; level++) {
701
+ const std::vector<FileMetaData*>& files = v->files_[level];
702
+ for (size_t i = 0; i < files.size(); i++) {
703
+ if (icmp_.Compare(files[i]->largest, ikey) <= 0) {
704
+ // Entire file is before "ikey", so just add the file size
705
+ result += files[i]->file_size;
706
+ } else if (icmp_.Compare(files[i]->smallest, ikey) > 0) {
707
+ // Entire file is after "ikey", so ignore
708
+ if (level > 0) {
709
+ // Files other than level 0 are sorted by meta->smallest, so
710
+ // no further files in this level will contain data for
711
+ // "ikey".
712
+ break;
713
+ }
714
+ } else {
715
+ // "ikey" falls in the range for this table. Add the
716
+ // approximate offset of "ikey" within the table.
717
+ Table* tableptr;
718
+ Iterator* iter = table_cache_->NewIterator(
719
+ ReadOptions(), files[i]->number, files[i]->file_size, &tableptr);
720
+ if (tableptr != NULL) {
721
+ result += tableptr->ApproximateOffsetOf(ikey.Encode());
722
+ }
723
+ delete iter;
724
+ }
725
+ }
726
+ }
727
+ return result;
728
+ }
729
+
730
+ void VersionSet::AddLiveFiles(std::set<uint64_t>* live) {
731
+ for (Version* v = dummy_versions_.next_;
732
+ v != &dummy_versions_;
733
+ v = v->next_) {
734
+ for (int level = 0; level < config::kNumLevels; level++) {
735
+ const std::vector<FileMetaData*>& files = v->files_[level];
736
+ for (size_t i = 0; i < files.size(); i++) {
737
+ live->insert(files[i]->number);
738
+ }
739
+ }
740
+ }
741
+ }
742
+
743
+ int64_t VersionSet::NumLevelBytes(int level) const {
744
+ assert(level >= 0);
745
+ assert(level < config::kNumLevels);
746
+ return TotalFileSize(current_->files_[level]);
747
+ }
748
+
749
+ int64_t VersionSet::MaxNextLevelOverlappingBytes() {
750
+ int64_t result = 0;
751
+ std::vector<FileMetaData*> overlaps;
752
+ for (int level = 0; level < config::kNumLevels - 1; level++) {
753
+ for (size_t i = 0; i < current_->files_[level].size(); i++) {
754
+ const FileMetaData* f = current_->files_[level][i];
755
+ GetOverlappingInputs(level+1, f->smallest, f->largest, &overlaps);
756
+ const int64_t sum = TotalFileSize(overlaps);
757
+ if (sum > result) {
758
+ result = sum;
759
+ }
760
+ }
761
+ }
762
+ return result;
763
+ }
764
+
765
+ // Store in "*inputs" all files in "level" that overlap [begin,end]
766
+ void VersionSet::GetOverlappingInputs(
767
+ int level,
768
+ const InternalKey& begin,
769
+ const InternalKey& end,
770
+ std::vector<FileMetaData*>* inputs) {
771
+ inputs->clear();
772
+ Slice user_begin = begin.user_key();
773
+ Slice user_end = end.user_key();
774
+ const Comparator* user_cmp = icmp_.user_comparator();
775
+ for (size_t i = 0; i < current_->files_[level].size(); i++) {
776
+ FileMetaData* f = current_->files_[level][i];
777
+ if (user_cmp->Compare(f->largest.user_key(), user_begin) < 0 ||
778
+ user_cmp->Compare(f->smallest.user_key(), user_end) > 0) {
779
+ // Either completely before or after range; skip it
780
+ } else {
781
+ inputs->push_back(f);
782
+ }
783
+ }
784
+ }
785
+
786
+ // Stores the minimal range that covers all entries in inputs in
787
+ // *smallest, *largest.
788
+ // REQUIRES: inputs is not empty
789
+ void VersionSet::GetRange(const std::vector<FileMetaData*>& inputs,
790
+ InternalKey* smallest,
791
+ InternalKey* largest) {
792
+ assert(!inputs.empty());
793
+ smallest->Clear();
794
+ largest->Clear();
795
+ for (size_t i = 0; i < inputs.size(); i++) {
796
+ FileMetaData* f = inputs[i];
797
+ if (i == 0) {
798
+ *smallest = f->smallest;
799
+ *largest = f->largest;
800
+ } else {
801
+ if (icmp_.Compare(f->smallest, *smallest) < 0) {
802
+ *smallest = f->smallest;
803
+ }
804
+ if (icmp_.Compare(f->largest, *largest) > 0) {
805
+ *largest = f->largest;
806
+ }
807
+ }
808
+ }
809
+ }
810
+
811
+ // Stores the minimal range that covers all entries in inputs1 and inputs2
812
+ // in *smallest, *largest.
813
+ // REQUIRES: inputs is not empty
814
+ void VersionSet::GetRange2(const std::vector<FileMetaData*>& inputs1,
815
+ const std::vector<FileMetaData*>& inputs2,
816
+ InternalKey* smallest,
817
+ InternalKey* largest) {
818
+ std::vector<FileMetaData*> all = inputs1;
819
+ all.insert(all.end(), inputs2.begin(), inputs2.end());
820
+ GetRange(all, smallest, largest);
821
+ }
822
+
823
+ Iterator* VersionSet::MakeInputIterator(Compaction* c) {
824
+ ReadOptions options;
825
+ options.verify_checksums = options_->paranoid_checks;
826
+ options.fill_cache = false;
827
+
828
+ // Level-0 files have to be merged together. For other levels,
829
+ // we will make a concatenating iterator per level.
830
+ // TODO(opt): use concatenating iterator for level-0 if there is no overlap
831
+ const int space = (c->level() == 0 ? c->inputs_[0].size() + 1 : 2);
832
+ Iterator** list = new Iterator*[space];
833
+ int num = 0;
834
+ for (int which = 0; which < 2; which++) {
835
+ if (!c->inputs_[which].empty()) {
836
+ if (c->level() + which == 0) {
837
+ const std::vector<FileMetaData*>& files = c->inputs_[which];
838
+ for (size_t i = 0; i < files.size(); i++) {
839
+ list[num++] = table_cache_->NewIterator(
840
+ options, files[i]->number, files[i]->file_size);
841
+ }
842
+ } else {
843
+ // Create concatenating iterator for the files from this level
844
+ list[num++] = NewTwoLevelIterator(
845
+ new Version::LevelFileNumIterator(icmp_, &c->inputs_[which]),
846
+ &GetFileIterator, table_cache_, options);
847
+ }
848
+ }
849
+ }
850
+ assert(num <= space);
851
+ Iterator* result = NewMergingIterator(&icmp_, list, num);
852
+ delete[] list;
853
+ return result;
854
+ }
855
+
856
+ Compaction* VersionSet::PickCompaction() {
857
+ if (!NeedsCompaction()) {
858
+ return NULL;
859
+ }
860
+ const int level = current_->compaction_level_;
861
+ assert(level >= 0);
862
+ assert(level+1 < config::kNumLevels);
863
+
864
+ Compaction* c = new Compaction(level);
865
+ c->input_version_ = current_;
866
+ c->input_version_->Ref();
867
+
868
+ // Pick the first file that comes after compact_pointer_[level]
869
+ for (size_t i = 0; i < current_->files_[level].size(); i++) {
870
+ FileMetaData* f = current_->files_[level][i];
871
+ if (compact_pointer_[level].empty() ||
872
+ icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) {
873
+ c->inputs_[0].push_back(f);
874
+ break;
875
+ }
876
+ }
877
+ if (c->inputs_[0].empty()) {
878
+ // Wrap-around to the beginning of the key space
879
+ c->inputs_[0].push_back(current_->files_[level][0]);
880
+ }
881
+
882
+ // Files in level 0 may overlap each other, so pick up all overlapping ones
883
+ if (level == 0) {
884
+ InternalKey smallest, largest;
885
+ GetRange(c->inputs_[0], &smallest, &largest);
886
+ // Note that the next call will discard the file we placed in
887
+ // c->inputs_[0] earlier and replace it with an overlapping set
888
+ // which will include the picked file.
889
+ GetOverlappingInputs(0, smallest, largest, &c->inputs_[0]);
890
+ assert(!c->inputs_[0].empty());
891
+ }
892
+
893
+ SetupOtherInputs(c);
894
+
895
+ return c;
896
+ }
897
+
898
+ void VersionSet::SetupOtherInputs(Compaction* c) {
899
+ const int level = c->level();
900
+ InternalKey smallest, largest;
901
+ GetRange(c->inputs_[0], &smallest, &largest);
902
+
903
+ GetOverlappingInputs(level+1, smallest, largest, &c->inputs_[1]);
904
+
905
+ // Get entire range covered by compaction
906
+ InternalKey all_start, all_limit;
907
+ GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit);
908
+
909
+ // See if we can grow the number of inputs in "level" without
910
+ // changing the number of "level+1" files we pick up.
911
+ if (!c->inputs_[1].empty()) {
912
+ std::vector<FileMetaData*> expanded0;
913
+ GetOverlappingInputs(level, all_start, all_limit, &expanded0);
914
+ if (expanded0.size() > c->inputs_[0].size()) {
915
+ InternalKey new_start, new_limit;
916
+ GetRange(expanded0, &new_start, &new_limit);
917
+ std::vector<FileMetaData*> expanded1;
918
+ GetOverlappingInputs(level+1, new_start, new_limit, &expanded1);
919
+ if (expanded1.size() == c->inputs_[1].size()) {
920
+ Log(env_, options_->info_log,
921
+ "Expanding@%d %d+%d to %d+%d\n",
922
+ level,
923
+ int(c->inputs_[0].size()),
924
+ int(c->inputs_[1].size()),
925
+ int(expanded0.size()),
926
+ int(expanded1.size()));
927
+ smallest = new_start;
928
+ largest = new_limit;
929
+ c->inputs_[0] = expanded0;
930
+ c->inputs_[1] = expanded1;
931
+ GetRange2(c->inputs_[0], c->inputs_[1], &all_start, &all_limit);
932
+ }
933
+ }
934
+ }
935
+
936
+ // Compute the set of grandparent files that overlap this compaction
937
+ // (parent == level+1; grandparent == level+2)
938
+ if (level + 2 < config::kNumLevels) {
939
+ GetOverlappingInputs(level + 2, all_start, all_limit, &c->grandparents_);
940
+ }
941
+
942
+ if (false) {
943
+ Log(env_, options_->info_log, "Compacting %d '%s' .. '%s'",
944
+ level,
945
+ EscapeString(smallest.Encode()).c_str(),
946
+ EscapeString(largest.Encode()).c_str());
947
+ }
948
+
949
+ // Update the place where we will do the next compaction for this level.
950
+ // We update this immediately instead of waiting for the VersionEdit
951
+ // to be applied so that if the compaction fails, we will try a different
952
+ // key range next time.
953
+ compact_pointer_[level] = largest.Encode().ToString();
954
+ c->edit_.SetCompactPointer(level, largest);
955
+ }
956
+
957
+ Compaction* VersionSet::CompactRange(
958
+ int level,
959
+ const InternalKey& begin,
960
+ const InternalKey& end) {
961
+ std::vector<FileMetaData*> inputs;
962
+ GetOverlappingInputs(level, begin, end, &inputs);
963
+ if (inputs.empty()) {
964
+ return NULL;
965
+ }
966
+
967
+ Compaction* c = new Compaction(level);
968
+ c->input_version_ = current_;
969
+ c->input_version_->Ref();
970
+ c->inputs_[0] = inputs;
971
+ SetupOtherInputs(c);
972
+ return c;
973
+ }
974
+
975
+ Compaction::Compaction(int level)
976
+ : level_(level),
977
+ max_output_file_size_(MaxFileSizeForLevel(level)),
978
+ input_version_(NULL),
979
+ grandparent_index_(0),
980
+ seen_key_(false),
981
+ overlapped_bytes_(0) {
982
+ for (int i = 0; i < config::kNumLevels; i++) {
983
+ level_ptrs_[i] = 0;
984
+ }
985
+ }
986
+
987
+ Compaction::~Compaction() {
988
+ if (input_version_ != NULL) {
989
+ input_version_->Unref();
990
+ }
991
+ }
992
+
993
+ bool Compaction::IsTrivialMove() const {
994
+ // Avoid a move if there is lots of overlapping grandparent data.
995
+ // Otherwise, the move could create a parent file that will require
996
+ // a very expensive merge later on.
997
+ return (num_input_files(0) == 1 &&
998
+ num_input_files(1) == 0 &&
999
+ TotalFileSize(grandparents_) <= kMaxGrandParentOverlapBytes);
1000
+ }
1001
+
1002
+ void Compaction::AddInputDeletions(VersionEdit* edit) {
1003
+ for (int which = 0; which < 2; which++) {
1004
+ for (size_t i = 0; i < inputs_[which].size(); i++) {
1005
+ edit->DeleteFile(level_ + which, inputs_[which][i]->number);
1006
+ }
1007
+ }
1008
+ }
1009
+
1010
+ bool Compaction::IsBaseLevelForKey(const Slice& user_key) {
1011
+ // Maybe use binary search to find right entry instead of linear search?
1012
+ const Comparator* user_cmp = input_version_->vset_->icmp_.user_comparator();
1013
+ for (int lvl = level_ + 2; lvl < config::kNumLevels; lvl++) {
1014
+ const std::vector<FileMetaData*>& files = input_version_->files_[lvl];
1015
+ for (; level_ptrs_[lvl] < files.size(); ) {
1016
+ FileMetaData* f = files[level_ptrs_[lvl]];
1017
+ if (user_cmp->Compare(user_key, f->largest.user_key()) <= 0) {
1018
+ // We've advanced far enough
1019
+ if (user_cmp->Compare(user_key, f->smallest.user_key()) >= 0) {
1020
+ // Key falls in this file's range, so definitely not base level
1021
+ return false;
1022
+ }
1023
+ break;
1024
+ }
1025
+ level_ptrs_[lvl]++;
1026
+ }
1027
+ }
1028
+ return true;
1029
+ }
1030
+
1031
+ bool Compaction::ShouldStopBefore(const Slice& internal_key) {
1032
+ // Scan to find earliest grandparent file that contains key.
1033
+ const InternalKeyComparator* icmp = &input_version_->vset_->icmp_;
1034
+ while (grandparent_index_ < grandparents_.size() &&
1035
+ icmp->Compare(internal_key,
1036
+ grandparents_[grandparent_index_]->largest.Encode()) > 0) {
1037
+ if (seen_key_) {
1038
+ overlapped_bytes_ += grandparents_[grandparent_index_]->file_size;
1039
+ }
1040
+ grandparent_index_++;
1041
+ }
1042
+ seen_key_ = true;
1043
+
1044
+ if (overlapped_bytes_ > kMaxGrandParentOverlapBytes) {
1045
+ // Too much overlap for current output; start new output
1046
+ overlapped_bytes_ = 0;
1047
+ return true;
1048
+ } else {
1049
+ return false;
1050
+ }
1051
+ }
1052
+
1053
+ void Compaction::ReleaseInputs() {
1054
+ if (input_version_ != NULL) {
1055
+ input_version_->Unref();
1056
+ input_version_ = NULL;
1057
+ }
1058
+ }
1059
+
1060
+ }