leveldb-ruby 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }