filiptepper-leveldb-ruby 0.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/LICENSE +24 -0
  2. data/README +72 -0
  3. data/ext/leveldb/extconf.rb +14 -0
  4. data/ext/leveldb/leveldb.cc +530 -0
  5. data/ext/leveldb/platform.rb +83 -0
  6. data/leveldb/Makefile +191 -0
  7. data/leveldb/build_detect_platform +160 -0
  8. data/leveldb/db/builder.cc +88 -0
  9. data/leveldb/db/builder.h +34 -0
  10. data/leveldb/db/c.cc +581 -0
  11. data/leveldb/db/corruption_test.cc +359 -0
  12. data/leveldb/db/db_bench.cc +970 -0
  13. data/leveldb/db/db_impl.cc +1448 -0
  14. data/leveldb/db/db_impl.h +194 -0
  15. data/leveldb/db/db_iter.cc +299 -0
  16. data/leveldb/db/db_iter.h +26 -0
  17. data/leveldb/db/db_test.cc +1901 -0
  18. data/leveldb/db/dbformat.cc +140 -0
  19. data/leveldb/db/dbformat.h +227 -0
  20. data/leveldb/db/dbformat_test.cc +112 -0
  21. data/leveldb/db/filename.cc +139 -0
  22. data/leveldb/db/filename.h +80 -0
  23. data/leveldb/db/filename_test.cc +122 -0
  24. data/leveldb/db/log_format.h +35 -0
  25. data/leveldb/db/log_reader.cc +259 -0
  26. data/leveldb/db/log_reader.h +108 -0
  27. data/leveldb/db/log_test.cc +500 -0
  28. data/leveldb/db/log_writer.cc +103 -0
  29. data/leveldb/db/log_writer.h +48 -0
  30. data/leveldb/db/memtable.cc +145 -0
  31. data/leveldb/db/memtable.h +91 -0
  32. data/leveldb/db/repair.cc +389 -0
  33. data/leveldb/db/skiplist.h +379 -0
  34. data/leveldb/db/skiplist_test.cc +378 -0
  35. data/leveldb/db/snapshot.h +66 -0
  36. data/leveldb/db/table_cache.cc +121 -0
  37. data/leveldb/db/table_cache.h +61 -0
  38. data/leveldb/db/version_edit.cc +266 -0
  39. data/leveldb/db/version_edit.h +107 -0
  40. data/leveldb/db/version_edit_test.cc +46 -0
  41. data/leveldb/db/version_set.cc +1402 -0
  42. data/leveldb/db/version_set.h +370 -0
  43. data/leveldb/db/version_set_test.cc +179 -0
  44. data/leveldb/db/write_batch.cc +147 -0
  45. data/leveldb/db/write_batch_internal.h +49 -0
  46. data/leveldb/db/write_batch_test.cc +120 -0
  47. data/leveldb/helpers/memenv/memenv.cc +374 -0
  48. data/leveldb/helpers/memenv/memenv.h +20 -0
  49. data/leveldb/helpers/memenv/memenv_test.cc +232 -0
  50. data/leveldb/include/leveldb/c.h +275 -0
  51. data/leveldb/include/leveldb/cache.h +99 -0
  52. data/leveldb/include/leveldb/comparator.h +63 -0
  53. data/leveldb/include/leveldb/db.h +161 -0
  54. data/leveldb/include/leveldb/env.h +323 -0
  55. data/leveldb/include/leveldb/filter_policy.h +70 -0
  56. data/leveldb/include/leveldb/iterator.h +100 -0
  57. data/leveldb/include/leveldb/options.h +195 -0
  58. data/leveldb/include/leveldb/slice.h +109 -0
  59. data/leveldb/include/leveldb/status.h +106 -0
  60. data/leveldb/include/leveldb/table.h +85 -0
  61. data/leveldb/include/leveldb/table_builder.h +92 -0
  62. data/leveldb/include/leveldb/write_batch.h +64 -0
  63. data/leveldb/port/atomic_pointer.h +144 -0
  64. data/leveldb/port/port.h +21 -0
  65. data/leveldb/port/port_android.cc +64 -0
  66. data/leveldb/port/port_android.h +159 -0
  67. data/leveldb/port/port_example.h +125 -0
  68. data/leveldb/port/port_posix.cc +50 -0
  69. data/leveldb/port/port_posix.h +129 -0
  70. data/leveldb/port/win/stdint.h +24 -0
  71. data/leveldb/table/block.cc +267 -0
  72. data/leveldb/table/block.h +44 -0
  73. data/leveldb/table/block_builder.cc +109 -0
  74. data/leveldb/table/block_builder.h +57 -0
  75. data/leveldb/table/filter_block.cc +111 -0
  76. data/leveldb/table/filter_block.h +68 -0
  77. data/leveldb/table/filter_block_test.cc +128 -0
  78. data/leveldb/table/format.cc +145 -0
  79. data/leveldb/table/format.h +108 -0
  80. data/leveldb/table/iterator.cc +67 -0
  81. data/leveldb/table/iterator_wrapper.h +63 -0
  82. data/leveldb/table/merger.cc +197 -0
  83. data/leveldb/table/merger.h +26 -0
  84. data/leveldb/table/table.cc +276 -0
  85. data/leveldb/table/table_builder.cc +270 -0
  86. data/leveldb/table/table_test.cc +838 -0
  87. data/leveldb/table/two_level_iterator.cc +182 -0
  88. data/leveldb/table/two_level_iterator.h +34 -0
  89. data/leveldb/util/arena.cc +68 -0
  90. data/leveldb/util/arena.h +68 -0
  91. data/leveldb/util/arena_test.cc +68 -0
  92. data/leveldb/util/bloom.cc +95 -0
  93. data/leveldb/util/bloom_test.cc +159 -0
  94. data/leveldb/util/cache.cc +328 -0
  95. data/leveldb/util/cache_test.cc +186 -0
  96. data/leveldb/util/coding.cc +194 -0
  97. data/leveldb/util/coding.h +104 -0
  98. data/leveldb/util/coding_test.cc +173 -0
  99. data/leveldb/util/comparator.cc +76 -0
  100. data/leveldb/util/crc32c.cc +332 -0
  101. data/leveldb/util/crc32c.h +45 -0
  102. data/leveldb/util/crc32c_test.cc +72 -0
  103. data/leveldb/util/env.cc +96 -0
  104. data/leveldb/util/env_posix.cc +609 -0
  105. data/leveldb/util/env_test.cc +104 -0
  106. data/leveldb/util/filter_policy.cc +11 -0
  107. data/leveldb/util/hash.cc +45 -0
  108. data/leveldb/util/hash.h +19 -0
  109. data/leveldb/util/histogram.cc +139 -0
  110. data/leveldb/util/histogram.h +42 -0
  111. data/leveldb/util/logging.cc +81 -0
  112. data/leveldb/util/logging.h +47 -0
  113. data/leveldb/util/mutexlock.h +39 -0
  114. data/leveldb/util/options.cc +29 -0
  115. data/leveldb/util/posix_logger.h +98 -0
  116. data/leveldb/util/random.h +59 -0
  117. data/leveldb/util/status.cc +75 -0
  118. data/leveldb/util/testharness.cc +77 -0
  119. data/leveldb/util/testharness.h +138 -0
  120. data/leveldb/util/testutil.cc +51 -0
  121. data/leveldb/util/testutil.h +53 -0
  122. data/lib/leveldb.rb +76 -0
  123. metadata +175 -0
@@ -0,0 +1,26 @@
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_DB_ITER_H_
6
+ #define STORAGE_LEVELDB_DB_DB_ITER_H_
7
+
8
+ #include <stdint.h>
9
+ #include "leveldb/db.h"
10
+ #include "db/dbformat.h"
11
+
12
+ namespace leveldb {
13
+
14
+ // Return a new iterator that converts internal keys (yielded by
15
+ // "*internal_iter") that were live at the specified "sequence" number
16
+ // into appropriate user keys.
17
+ extern Iterator* NewDBIterator(
18
+ const std::string* dbname,
19
+ Env* env,
20
+ const Comparator* user_key_comparator,
21
+ Iterator* internal_iter,
22
+ const SequenceNumber& sequence);
23
+
24
+ } // namespace leveldb
25
+
26
+ #endif // STORAGE_LEVELDB_DB_DB_ITER_H_
@@ -0,0 +1,1901 @@
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 "leveldb/db.h"
6
+ #include "leveldb/filter_policy.h"
7
+ #include "db/db_impl.h"
8
+ #include "db/filename.h"
9
+ #include "db/version_set.h"
10
+ #include "db/write_batch_internal.h"
11
+ #include "leveldb/cache.h"
12
+ #include "leveldb/env.h"
13
+ #include "leveldb/table.h"
14
+ #include "util/hash.h"
15
+ #include "util/logging.h"
16
+ #include "util/mutexlock.h"
17
+ #include "util/testharness.h"
18
+ #include "util/testutil.h"
19
+
20
+ namespace leveldb {
21
+
22
+ static std::string RandomString(Random* rnd, int len) {
23
+ std::string r;
24
+ test::RandomString(rnd, len, &r);
25
+ return r;
26
+ }
27
+
28
+ namespace {
29
+ class AtomicCounter {
30
+ private:
31
+ port::Mutex mu_;
32
+ int count_;
33
+ public:
34
+ AtomicCounter() : count_(0) { }
35
+ void Increment() {
36
+ MutexLock l(&mu_);
37
+ count_++;
38
+ }
39
+ int Read() {
40
+ MutexLock l(&mu_);
41
+ return count_;
42
+ }
43
+ void Reset() {
44
+ MutexLock l(&mu_);
45
+ count_ = 0;
46
+ }
47
+ };
48
+ }
49
+
50
+ // Special Env used to delay background operations
51
+ class SpecialEnv : public EnvWrapper {
52
+ public:
53
+ // sstable Sync() calls are blocked while this pointer is non-NULL.
54
+ port::AtomicPointer delay_sstable_sync_;
55
+
56
+ // Simulate no-space errors while this pointer is non-NULL.
57
+ port::AtomicPointer no_space_;
58
+
59
+ bool count_random_reads_;
60
+ AtomicCounter random_read_counter_;
61
+
62
+ explicit SpecialEnv(Env* base) : EnvWrapper(base) {
63
+ delay_sstable_sync_.Release_Store(NULL);
64
+ no_space_.Release_Store(NULL);
65
+ count_random_reads_ = false;
66
+ }
67
+
68
+ Status NewWritableFile(const std::string& f, WritableFile** r) {
69
+ class SSTableFile : public WritableFile {
70
+ private:
71
+ SpecialEnv* env_;
72
+ WritableFile* base_;
73
+
74
+ public:
75
+ SSTableFile(SpecialEnv* env, WritableFile* base)
76
+ : env_(env),
77
+ base_(base) {
78
+ }
79
+ ~SSTableFile() { delete base_; }
80
+ Status Append(const Slice& data) {
81
+ if (env_->no_space_.Acquire_Load() != NULL) {
82
+ // Drop writes on the floor
83
+ return Status::OK();
84
+ } else {
85
+ return base_->Append(data);
86
+ }
87
+ }
88
+ Status Close() { return base_->Close(); }
89
+ Status Flush() { return base_->Flush(); }
90
+ Status Sync() {
91
+ while (env_->delay_sstable_sync_.Acquire_Load() != NULL) {
92
+ env_->SleepForMicroseconds(100000);
93
+ }
94
+ return base_->Sync();
95
+ }
96
+ };
97
+
98
+ Status s = target()->NewWritableFile(f, r);
99
+ if (s.ok()) {
100
+ if (strstr(f.c_str(), ".sst") != NULL) {
101
+ *r = new SSTableFile(this, *r);
102
+ }
103
+ }
104
+ return s;
105
+ }
106
+
107
+ Status NewRandomAccessFile(const std::string& f, RandomAccessFile** r) {
108
+ class CountingFile : public RandomAccessFile {
109
+ private:
110
+ RandomAccessFile* target_;
111
+ AtomicCounter* counter_;
112
+ public:
113
+ CountingFile(RandomAccessFile* target, AtomicCounter* counter)
114
+ : target_(target), counter_(counter) {
115
+ }
116
+ virtual ~CountingFile() { delete target_; }
117
+ virtual Status Read(uint64_t offset, size_t n, Slice* result,
118
+ char* scratch) const {
119
+ counter_->Increment();
120
+ return target_->Read(offset, n, result, scratch);
121
+ }
122
+ };
123
+
124
+ Status s = target()->NewRandomAccessFile(f, r);
125
+ if (s.ok() && count_random_reads_) {
126
+ *r = new CountingFile(*r, &random_read_counter_);
127
+ }
128
+ return s;
129
+ }
130
+ };
131
+
132
+ class DBTest {
133
+ private:
134
+ const FilterPolicy* filter_policy_;
135
+
136
+ // Sequence of option configurations to try
137
+ enum OptionConfig {
138
+ kDefault,
139
+ kFilter,
140
+ kEnd
141
+ };
142
+ int option_config_;
143
+
144
+ public:
145
+ std::string dbname_;
146
+ SpecialEnv* env_;
147
+ DB* db_;
148
+
149
+ Options last_options_;
150
+
151
+ DBTest() : option_config_(kDefault),
152
+ env_(new SpecialEnv(Env::Default())) {
153
+ filter_policy_ = NewBloomFilterPolicy(10);
154
+ dbname_ = test::TmpDir() + "/db_test";
155
+ DestroyDB(dbname_, Options());
156
+ db_ = NULL;
157
+ Reopen();
158
+ }
159
+
160
+ ~DBTest() {
161
+ delete db_;
162
+ DestroyDB(dbname_, Options());
163
+ delete env_;
164
+ delete filter_policy_;
165
+ }
166
+
167
+ // Switch to a fresh database with the next option configuration to
168
+ // test. Return false if there are no more configurations to test.
169
+ bool ChangeOptions() {
170
+ if (option_config_ == kEnd) {
171
+ return false;
172
+ } else {
173
+ option_config_++;
174
+ DestroyAndReopen();
175
+ return true;
176
+ }
177
+ }
178
+
179
+ // Return the current option configuration.
180
+ Options CurrentOptions() {
181
+ Options options;
182
+ switch (option_config_) {
183
+ case kFilter:
184
+ options.filter_policy = filter_policy_;
185
+ break;
186
+ default:
187
+ break;
188
+ }
189
+ return options;
190
+ }
191
+
192
+ DBImpl* dbfull() {
193
+ return reinterpret_cast<DBImpl*>(db_);
194
+ }
195
+
196
+ void Reopen(Options* options = NULL) {
197
+ ASSERT_OK(TryReopen(options));
198
+ }
199
+
200
+ void Close() {
201
+ delete db_;
202
+ db_ = NULL;
203
+ }
204
+
205
+ void DestroyAndReopen(Options* options = NULL) {
206
+ delete db_;
207
+ db_ = NULL;
208
+ DestroyDB(dbname_, Options());
209
+ ASSERT_OK(TryReopen(options));
210
+ }
211
+
212
+ Status TryReopen(Options* options) {
213
+ delete db_;
214
+ db_ = NULL;
215
+ Options opts;
216
+ if (options != NULL) {
217
+ opts = *options;
218
+ } else {
219
+ opts = CurrentOptions();
220
+ opts.create_if_missing = true;
221
+ }
222
+ last_options_ = opts;
223
+
224
+ return DB::Open(opts, dbname_, &db_);
225
+ }
226
+
227
+ Status Put(const std::string& k, const std::string& v) {
228
+ return db_->Put(WriteOptions(), k, v);
229
+ }
230
+
231
+ Status Delete(const std::string& k) {
232
+ return db_->Delete(WriteOptions(), k);
233
+ }
234
+
235
+ std::string Get(const std::string& k, const Snapshot* snapshot = NULL) {
236
+ ReadOptions options;
237
+ options.snapshot = snapshot;
238
+ std::string result;
239
+ Status s = db_->Get(options, k, &result);
240
+ if (s.IsNotFound()) {
241
+ result = "NOT_FOUND";
242
+ } else if (!s.ok()) {
243
+ result = s.ToString();
244
+ }
245
+ return result;
246
+ }
247
+
248
+ // Return a string that contains all key,value pairs in order,
249
+ // formatted like "(k1->v1)(k2->v2)".
250
+ std::string Contents() {
251
+ std::vector<std::string> forward;
252
+ std::string result;
253
+ Iterator* iter = db_->NewIterator(ReadOptions());
254
+ for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
255
+ std::string s = IterStatus(iter);
256
+ result.push_back('(');
257
+ result.append(s);
258
+ result.push_back(')');
259
+ forward.push_back(s);
260
+ }
261
+
262
+ // Check reverse iteration results are the reverse of forward results
263
+ int matched = 0;
264
+ for (iter->SeekToLast(); iter->Valid(); iter->Prev()) {
265
+ ASSERT_LT(matched, forward.size());
266
+ ASSERT_EQ(IterStatus(iter), forward[forward.size() - matched - 1]);
267
+ matched++;
268
+ }
269
+ ASSERT_EQ(matched, forward.size());
270
+
271
+ delete iter;
272
+ return result;
273
+ }
274
+
275
+ std::string AllEntriesFor(const Slice& user_key) {
276
+ Iterator* iter = dbfull()->TEST_NewInternalIterator();
277
+ InternalKey target(user_key, kMaxSequenceNumber, kTypeValue);
278
+ iter->Seek(target.Encode());
279
+ std::string result;
280
+ if (!iter->status().ok()) {
281
+ result = iter->status().ToString();
282
+ } else {
283
+ result = "[ ";
284
+ bool first = true;
285
+ while (iter->Valid()) {
286
+ ParsedInternalKey ikey;
287
+ if (!ParseInternalKey(iter->key(), &ikey)) {
288
+ result += "CORRUPTED";
289
+ } else {
290
+ if (last_options_.comparator->Compare(ikey.user_key, user_key) != 0) {
291
+ break;
292
+ }
293
+ if (!first) {
294
+ result += ", ";
295
+ }
296
+ first = false;
297
+ switch (ikey.type) {
298
+ case kTypeValue:
299
+ result += iter->value().ToString();
300
+ break;
301
+ case kTypeDeletion:
302
+ result += "DEL";
303
+ break;
304
+ }
305
+ }
306
+ iter->Next();
307
+ }
308
+ if (!first) {
309
+ result += " ";
310
+ }
311
+ result += "]";
312
+ }
313
+ delete iter;
314
+ return result;
315
+ }
316
+
317
+ int NumTableFilesAtLevel(int level) {
318
+ std::string property;
319
+ ASSERT_TRUE(
320
+ db_->GetProperty("leveldb.num-files-at-level" + NumberToString(level),
321
+ &property));
322
+ return atoi(property.c_str());
323
+ }
324
+
325
+ int TotalTableFiles() {
326
+ int result = 0;
327
+ for (int level = 0; level < config::kNumLevels; level++) {
328
+ result += NumTableFilesAtLevel(level);
329
+ }
330
+ return result;
331
+ }
332
+
333
+ // Return spread of files per level
334
+ std::string FilesPerLevel() {
335
+ std::string result;
336
+ int last_non_zero_offset = 0;
337
+ for (int level = 0; level < config::kNumLevels; level++) {
338
+ int f = NumTableFilesAtLevel(level);
339
+ char buf[100];
340
+ snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f);
341
+ result += buf;
342
+ if (f > 0) {
343
+ last_non_zero_offset = result.size();
344
+ }
345
+ }
346
+ result.resize(last_non_zero_offset);
347
+ return result;
348
+ }
349
+
350
+ int CountFiles() {
351
+ std::vector<std::string> files;
352
+ env_->GetChildren(dbname_, &files);
353
+ return static_cast<int>(files.size());
354
+ }
355
+
356
+ uint64_t Size(const Slice& start, const Slice& limit) {
357
+ Range r(start, limit);
358
+ uint64_t size;
359
+ db_->GetApproximateSizes(&r, 1, &size);
360
+ return size;
361
+ }
362
+
363
+ void Compact(const Slice& start, const Slice& limit) {
364
+ db_->CompactRange(&start, &limit);
365
+ }
366
+
367
+ // Do n memtable compactions, each of which produces an sstable
368
+ // covering the range [small,large].
369
+ void MakeTables(int n, const std::string& small, const std::string& large) {
370
+ for (int i = 0; i < n; i++) {
371
+ Put(small, "begin");
372
+ Put(large, "end");
373
+ dbfull()->TEST_CompactMemTable();
374
+ }
375
+ }
376
+
377
+ // Prevent pushing of new sstables into deeper levels by adding
378
+ // tables that cover a specified range to all levels.
379
+ void FillLevels(const std::string& smallest, const std::string& largest) {
380
+ MakeTables(config::kNumLevels, smallest, largest);
381
+ }
382
+
383
+ void DumpFileCounts(const char* label) {
384
+ fprintf(stderr, "---\n%s:\n", label);
385
+ fprintf(stderr, "maxoverlap: %lld\n",
386
+ static_cast<long long>(
387
+ dbfull()->TEST_MaxNextLevelOverlappingBytes()));
388
+ for (int level = 0; level < config::kNumLevels; level++) {
389
+ int num = NumTableFilesAtLevel(level);
390
+ if (num > 0) {
391
+ fprintf(stderr, " level %3d : %d files\n", level, num);
392
+ }
393
+ }
394
+ }
395
+
396
+ std::string DumpSSTableList() {
397
+ std::string property;
398
+ db_->GetProperty("leveldb.sstables", &property);
399
+ return property;
400
+ }
401
+
402
+ std::string IterStatus(Iterator* iter) {
403
+ std::string result;
404
+ if (iter->Valid()) {
405
+ result = iter->key().ToString() + "->" + iter->value().ToString();
406
+ } else {
407
+ result = "(invalid)";
408
+ }
409
+ return result;
410
+ }
411
+ };
412
+
413
+ TEST(DBTest, Empty) {
414
+ do {
415
+ ASSERT_TRUE(db_ != NULL);
416
+ ASSERT_EQ("NOT_FOUND", Get("foo"));
417
+ } while (ChangeOptions());
418
+ }
419
+
420
+ TEST(DBTest, ReadWrite) {
421
+ do {
422
+ ASSERT_OK(Put("foo", "v1"));
423
+ ASSERT_EQ("v1", Get("foo"));
424
+ ASSERT_OK(Put("bar", "v2"));
425
+ ASSERT_OK(Put("foo", "v3"));
426
+ ASSERT_EQ("v3", Get("foo"));
427
+ ASSERT_EQ("v2", Get("bar"));
428
+ } while (ChangeOptions());
429
+ }
430
+
431
+ TEST(DBTest, PutDeleteGet) {
432
+ do {
433
+ ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1"));
434
+ ASSERT_EQ("v1", Get("foo"));
435
+ ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2"));
436
+ ASSERT_EQ("v2", Get("foo"));
437
+ ASSERT_OK(db_->Delete(WriteOptions(), "foo"));
438
+ ASSERT_EQ("NOT_FOUND", Get("foo"));
439
+ } while (ChangeOptions());
440
+ }
441
+
442
+ TEST(DBTest, GetFromImmutableLayer) {
443
+ do {
444
+ Options options = CurrentOptions();
445
+ options.env = env_;
446
+ options.write_buffer_size = 100000; // Small write buffer
447
+ Reopen(&options);
448
+
449
+ ASSERT_OK(Put("foo", "v1"));
450
+ ASSERT_EQ("v1", Get("foo"));
451
+
452
+ env_->delay_sstable_sync_.Release_Store(env_); // Block sync calls
453
+ Put("k1", std::string(100000, 'x')); // Fill memtable
454
+ Put("k2", std::string(100000, 'y')); // Trigger compaction
455
+ ASSERT_EQ("v1", Get("foo"));
456
+ env_->delay_sstable_sync_.Release_Store(NULL); // Release sync calls
457
+ } while (ChangeOptions());
458
+ }
459
+
460
+ TEST(DBTest, GetFromVersions) {
461
+ do {
462
+ ASSERT_OK(Put("foo", "v1"));
463
+ dbfull()->TEST_CompactMemTable();
464
+ ASSERT_EQ("v1", Get("foo"));
465
+ } while (ChangeOptions());
466
+ }
467
+
468
+ TEST(DBTest, GetSnapshot) {
469
+ do {
470
+ // Try with both a short key and a long key
471
+ for (int i = 0; i < 2; i++) {
472
+ std::string key = (i == 0) ? std::string("foo") : std::string(200, 'x');
473
+ ASSERT_OK(Put(key, "v1"));
474
+ const Snapshot* s1 = db_->GetSnapshot();
475
+ ASSERT_OK(Put(key, "v2"));
476
+ ASSERT_EQ("v2", Get(key));
477
+ ASSERT_EQ("v1", Get(key, s1));
478
+ dbfull()->TEST_CompactMemTable();
479
+ ASSERT_EQ("v2", Get(key));
480
+ ASSERT_EQ("v1", Get(key, s1));
481
+ db_->ReleaseSnapshot(s1);
482
+ }
483
+ } while (ChangeOptions());
484
+ }
485
+
486
+ TEST(DBTest, GetLevel0Ordering) {
487
+ do {
488
+ // Check that we process level-0 files in correct order. The code
489
+ // below generates two level-0 files where the earlier one comes
490
+ // before the later one in the level-0 file list since the earlier
491
+ // one has a smaller "smallest" key.
492
+ ASSERT_OK(Put("bar", "b"));
493
+ ASSERT_OK(Put("foo", "v1"));
494
+ dbfull()->TEST_CompactMemTable();
495
+ ASSERT_OK(Put("foo", "v2"));
496
+ dbfull()->TEST_CompactMemTable();
497
+ ASSERT_EQ("v2", Get("foo"));
498
+ } while (ChangeOptions());
499
+ }
500
+
501
+ TEST(DBTest, GetOrderedByLevels) {
502
+ do {
503
+ ASSERT_OK(Put("foo", "v1"));
504
+ Compact("a", "z");
505
+ ASSERT_EQ("v1", Get("foo"));
506
+ ASSERT_OK(Put("foo", "v2"));
507
+ ASSERT_EQ("v2", Get("foo"));
508
+ dbfull()->TEST_CompactMemTable();
509
+ ASSERT_EQ("v2", Get("foo"));
510
+ } while (ChangeOptions());
511
+ }
512
+
513
+ TEST(DBTest, GetPicksCorrectFile) {
514
+ do {
515
+ // Arrange to have multiple files in a non-level-0 level.
516
+ ASSERT_OK(Put("a", "va"));
517
+ Compact("a", "b");
518
+ ASSERT_OK(Put("x", "vx"));
519
+ Compact("x", "y");
520
+ ASSERT_OK(Put("f", "vf"));
521
+ Compact("f", "g");
522
+ ASSERT_EQ("va", Get("a"));
523
+ ASSERT_EQ("vf", Get("f"));
524
+ ASSERT_EQ("vx", Get("x"));
525
+ } while (ChangeOptions());
526
+ }
527
+
528
+ TEST(DBTest, GetEncountersEmptyLevel) {
529
+ do {
530
+ // Arrange for the following to happen:
531
+ // * sstable A in level 0
532
+ // * nothing in level 1
533
+ // * sstable B in level 2
534
+ // Then do enough Get() calls to arrange for an automatic compaction
535
+ // of sstable A. A bug would cause the compaction to be marked as
536
+ // occuring at level 1 (instead of the correct level 0).
537
+
538
+ // Step 1: First place sstables in levels 0 and 2
539
+ int compaction_count = 0;
540
+ while (NumTableFilesAtLevel(0) == 0 ||
541
+ NumTableFilesAtLevel(2) == 0) {
542
+ ASSERT_LE(compaction_count, 100) << "could not fill levels 0 and 2";
543
+ compaction_count++;
544
+ Put("a", "begin");
545
+ Put("z", "end");
546
+ dbfull()->TEST_CompactMemTable();
547
+ }
548
+
549
+ // Step 2: clear level 1 if necessary.
550
+ dbfull()->TEST_CompactRange(1, NULL, NULL);
551
+ ASSERT_EQ(NumTableFilesAtLevel(0), 1);
552
+ ASSERT_EQ(NumTableFilesAtLevel(1), 0);
553
+ ASSERT_EQ(NumTableFilesAtLevel(2), 1);
554
+
555
+ // Step 3: read until level 0 compaction disappears.
556
+ int read_count = 0;
557
+ while (NumTableFilesAtLevel(0) > 0) {
558
+ ASSERT_LE(read_count, 10000) << "did not trigger level 0 compaction";
559
+ read_count++;
560
+ ASSERT_EQ("NOT_FOUND", Get("missing"));
561
+ }
562
+ } while (ChangeOptions());
563
+ }
564
+
565
+ TEST(DBTest, IterEmpty) {
566
+ Iterator* iter = db_->NewIterator(ReadOptions());
567
+
568
+ iter->SeekToFirst();
569
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
570
+
571
+ iter->SeekToLast();
572
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
573
+
574
+ iter->Seek("foo");
575
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
576
+
577
+ delete iter;
578
+ }
579
+
580
+ TEST(DBTest, IterSingle) {
581
+ ASSERT_OK(Put("a", "va"));
582
+ Iterator* iter = db_->NewIterator(ReadOptions());
583
+
584
+ iter->SeekToFirst();
585
+ ASSERT_EQ(IterStatus(iter), "a->va");
586
+ iter->Next();
587
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
588
+ iter->SeekToFirst();
589
+ ASSERT_EQ(IterStatus(iter), "a->va");
590
+ iter->Prev();
591
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
592
+
593
+ iter->SeekToLast();
594
+ ASSERT_EQ(IterStatus(iter), "a->va");
595
+ iter->Next();
596
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
597
+ iter->SeekToLast();
598
+ ASSERT_EQ(IterStatus(iter), "a->va");
599
+ iter->Prev();
600
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
601
+
602
+ iter->Seek("");
603
+ ASSERT_EQ(IterStatus(iter), "a->va");
604
+ iter->Next();
605
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
606
+
607
+ iter->Seek("a");
608
+ ASSERT_EQ(IterStatus(iter), "a->va");
609
+ iter->Next();
610
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
611
+
612
+ iter->Seek("b");
613
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
614
+
615
+ delete iter;
616
+ }
617
+
618
+ TEST(DBTest, IterMulti) {
619
+ ASSERT_OK(Put("a", "va"));
620
+ ASSERT_OK(Put("b", "vb"));
621
+ ASSERT_OK(Put("c", "vc"));
622
+ Iterator* iter = db_->NewIterator(ReadOptions());
623
+
624
+ iter->SeekToFirst();
625
+ ASSERT_EQ(IterStatus(iter), "a->va");
626
+ iter->Next();
627
+ ASSERT_EQ(IterStatus(iter), "b->vb");
628
+ iter->Next();
629
+ ASSERT_EQ(IterStatus(iter), "c->vc");
630
+ iter->Next();
631
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
632
+ iter->SeekToFirst();
633
+ ASSERT_EQ(IterStatus(iter), "a->va");
634
+ iter->Prev();
635
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
636
+
637
+ iter->SeekToLast();
638
+ ASSERT_EQ(IterStatus(iter), "c->vc");
639
+ iter->Prev();
640
+ ASSERT_EQ(IterStatus(iter), "b->vb");
641
+ iter->Prev();
642
+ ASSERT_EQ(IterStatus(iter), "a->va");
643
+ iter->Prev();
644
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
645
+ iter->SeekToLast();
646
+ ASSERT_EQ(IterStatus(iter), "c->vc");
647
+ iter->Next();
648
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
649
+
650
+ iter->Seek("");
651
+ ASSERT_EQ(IterStatus(iter), "a->va");
652
+ iter->Seek("a");
653
+ ASSERT_EQ(IterStatus(iter), "a->va");
654
+ iter->Seek("ax");
655
+ ASSERT_EQ(IterStatus(iter), "b->vb");
656
+ iter->Seek("b");
657
+ ASSERT_EQ(IterStatus(iter), "b->vb");
658
+ iter->Seek("z");
659
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
660
+
661
+ // Switch from reverse to forward
662
+ iter->SeekToLast();
663
+ iter->Prev();
664
+ iter->Prev();
665
+ iter->Next();
666
+ ASSERT_EQ(IterStatus(iter), "b->vb");
667
+
668
+ // Switch from forward to reverse
669
+ iter->SeekToFirst();
670
+ iter->Next();
671
+ iter->Next();
672
+ iter->Prev();
673
+ ASSERT_EQ(IterStatus(iter), "b->vb");
674
+
675
+ // Make sure iter stays at snapshot
676
+ ASSERT_OK(Put("a", "va2"));
677
+ ASSERT_OK(Put("a2", "va3"));
678
+ ASSERT_OK(Put("b", "vb2"));
679
+ ASSERT_OK(Put("c", "vc2"));
680
+ ASSERT_OK(Delete("b"));
681
+ iter->SeekToFirst();
682
+ ASSERT_EQ(IterStatus(iter), "a->va");
683
+ iter->Next();
684
+ ASSERT_EQ(IterStatus(iter), "b->vb");
685
+ iter->Next();
686
+ ASSERT_EQ(IterStatus(iter), "c->vc");
687
+ iter->Next();
688
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
689
+ iter->SeekToLast();
690
+ ASSERT_EQ(IterStatus(iter), "c->vc");
691
+ iter->Prev();
692
+ ASSERT_EQ(IterStatus(iter), "b->vb");
693
+ iter->Prev();
694
+ ASSERT_EQ(IterStatus(iter), "a->va");
695
+ iter->Prev();
696
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
697
+
698
+ delete iter;
699
+ }
700
+
701
+ TEST(DBTest, IterSmallAndLargeMix) {
702
+ ASSERT_OK(Put("a", "va"));
703
+ ASSERT_OK(Put("b", std::string(100000, 'b')));
704
+ ASSERT_OK(Put("c", "vc"));
705
+ ASSERT_OK(Put("d", std::string(100000, 'd')));
706
+ ASSERT_OK(Put("e", std::string(100000, 'e')));
707
+
708
+ Iterator* iter = db_->NewIterator(ReadOptions());
709
+
710
+ iter->SeekToFirst();
711
+ ASSERT_EQ(IterStatus(iter), "a->va");
712
+ iter->Next();
713
+ ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b'));
714
+ iter->Next();
715
+ ASSERT_EQ(IterStatus(iter), "c->vc");
716
+ iter->Next();
717
+ ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd'));
718
+ iter->Next();
719
+ ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e'));
720
+ iter->Next();
721
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
722
+
723
+ iter->SeekToLast();
724
+ ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e'));
725
+ iter->Prev();
726
+ ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd'));
727
+ iter->Prev();
728
+ ASSERT_EQ(IterStatus(iter), "c->vc");
729
+ iter->Prev();
730
+ ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b'));
731
+ iter->Prev();
732
+ ASSERT_EQ(IterStatus(iter), "a->va");
733
+ iter->Prev();
734
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
735
+
736
+ delete iter;
737
+ }
738
+
739
+ TEST(DBTest, IterMultiWithDelete) {
740
+ do {
741
+ ASSERT_OK(Put("a", "va"));
742
+ ASSERT_OK(Put("b", "vb"));
743
+ ASSERT_OK(Put("c", "vc"));
744
+ ASSERT_OK(Delete("b"));
745
+ ASSERT_EQ("NOT_FOUND", Get("b"));
746
+
747
+ Iterator* iter = db_->NewIterator(ReadOptions());
748
+ iter->Seek("c");
749
+ ASSERT_EQ(IterStatus(iter), "c->vc");
750
+ iter->Prev();
751
+ ASSERT_EQ(IterStatus(iter), "a->va");
752
+ delete iter;
753
+ } while (ChangeOptions());
754
+ }
755
+
756
+ TEST(DBTest, Recover) {
757
+ do {
758
+ ASSERT_OK(Put("foo", "v1"));
759
+ ASSERT_OK(Put("baz", "v5"));
760
+
761
+ Reopen();
762
+ ASSERT_EQ("v1", Get("foo"));
763
+
764
+ ASSERT_EQ("v1", Get("foo"));
765
+ ASSERT_EQ("v5", Get("baz"));
766
+ ASSERT_OK(Put("bar", "v2"));
767
+ ASSERT_OK(Put("foo", "v3"));
768
+
769
+ Reopen();
770
+ ASSERT_EQ("v3", Get("foo"));
771
+ ASSERT_OK(Put("foo", "v4"));
772
+ ASSERT_EQ("v4", Get("foo"));
773
+ ASSERT_EQ("v2", Get("bar"));
774
+ ASSERT_EQ("v5", Get("baz"));
775
+ } while (ChangeOptions());
776
+ }
777
+
778
+ TEST(DBTest, RecoveryWithEmptyLog) {
779
+ do {
780
+ ASSERT_OK(Put("foo", "v1"));
781
+ ASSERT_OK(Put("foo", "v2"));
782
+ Reopen();
783
+ Reopen();
784
+ ASSERT_OK(Put("foo", "v3"));
785
+ Reopen();
786
+ ASSERT_EQ("v3", Get("foo"));
787
+ } while (ChangeOptions());
788
+ }
789
+
790
+ // Check that writes done during a memtable compaction are recovered
791
+ // if the database is shutdown during the memtable compaction.
792
+ TEST(DBTest, RecoverDuringMemtableCompaction) {
793
+ do {
794
+ Options options = CurrentOptions();
795
+ options.env = env_;
796
+ options.write_buffer_size = 1000000;
797
+ Reopen(&options);
798
+
799
+ // Trigger a long memtable compaction and reopen the database during it
800
+ ASSERT_OK(Put("foo", "v1")); // Goes to 1st log file
801
+ ASSERT_OK(Put("big1", std::string(10000000, 'x'))); // Fills memtable
802
+ ASSERT_OK(Put("big2", std::string(1000, 'y'))); // Triggers compaction
803
+ ASSERT_OK(Put("bar", "v2")); // Goes to new log file
804
+
805
+ Reopen(&options);
806
+ ASSERT_EQ("v1", Get("foo"));
807
+ ASSERT_EQ("v2", Get("bar"));
808
+ ASSERT_EQ(std::string(10000000, 'x'), Get("big1"));
809
+ ASSERT_EQ(std::string(1000, 'y'), Get("big2"));
810
+ } while (ChangeOptions());
811
+ }
812
+
813
+ static std::string Key(int i) {
814
+ char buf[100];
815
+ snprintf(buf, sizeof(buf), "key%06d", i);
816
+ return std::string(buf);
817
+ }
818
+
819
+ TEST(DBTest, MinorCompactionsHappen) {
820
+ Options options = CurrentOptions();
821
+ options.write_buffer_size = 10000;
822
+ Reopen(&options);
823
+
824
+ const int N = 500;
825
+
826
+ int starting_num_tables = TotalTableFiles();
827
+ for (int i = 0; i < N; i++) {
828
+ ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v')));
829
+ }
830
+ int ending_num_tables = TotalTableFiles();
831
+ ASSERT_GT(ending_num_tables, starting_num_tables);
832
+
833
+ for (int i = 0; i < N; i++) {
834
+ ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));
835
+ }
836
+
837
+ Reopen();
838
+
839
+ for (int i = 0; i < N; i++) {
840
+ ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));
841
+ }
842
+ }
843
+
844
+ TEST(DBTest, RecoverWithLargeLog) {
845
+ {
846
+ Options options = CurrentOptions();
847
+ Reopen(&options);
848
+ ASSERT_OK(Put("big1", std::string(200000, '1')));
849
+ ASSERT_OK(Put("big2", std::string(200000, '2')));
850
+ ASSERT_OK(Put("small3", std::string(10, '3')));
851
+ ASSERT_OK(Put("small4", std::string(10, '4')));
852
+ ASSERT_EQ(NumTableFilesAtLevel(0), 0);
853
+ }
854
+
855
+ // Make sure that if we re-open with a small write buffer size that
856
+ // we flush table files in the middle of a large log file.
857
+ Options options = CurrentOptions();
858
+ options.write_buffer_size = 100000;
859
+ Reopen(&options);
860
+ ASSERT_EQ(NumTableFilesAtLevel(0), 3);
861
+ ASSERT_EQ(std::string(200000, '1'), Get("big1"));
862
+ ASSERT_EQ(std::string(200000, '2'), Get("big2"));
863
+ ASSERT_EQ(std::string(10, '3'), Get("small3"));
864
+ ASSERT_EQ(std::string(10, '4'), Get("small4"));
865
+ ASSERT_GT(NumTableFilesAtLevel(0), 1);
866
+ }
867
+
868
+ TEST(DBTest, CompactionsGenerateMultipleFiles) {
869
+ Options options = CurrentOptions();
870
+ options.write_buffer_size = 100000000; // Large write buffer
871
+ Reopen(&options);
872
+
873
+ Random rnd(301);
874
+
875
+ // Write 8MB (80 values, each 100K)
876
+ ASSERT_EQ(NumTableFilesAtLevel(0), 0);
877
+ std::vector<std::string> values;
878
+ for (int i = 0; i < 80; i++) {
879
+ values.push_back(RandomString(&rnd, 100000));
880
+ ASSERT_OK(Put(Key(i), values[i]));
881
+ }
882
+
883
+ // Reopening moves updates to level-0
884
+ Reopen(&options);
885
+ dbfull()->TEST_CompactRange(0, NULL, NULL);
886
+
887
+ ASSERT_EQ(NumTableFilesAtLevel(0), 0);
888
+ ASSERT_GT(NumTableFilesAtLevel(1), 1);
889
+ for (int i = 0; i < 80; i++) {
890
+ ASSERT_EQ(Get(Key(i)), values[i]);
891
+ }
892
+ }
893
+
894
+ TEST(DBTest, RepeatedWritesToSameKey) {
895
+ Options options = CurrentOptions();
896
+ options.env = env_;
897
+ options.write_buffer_size = 100000; // Small write buffer
898
+ Reopen(&options);
899
+
900
+ // We must have at most one file per level except for level-0,
901
+ // which may have up to kL0_StopWritesTrigger files.
902
+ const int kMaxFiles = config::kNumLevels + config::kL0_StopWritesTrigger;
903
+
904
+ Random rnd(301);
905
+ std::string value = RandomString(&rnd, 2 * options.write_buffer_size);
906
+ for (int i = 0; i < 5 * kMaxFiles; i++) {
907
+ Put("key", value);
908
+ ASSERT_LE(TotalTableFiles(), kMaxFiles);
909
+ fprintf(stderr, "after %d: %d files\n", int(i+1), TotalTableFiles());
910
+ }
911
+ }
912
+
913
+ TEST(DBTest, SparseMerge) {
914
+ Options options = CurrentOptions();
915
+ options.compression = kNoCompression;
916
+ Reopen(&options);
917
+
918
+ FillLevels("A", "Z");
919
+
920
+ // Suppose there is:
921
+ // small amount of data with prefix A
922
+ // large amount of data with prefix B
923
+ // small amount of data with prefix C
924
+ // and that recent updates have made small changes to all three prefixes.
925
+ // Check that we do not do a compaction that merges all of B in one shot.
926
+ const std::string value(1000, 'x');
927
+ Put("A", "va");
928
+ // Write approximately 100MB of "B" values
929
+ for (int i = 0; i < 100000; i++) {
930
+ char key[100];
931
+ snprintf(key, sizeof(key), "B%010d", i);
932
+ Put(key, value);
933
+ }
934
+ Put("C", "vc");
935
+ dbfull()->TEST_CompactMemTable();
936
+ dbfull()->TEST_CompactRange(0, NULL, NULL);
937
+
938
+ // Make sparse update
939
+ Put("A", "va2");
940
+ Put("B100", "bvalue2");
941
+ Put("C", "vc2");
942
+ dbfull()->TEST_CompactMemTable();
943
+
944
+ // Compactions should not cause us to create a situation where
945
+ // a file overlaps too much data at the next level.
946
+ ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);
947
+ dbfull()->TEST_CompactRange(0, NULL, NULL);
948
+ ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);
949
+ dbfull()->TEST_CompactRange(1, NULL, NULL);
950
+ ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);
951
+ }
952
+
953
+ static bool Between(uint64_t val, uint64_t low, uint64_t high) {
954
+ bool result = (val >= low) && (val <= high);
955
+ if (!result) {
956
+ fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n",
957
+ (unsigned long long)(val),
958
+ (unsigned long long)(low),
959
+ (unsigned long long)(high));
960
+ }
961
+ return result;
962
+ }
963
+
964
+ TEST(DBTest, ApproximateSizes) {
965
+ do {
966
+ Options options = CurrentOptions();
967
+ options.write_buffer_size = 100000000; // Large write buffer
968
+ options.compression = kNoCompression;
969
+ DestroyAndReopen();
970
+
971
+ ASSERT_TRUE(Between(Size("", "xyz"), 0, 0));
972
+ Reopen(&options);
973
+ ASSERT_TRUE(Between(Size("", "xyz"), 0, 0));
974
+
975
+ // Write 8MB (80 values, each 100K)
976
+ ASSERT_EQ(NumTableFilesAtLevel(0), 0);
977
+ const int N = 80;
978
+ static const int S1 = 100000;
979
+ static const int S2 = 105000; // Allow some expansion from metadata
980
+ Random rnd(301);
981
+ for (int i = 0; i < N; i++) {
982
+ ASSERT_OK(Put(Key(i), RandomString(&rnd, S1)));
983
+ }
984
+
985
+ // 0 because GetApproximateSizes() does not account for memtable space
986
+ ASSERT_TRUE(Between(Size("", Key(50)), 0, 0));
987
+
988
+ // Check sizes across recovery by reopening a few times
989
+ for (int run = 0; run < 3; run++) {
990
+ Reopen(&options);
991
+
992
+ for (int compact_start = 0; compact_start < N; compact_start += 10) {
993
+ for (int i = 0; i < N; i += 10) {
994
+ ASSERT_TRUE(Between(Size("", Key(i)), S1*i, S2*i));
995
+ ASSERT_TRUE(Between(Size("", Key(i)+".suffix"), S1*(i+1), S2*(i+1)));
996
+ ASSERT_TRUE(Between(Size(Key(i), Key(i+10)), S1*10, S2*10));
997
+ }
998
+ ASSERT_TRUE(Between(Size("", Key(50)), S1*50, S2*50));
999
+ ASSERT_TRUE(Between(Size("", Key(50)+".suffix"), S1*50, S2*50));
1000
+
1001
+ std::string cstart_str = Key(compact_start);
1002
+ std::string cend_str = Key(compact_start + 9);
1003
+ Slice cstart = cstart_str;
1004
+ Slice cend = cend_str;
1005
+ dbfull()->TEST_CompactRange(0, &cstart, &cend);
1006
+ }
1007
+
1008
+ ASSERT_EQ(NumTableFilesAtLevel(0), 0);
1009
+ ASSERT_GT(NumTableFilesAtLevel(1), 0);
1010
+ }
1011
+ } while (ChangeOptions());
1012
+ }
1013
+
1014
+ TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) {
1015
+ do {
1016
+ Options options = CurrentOptions();
1017
+ options.compression = kNoCompression;
1018
+ Reopen();
1019
+
1020
+ Random rnd(301);
1021
+ std::string big1 = RandomString(&rnd, 100000);
1022
+ ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000)));
1023
+ ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000)));
1024
+ ASSERT_OK(Put(Key(2), big1));
1025
+ ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000)));
1026
+ ASSERT_OK(Put(Key(4), big1));
1027
+ ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000)));
1028
+ ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000)));
1029
+ ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000)));
1030
+
1031
+ // Check sizes across recovery by reopening a few times
1032
+ for (int run = 0; run < 3; run++) {
1033
+ Reopen(&options);
1034
+
1035
+ ASSERT_TRUE(Between(Size("", Key(0)), 0, 0));
1036
+ ASSERT_TRUE(Between(Size("", Key(1)), 10000, 11000));
1037
+ ASSERT_TRUE(Between(Size("", Key(2)), 20000, 21000));
1038
+ ASSERT_TRUE(Between(Size("", Key(3)), 120000, 121000));
1039
+ ASSERT_TRUE(Between(Size("", Key(4)), 130000, 131000));
1040
+ ASSERT_TRUE(Between(Size("", Key(5)), 230000, 231000));
1041
+ ASSERT_TRUE(Between(Size("", Key(6)), 240000, 241000));
1042
+ ASSERT_TRUE(Between(Size("", Key(7)), 540000, 541000));
1043
+ ASSERT_TRUE(Between(Size("", Key(8)), 550000, 560000));
1044
+
1045
+ ASSERT_TRUE(Between(Size(Key(3), Key(5)), 110000, 111000));
1046
+
1047
+ dbfull()->TEST_CompactRange(0, NULL, NULL);
1048
+ }
1049
+ } while (ChangeOptions());
1050
+ }
1051
+
1052
+ TEST(DBTest, IteratorPinsRef) {
1053
+ Put("foo", "hello");
1054
+
1055
+ // Get iterator that will yield the current contents of the DB.
1056
+ Iterator* iter = db_->NewIterator(ReadOptions());
1057
+
1058
+ // Write to force compactions
1059
+ Put("foo", "newvalue1");
1060
+ for (int i = 0; i < 100; i++) {
1061
+ ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values
1062
+ }
1063
+ Put("foo", "newvalue2");
1064
+
1065
+ iter->SeekToFirst();
1066
+ ASSERT_TRUE(iter->Valid());
1067
+ ASSERT_EQ("foo", iter->key().ToString());
1068
+ ASSERT_EQ("hello", iter->value().ToString());
1069
+ iter->Next();
1070
+ ASSERT_TRUE(!iter->Valid());
1071
+ delete iter;
1072
+ }
1073
+
1074
+ TEST(DBTest, Snapshot) {
1075
+ do {
1076
+ Put("foo", "v1");
1077
+ const Snapshot* s1 = db_->GetSnapshot();
1078
+ Put("foo", "v2");
1079
+ const Snapshot* s2 = db_->GetSnapshot();
1080
+ Put("foo", "v3");
1081
+ const Snapshot* s3 = db_->GetSnapshot();
1082
+
1083
+ Put("foo", "v4");
1084
+ ASSERT_EQ("v1", Get("foo", s1));
1085
+ ASSERT_EQ("v2", Get("foo", s2));
1086
+ ASSERT_EQ("v3", Get("foo", s3));
1087
+ ASSERT_EQ("v4", Get("foo"));
1088
+
1089
+ db_->ReleaseSnapshot(s3);
1090
+ ASSERT_EQ("v1", Get("foo", s1));
1091
+ ASSERT_EQ("v2", Get("foo", s2));
1092
+ ASSERT_EQ("v4", Get("foo"));
1093
+
1094
+ db_->ReleaseSnapshot(s1);
1095
+ ASSERT_EQ("v2", Get("foo", s2));
1096
+ ASSERT_EQ("v4", Get("foo"));
1097
+
1098
+ db_->ReleaseSnapshot(s2);
1099
+ ASSERT_EQ("v4", Get("foo"));
1100
+ } while (ChangeOptions());
1101
+ }
1102
+
1103
+ TEST(DBTest, HiddenValuesAreRemoved) {
1104
+ do {
1105
+ Random rnd(301);
1106
+ FillLevels("a", "z");
1107
+
1108
+ std::string big = RandomString(&rnd, 50000);
1109
+ Put("foo", big);
1110
+ Put("pastfoo", "v");
1111
+ const Snapshot* snapshot = db_->GetSnapshot();
1112
+ Put("foo", "tiny");
1113
+ Put("pastfoo2", "v2"); // Advance sequence number one more
1114
+
1115
+ ASSERT_OK(dbfull()->TEST_CompactMemTable());
1116
+ ASSERT_GT(NumTableFilesAtLevel(0), 0);
1117
+
1118
+ ASSERT_EQ(big, Get("foo", snapshot));
1119
+ ASSERT_TRUE(Between(Size("", "pastfoo"), 50000, 60000));
1120
+ db_->ReleaseSnapshot(snapshot);
1121
+ ASSERT_EQ(AllEntriesFor("foo"), "[ tiny, " + big + " ]");
1122
+ Slice x("x");
1123
+ dbfull()->TEST_CompactRange(0, NULL, &x);
1124
+ ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]");
1125
+ ASSERT_EQ(NumTableFilesAtLevel(0), 0);
1126
+ ASSERT_GE(NumTableFilesAtLevel(1), 1);
1127
+ dbfull()->TEST_CompactRange(1, NULL, &x);
1128
+ ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]");
1129
+
1130
+ ASSERT_TRUE(Between(Size("", "pastfoo"), 0, 1000));
1131
+ } while (ChangeOptions());
1132
+ }
1133
+
1134
+ TEST(DBTest, DeletionMarkers1) {
1135
+ Put("foo", "v1");
1136
+ ASSERT_OK(dbfull()->TEST_CompactMemTable());
1137
+ const int last = config::kMaxMemCompactLevel;
1138
+ ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level
1139
+
1140
+ // Place a table at level last-1 to prevent merging with preceding mutation
1141
+ Put("a", "begin");
1142
+ Put("z", "end");
1143
+ dbfull()->TEST_CompactMemTable();
1144
+ ASSERT_EQ(NumTableFilesAtLevel(last), 1);
1145
+ ASSERT_EQ(NumTableFilesAtLevel(last-1), 1);
1146
+
1147
+ Delete("foo");
1148
+ Put("foo", "v2");
1149
+ ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");
1150
+ ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2
1151
+ ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");
1152
+ Slice z("z");
1153
+ dbfull()->TEST_CompactRange(last-2, NULL, &z);
1154
+ // DEL eliminated, but v1 remains because we aren't compacting that level
1155
+ // (DEL can be eliminated because v2 hides v1).
1156
+ ASSERT_EQ(AllEntriesFor("foo"), "[ v2, v1 ]");
1157
+ dbfull()->TEST_CompactRange(last-1, NULL, NULL);
1158
+ // Merging last-1 w/ last, so we are the base level for "foo", so
1159
+ // DEL is removed. (as is v1).
1160
+ ASSERT_EQ(AllEntriesFor("foo"), "[ v2 ]");
1161
+ }
1162
+
1163
+ TEST(DBTest, DeletionMarkers2) {
1164
+ Put("foo", "v1");
1165
+ ASSERT_OK(dbfull()->TEST_CompactMemTable());
1166
+ const int last = config::kMaxMemCompactLevel;
1167
+ ASSERT_EQ(NumTableFilesAtLevel(last), 1); // foo => v1 is now in last level
1168
+
1169
+ // Place a table at level last-1 to prevent merging with preceding mutation
1170
+ Put("a", "begin");
1171
+ Put("z", "end");
1172
+ dbfull()->TEST_CompactMemTable();
1173
+ ASSERT_EQ(NumTableFilesAtLevel(last), 1);
1174
+ ASSERT_EQ(NumTableFilesAtLevel(last-1), 1);
1175
+
1176
+ Delete("foo");
1177
+ ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
1178
+ ASSERT_OK(dbfull()->TEST_CompactMemTable()); // Moves to level last-2
1179
+ ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
1180
+ dbfull()->TEST_CompactRange(last-2, NULL, NULL);
1181
+ // DEL kept: "last" file overlaps
1182
+ ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
1183
+ dbfull()->TEST_CompactRange(last-1, NULL, NULL);
1184
+ // Merging last-1 w/ last, so we are the base level for "foo", so
1185
+ // DEL is removed. (as is v1).
1186
+ ASSERT_EQ(AllEntriesFor("foo"), "[ ]");
1187
+ }
1188
+
1189
+ TEST(DBTest, OverlapInLevel0) {
1190
+ do {
1191
+ ASSERT_EQ(config::kMaxMemCompactLevel, 2) << "Fix test to match config";
1192
+
1193
+ // Fill levels 1 and 2 to disable the pushing of new memtables to levels > 0.
1194
+ ASSERT_OK(Put("100", "v100"));
1195
+ ASSERT_OK(Put("999", "v999"));
1196
+ dbfull()->TEST_CompactMemTable();
1197
+ ASSERT_OK(Delete("100"));
1198
+ ASSERT_OK(Delete("999"));
1199
+ dbfull()->TEST_CompactMemTable();
1200
+ ASSERT_EQ("0,1,1", FilesPerLevel());
1201
+
1202
+ // Make files spanning the following ranges in level-0:
1203
+ // files[0] 200 .. 900
1204
+ // files[1] 300 .. 500
1205
+ // Note that files are sorted by smallest key.
1206
+ ASSERT_OK(Put("300", "v300"));
1207
+ ASSERT_OK(Put("500", "v500"));
1208
+ dbfull()->TEST_CompactMemTable();
1209
+ ASSERT_OK(Put("200", "v200"));
1210
+ ASSERT_OK(Put("600", "v600"));
1211
+ ASSERT_OK(Put("900", "v900"));
1212
+ dbfull()->TEST_CompactMemTable();
1213
+ ASSERT_EQ("2,1,1", FilesPerLevel());
1214
+
1215
+ // Compact away the placeholder files we created initially
1216
+ dbfull()->TEST_CompactRange(1, NULL, NULL);
1217
+ dbfull()->TEST_CompactRange(2, NULL, NULL);
1218
+ ASSERT_EQ("2", FilesPerLevel());
1219
+
1220
+ // Do a memtable compaction. Before bug-fix, the compaction would
1221
+ // not detect the overlap with level-0 files and would incorrectly place
1222
+ // the deletion in a deeper level.
1223
+ ASSERT_OK(Delete("600"));
1224
+ dbfull()->TEST_CompactMemTable();
1225
+ ASSERT_EQ("3", FilesPerLevel());
1226
+ ASSERT_EQ("NOT_FOUND", Get("600"));
1227
+ } while (ChangeOptions());
1228
+ }
1229
+
1230
+ TEST(DBTest, L0_CompactionBug_Issue44_a) {
1231
+ Reopen();
1232
+ ASSERT_OK(Put("b", "v"));
1233
+ Reopen();
1234
+ ASSERT_OK(Delete("b"));
1235
+ ASSERT_OK(Delete("a"));
1236
+ Reopen();
1237
+ ASSERT_OK(Delete("a"));
1238
+ Reopen();
1239
+ ASSERT_OK(Put("a", "v"));
1240
+ Reopen();
1241
+ Reopen();
1242
+ ASSERT_EQ("(a->v)", Contents());
1243
+ env_->SleepForMicroseconds(1000000); // Wait for compaction to finish
1244
+ ASSERT_EQ("(a->v)", Contents());
1245
+ }
1246
+
1247
+ TEST(DBTest, L0_CompactionBug_Issue44_b) {
1248
+ Reopen();
1249
+ Put("","");
1250
+ Reopen();
1251
+ Delete("e");
1252
+ Put("","");
1253
+ Reopen();
1254
+ Put("c", "cv");
1255
+ Reopen();
1256
+ Put("","");
1257
+ Reopen();
1258
+ Put("","");
1259
+ env_->SleepForMicroseconds(1000000); // Wait for compaction to finish
1260
+ Reopen();
1261
+ Put("d","dv");
1262
+ Reopen();
1263
+ Put("","");
1264
+ Reopen();
1265
+ Delete("d");
1266
+ Delete("b");
1267
+ Reopen();
1268
+ ASSERT_EQ("(->)(c->cv)", Contents());
1269
+ env_->SleepForMicroseconds(1000000); // Wait for compaction to finish
1270
+ ASSERT_EQ("(->)(c->cv)", Contents());
1271
+ }
1272
+
1273
+ TEST(DBTest, ComparatorCheck) {
1274
+ class NewComparator : public Comparator {
1275
+ public:
1276
+ virtual const char* Name() const { return "leveldb.NewComparator"; }
1277
+ virtual int Compare(const Slice& a, const Slice& b) const {
1278
+ return BytewiseComparator()->Compare(a, b);
1279
+ }
1280
+ virtual void FindShortestSeparator(std::string* s, const Slice& l) const {
1281
+ BytewiseComparator()->FindShortestSeparator(s, l);
1282
+ }
1283
+ virtual void FindShortSuccessor(std::string* key) const {
1284
+ BytewiseComparator()->FindShortSuccessor(key);
1285
+ }
1286
+ };
1287
+ NewComparator cmp;
1288
+ Options new_options = CurrentOptions();
1289
+ new_options.comparator = &cmp;
1290
+ Status s = TryReopen(&new_options);
1291
+ ASSERT_TRUE(!s.ok());
1292
+ ASSERT_TRUE(s.ToString().find("comparator") != std::string::npos)
1293
+ << s.ToString();
1294
+ }
1295
+
1296
+ TEST(DBTest, CustomComparator) {
1297
+ class NumberComparator : public Comparator {
1298
+ public:
1299
+ virtual const char* Name() const { return "test.NumberComparator"; }
1300
+ virtual int Compare(const Slice& a, const Slice& b) const {
1301
+ return ToNumber(a) - ToNumber(b);
1302
+ }
1303
+ virtual void FindShortestSeparator(std::string* s, const Slice& l) const {
1304
+ ToNumber(*s); // Check format
1305
+ ToNumber(l); // Check format
1306
+ }
1307
+ virtual void FindShortSuccessor(std::string* key) const {
1308
+ ToNumber(*key); // Check format
1309
+ }
1310
+ private:
1311
+ static int ToNumber(const Slice& x) {
1312
+ // Check that there are no extra characters.
1313
+ ASSERT_TRUE(x.size() >= 2 && x[0] == '[' && x[x.size()-1] == ']')
1314
+ << EscapeString(x);
1315
+ int val;
1316
+ char ignored;
1317
+ ASSERT_TRUE(sscanf(x.ToString().c_str(), "[%i]%c", &val, &ignored) == 1)
1318
+ << EscapeString(x);
1319
+ return val;
1320
+ }
1321
+ };
1322
+ NumberComparator cmp;
1323
+ Options new_options = CurrentOptions();
1324
+ new_options.create_if_missing = true;
1325
+ new_options.comparator = &cmp;
1326
+ new_options.filter_policy = NULL; // Cannot use bloom filters
1327
+ new_options.write_buffer_size = 1000; // Compact more often
1328
+ DestroyAndReopen(&new_options);
1329
+ ASSERT_OK(Put("[10]", "ten"));
1330
+ ASSERT_OK(Put("[0x14]", "twenty"));
1331
+ for (int i = 0; i < 2; i++) {
1332
+ ASSERT_EQ("ten", Get("[10]"));
1333
+ ASSERT_EQ("ten", Get("[0xa]"));
1334
+ ASSERT_EQ("twenty", Get("[20]"));
1335
+ ASSERT_EQ("twenty", Get("[0x14]"));
1336
+ ASSERT_EQ("NOT_FOUND", Get("[15]"));
1337
+ ASSERT_EQ("NOT_FOUND", Get("[0xf]"));
1338
+ Compact("[0]", "[9999]");
1339
+ }
1340
+
1341
+ for (int run = 0; run < 2; run++) {
1342
+ for (int i = 0; i < 1000; i++) {
1343
+ char buf[100];
1344
+ snprintf(buf, sizeof(buf), "[%d]", i*10);
1345
+ ASSERT_OK(Put(buf, buf));
1346
+ }
1347
+ Compact("[0]", "[1000000]");
1348
+ }
1349
+ }
1350
+
1351
+ TEST(DBTest, ManualCompaction) {
1352
+ ASSERT_EQ(config::kMaxMemCompactLevel, 2)
1353
+ << "Need to update this test to match kMaxMemCompactLevel";
1354
+
1355
+ MakeTables(3, "p", "q");
1356
+ ASSERT_EQ("1,1,1", FilesPerLevel());
1357
+
1358
+ // Compaction range falls before files
1359
+ Compact("", "c");
1360
+ ASSERT_EQ("1,1,1", FilesPerLevel());
1361
+
1362
+ // Compaction range falls after files
1363
+ Compact("r", "z");
1364
+ ASSERT_EQ("1,1,1", FilesPerLevel());
1365
+
1366
+ // Compaction range overlaps files
1367
+ Compact("p1", "p9");
1368
+ ASSERT_EQ("0,0,1", FilesPerLevel());
1369
+
1370
+ // Populate a different range
1371
+ MakeTables(3, "c", "e");
1372
+ ASSERT_EQ("1,1,2", FilesPerLevel());
1373
+
1374
+ // Compact just the new range
1375
+ Compact("b", "f");
1376
+ ASSERT_EQ("0,0,2", FilesPerLevel());
1377
+
1378
+ // Compact all
1379
+ MakeTables(1, "a", "z");
1380
+ ASSERT_EQ("0,1,2", FilesPerLevel());
1381
+ db_->CompactRange(NULL, NULL);
1382
+ ASSERT_EQ("0,0,1", FilesPerLevel());
1383
+ }
1384
+
1385
+ TEST(DBTest, DBOpen_Options) {
1386
+ std::string dbname = test::TmpDir() + "/db_options_test";
1387
+ DestroyDB(dbname, Options());
1388
+
1389
+ // Does not exist, and create_if_missing == false: error
1390
+ DB* db = NULL;
1391
+ Options opts;
1392
+ opts.create_if_missing = false;
1393
+ Status s = DB::Open(opts, dbname, &db);
1394
+ ASSERT_TRUE(strstr(s.ToString().c_str(), "does not exist") != NULL);
1395
+ ASSERT_TRUE(db == NULL);
1396
+
1397
+ // Does not exist, and create_if_missing == true: OK
1398
+ opts.create_if_missing = true;
1399
+ s = DB::Open(opts, dbname, &db);
1400
+ ASSERT_OK(s);
1401
+ ASSERT_TRUE(db != NULL);
1402
+
1403
+ delete db;
1404
+ db = NULL;
1405
+
1406
+ // Does exist, and error_if_exists == true: error
1407
+ opts.create_if_missing = false;
1408
+ opts.error_if_exists = true;
1409
+ s = DB::Open(opts, dbname, &db);
1410
+ ASSERT_TRUE(strstr(s.ToString().c_str(), "exists") != NULL);
1411
+ ASSERT_TRUE(db == NULL);
1412
+
1413
+ // Does exist, and error_if_exists == false: OK
1414
+ opts.create_if_missing = true;
1415
+ opts.error_if_exists = false;
1416
+ s = DB::Open(opts, dbname, &db);
1417
+ ASSERT_OK(s);
1418
+ ASSERT_TRUE(db != NULL);
1419
+
1420
+ delete db;
1421
+ db = NULL;
1422
+ }
1423
+
1424
+ // Check that number of files does not grow when we are out of space
1425
+ TEST(DBTest, NoSpace) {
1426
+ Options options = CurrentOptions();
1427
+ options.env = env_;
1428
+ Reopen(&options);
1429
+
1430
+ ASSERT_OK(Put("foo", "v1"));
1431
+ ASSERT_EQ("v1", Get("foo"));
1432
+ Compact("a", "z");
1433
+ const int num_files = CountFiles();
1434
+ env_->no_space_.Release_Store(env_); // Force out-of-space errors
1435
+ for (int i = 0; i < 10; i++) {
1436
+ for (int level = 0; level < config::kNumLevels-1; level++) {
1437
+ dbfull()->TEST_CompactRange(level, NULL, NULL);
1438
+ }
1439
+ }
1440
+ env_->no_space_.Release_Store(NULL);
1441
+ ASSERT_LT(CountFiles(), num_files + 5);
1442
+ }
1443
+
1444
+ TEST(DBTest, FilesDeletedAfterCompaction) {
1445
+ ASSERT_OK(Put("foo", "v2"));
1446
+ Compact("a", "z");
1447
+ const int num_files = CountFiles();
1448
+ for (int i = 0; i < 10; i++) {
1449
+ ASSERT_OK(Put("foo", "v2"));
1450
+ Compact("a", "z");
1451
+ }
1452
+ ASSERT_EQ(CountFiles(), num_files);
1453
+ }
1454
+
1455
+ TEST(DBTest, BloomFilter) {
1456
+ env_->count_random_reads_ = true;
1457
+ Options options = CurrentOptions();
1458
+ options.env = env_;
1459
+ options.block_cache = NewLRUCache(0); // Prevent cache hits
1460
+ options.filter_policy = NewBloomFilterPolicy(10);
1461
+ Reopen(&options);
1462
+
1463
+ // Populate multiple layers
1464
+ const int N = 10000;
1465
+ for (int i = 0; i < N; i++) {
1466
+ ASSERT_OK(Put(Key(i), Key(i)));
1467
+ }
1468
+ Compact("a", "z");
1469
+ for (int i = 0; i < N; i += 100) {
1470
+ ASSERT_OK(Put(Key(i), Key(i)));
1471
+ }
1472
+ dbfull()->TEST_CompactMemTable();
1473
+
1474
+ // Prevent auto compactions triggered by seeks
1475
+ env_->delay_sstable_sync_.Release_Store(env_);
1476
+
1477
+ // Lookup present keys. Should rarely read from small sstable.
1478
+ env_->random_read_counter_.Reset();
1479
+ for (int i = 0; i < N; i++) {
1480
+ ASSERT_EQ(Key(i), Get(Key(i)));
1481
+ }
1482
+ int reads = env_->random_read_counter_.Read();
1483
+ fprintf(stderr, "%d present => %d reads\n", N, reads);
1484
+ ASSERT_GE(reads, N);
1485
+ ASSERT_LE(reads, N + 2*N/100);
1486
+
1487
+ // Lookup present keys. Should rarely read from either sstable.
1488
+ env_->random_read_counter_.Reset();
1489
+ for (int i = 0; i < N; i++) {
1490
+ ASSERT_EQ("NOT_FOUND", Get(Key(i) + ".missing"));
1491
+ }
1492
+ reads = env_->random_read_counter_.Read();
1493
+ fprintf(stderr, "%d missing => %d reads\n", N, reads);
1494
+ ASSERT_LE(reads, 3*N/100);
1495
+
1496
+ env_->delay_sstable_sync_.Release_Store(NULL);
1497
+ Close();
1498
+ delete options.block_cache;
1499
+ delete options.filter_policy;
1500
+ }
1501
+
1502
+ // Multi-threaded test:
1503
+ namespace {
1504
+
1505
+ static const int kNumThreads = 4;
1506
+ static const int kTestSeconds = 10;
1507
+ static const int kNumKeys = 1000;
1508
+
1509
+ struct MTState {
1510
+ DBTest* test;
1511
+ port::AtomicPointer stop;
1512
+ port::AtomicPointer counter[kNumThreads];
1513
+ port::AtomicPointer thread_done[kNumThreads];
1514
+ };
1515
+
1516
+ struct MTThread {
1517
+ MTState* state;
1518
+ int id;
1519
+ };
1520
+
1521
+ static void MTThreadBody(void* arg) {
1522
+ MTThread* t = reinterpret_cast<MTThread*>(arg);
1523
+ int id = t->id;
1524
+ DB* db = t->state->test->db_;
1525
+ uintptr_t counter = 0;
1526
+ fprintf(stderr, "... starting thread %d\n", id);
1527
+ Random rnd(1000 + id);
1528
+ std::string value;
1529
+ char valbuf[1500];
1530
+ while (t->state->stop.Acquire_Load() == NULL) {
1531
+ t->state->counter[id].Release_Store(reinterpret_cast<void*>(counter));
1532
+
1533
+ int key = rnd.Uniform(kNumKeys);
1534
+ char keybuf[20];
1535
+ snprintf(keybuf, sizeof(keybuf), "%016d", key);
1536
+
1537
+ if (rnd.OneIn(2)) {
1538
+ // Write values of the form <key, my id, counter>.
1539
+ // We add some padding for force compactions.
1540
+ snprintf(valbuf, sizeof(valbuf), "%d.%d.%-1000d",
1541
+ key, id, static_cast<int>(counter));
1542
+ ASSERT_OK(db->Put(WriteOptions(), Slice(keybuf), Slice(valbuf)));
1543
+ } else {
1544
+ // Read a value and verify that it matches the pattern written above.
1545
+ Status s = db->Get(ReadOptions(), Slice(keybuf), &value);
1546
+ if (s.IsNotFound()) {
1547
+ // Key has not yet been written
1548
+ } else {
1549
+ // Check that the writer thread counter is >= the counter in the value
1550
+ ASSERT_OK(s);
1551
+ int k, w, c;
1552
+ ASSERT_EQ(3, sscanf(value.c_str(), "%d.%d.%d", &k, &w, &c)) << value;
1553
+ ASSERT_EQ(k, key);
1554
+ ASSERT_GE(w, 0);
1555
+ ASSERT_LT(w, kNumThreads);
1556
+ ASSERT_LE(c, reinterpret_cast<uintptr_t>(
1557
+ t->state->counter[w].Acquire_Load()));
1558
+ }
1559
+ }
1560
+ counter++;
1561
+ }
1562
+ t->state->thread_done[id].Release_Store(t);
1563
+ fprintf(stderr, "... stopping thread %d after %d ops\n", id, int(counter));
1564
+ }
1565
+
1566
+ } // namespace
1567
+
1568
+ TEST(DBTest, MultiThreaded) {
1569
+ do {
1570
+ // Initialize state
1571
+ MTState mt;
1572
+ mt.test = this;
1573
+ mt.stop.Release_Store(0);
1574
+ for (int id = 0; id < kNumThreads; id++) {
1575
+ mt.counter[id].Release_Store(0);
1576
+ mt.thread_done[id].Release_Store(0);
1577
+ }
1578
+
1579
+ // Start threads
1580
+ MTThread thread[kNumThreads];
1581
+ for (int id = 0; id < kNumThreads; id++) {
1582
+ thread[id].state = &mt;
1583
+ thread[id].id = id;
1584
+ env_->StartThread(MTThreadBody, &thread[id]);
1585
+ }
1586
+
1587
+ // Let them run for a while
1588
+ env_->SleepForMicroseconds(kTestSeconds * 1000000);
1589
+
1590
+ // Stop the threads and wait for them to finish
1591
+ mt.stop.Release_Store(&mt);
1592
+ for (int id = 0; id < kNumThreads; id++) {
1593
+ while (mt.thread_done[id].Acquire_Load() == NULL) {
1594
+ env_->SleepForMicroseconds(100000);
1595
+ }
1596
+ }
1597
+ } while (ChangeOptions());
1598
+ }
1599
+
1600
+ namespace {
1601
+ typedef std::map<std::string, std::string> KVMap;
1602
+ }
1603
+
1604
+ class ModelDB: public DB {
1605
+ public:
1606
+ class ModelSnapshot : public Snapshot {
1607
+ public:
1608
+ KVMap map_;
1609
+ };
1610
+
1611
+ explicit ModelDB(const Options& options): options_(options) { }
1612
+ ~ModelDB() { }
1613
+ virtual Status Put(const WriteOptions& o, const Slice& k, const Slice& v) {
1614
+ return DB::Put(o, k, v);
1615
+ }
1616
+ virtual Status Delete(const WriteOptions& o, const Slice& key) {
1617
+ return DB::Delete(o, key);
1618
+ }
1619
+ virtual Status Get(const ReadOptions& options,
1620
+ const Slice& key, std::string* value) {
1621
+ assert(false); // Not implemented
1622
+ return Status::NotFound(key);
1623
+ }
1624
+ virtual Iterator* NewIterator(const ReadOptions& options) {
1625
+ if (options.snapshot == NULL) {
1626
+ KVMap* saved = new KVMap;
1627
+ *saved = map_;
1628
+ return new ModelIter(saved, true);
1629
+ } else {
1630
+ const KVMap* snapshot_state =
1631
+ &(reinterpret_cast<const ModelSnapshot*>(options.snapshot)->map_);
1632
+ return new ModelIter(snapshot_state, false);
1633
+ }
1634
+ }
1635
+ virtual const Snapshot* GetSnapshot() {
1636
+ ModelSnapshot* snapshot = new ModelSnapshot;
1637
+ snapshot->map_ = map_;
1638
+ return snapshot;
1639
+ }
1640
+
1641
+ virtual void ReleaseSnapshot(const Snapshot* snapshot) {
1642
+ delete reinterpret_cast<const ModelSnapshot*>(snapshot);
1643
+ }
1644
+ virtual Status Write(const WriteOptions& options, WriteBatch* batch) {
1645
+ class Handler : public WriteBatch::Handler {
1646
+ public:
1647
+ KVMap* map_;
1648
+ virtual void Put(const Slice& key, const Slice& value) {
1649
+ (*map_)[key.ToString()] = value.ToString();
1650
+ }
1651
+ virtual void Delete(const Slice& key) {
1652
+ map_->erase(key.ToString());
1653
+ }
1654
+ };
1655
+ Handler handler;
1656
+ handler.map_ = &map_;
1657
+ return batch->Iterate(&handler);
1658
+ }
1659
+
1660
+ virtual bool GetProperty(const Slice& property, std::string* value) {
1661
+ return false;
1662
+ }
1663
+ virtual void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) {
1664
+ for (int i = 0; i < n; i++) {
1665
+ sizes[i] = 0;
1666
+ }
1667
+ }
1668
+ virtual void CompactRange(const Slice* start, const Slice* end) {
1669
+ }
1670
+
1671
+ private:
1672
+ class ModelIter: public Iterator {
1673
+ public:
1674
+ ModelIter(const KVMap* map, bool owned)
1675
+ : map_(map), owned_(owned), iter_(map_->end()) {
1676
+ }
1677
+ ~ModelIter() {
1678
+ if (owned_) delete map_;
1679
+ }
1680
+ virtual bool Valid() const { return iter_ != map_->end(); }
1681
+ virtual void SeekToFirst() { iter_ = map_->begin(); }
1682
+ virtual void SeekToLast() {
1683
+ if (map_->empty()) {
1684
+ iter_ = map_->end();
1685
+ } else {
1686
+ iter_ = map_->find(map_->rbegin()->first);
1687
+ }
1688
+ }
1689
+ virtual void Seek(const Slice& k) {
1690
+ iter_ = map_->lower_bound(k.ToString());
1691
+ }
1692
+ virtual void Next() { ++iter_; }
1693
+ virtual void Prev() { --iter_; }
1694
+ virtual Slice key() const { return iter_->first; }
1695
+ virtual Slice value() const { return iter_->second; }
1696
+ virtual Status status() const { return Status::OK(); }
1697
+ private:
1698
+ const KVMap* const map_;
1699
+ const bool owned_; // Do we own map_
1700
+ KVMap::const_iterator iter_;
1701
+ };
1702
+ const Options options_;
1703
+ KVMap map_;
1704
+ };
1705
+
1706
+ static std::string RandomKey(Random* rnd) {
1707
+ int len = (rnd->OneIn(3)
1708
+ ? 1 // Short sometimes to encourage collisions
1709
+ : (rnd->OneIn(100) ? rnd->Skewed(10) : rnd->Uniform(10)));
1710
+ return test::RandomKey(rnd, len);
1711
+ }
1712
+
1713
+ static bool CompareIterators(int step,
1714
+ DB* model,
1715
+ DB* db,
1716
+ const Snapshot* model_snap,
1717
+ const Snapshot* db_snap) {
1718
+ ReadOptions options;
1719
+ options.snapshot = model_snap;
1720
+ Iterator* miter = model->NewIterator(options);
1721
+ options.snapshot = db_snap;
1722
+ Iterator* dbiter = db->NewIterator(options);
1723
+ bool ok = true;
1724
+ int count = 0;
1725
+ for (miter->SeekToFirst(), dbiter->SeekToFirst();
1726
+ ok && miter->Valid() && dbiter->Valid();
1727
+ miter->Next(), dbiter->Next()) {
1728
+ count++;
1729
+ if (miter->key().compare(dbiter->key()) != 0) {
1730
+ fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n",
1731
+ step,
1732
+ EscapeString(miter->key()).c_str(),
1733
+ EscapeString(dbiter->key()).c_str());
1734
+ ok = false;
1735
+ break;
1736
+ }
1737
+
1738
+ if (miter->value().compare(dbiter->value()) != 0) {
1739
+ fprintf(stderr, "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n",
1740
+ step,
1741
+ EscapeString(miter->key()).c_str(),
1742
+ EscapeString(miter->value()).c_str(),
1743
+ EscapeString(miter->value()).c_str());
1744
+ ok = false;
1745
+ }
1746
+ }
1747
+
1748
+ if (ok) {
1749
+ if (miter->Valid() != dbiter->Valid()) {
1750
+ fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n",
1751
+ step, miter->Valid(), dbiter->Valid());
1752
+ ok = false;
1753
+ }
1754
+ }
1755
+ fprintf(stderr, "%d entries compared: ok=%d\n", count, ok);
1756
+ delete miter;
1757
+ delete dbiter;
1758
+ return ok;
1759
+ }
1760
+
1761
+ TEST(DBTest, Randomized) {
1762
+ Random rnd(test::RandomSeed());
1763
+ do {
1764
+ ModelDB model(CurrentOptions());
1765
+ const int N = 10000;
1766
+ const Snapshot* model_snap = NULL;
1767
+ const Snapshot* db_snap = NULL;
1768
+ std::string k, v;
1769
+ for (int step = 0; step < N; step++) {
1770
+ if (step % 100 == 0) {
1771
+ fprintf(stderr, "Step %d of %d\n", step, N);
1772
+ }
1773
+ // TODO(sanjay): Test Get() works
1774
+ int p = rnd.Uniform(100);
1775
+ if (p < 45) { // Put
1776
+ k = RandomKey(&rnd);
1777
+ v = RandomString(&rnd,
1778
+ rnd.OneIn(20)
1779
+ ? 100 + rnd.Uniform(100)
1780
+ : rnd.Uniform(8));
1781
+ ASSERT_OK(model.Put(WriteOptions(), k, v));
1782
+ ASSERT_OK(db_->Put(WriteOptions(), k, v));
1783
+
1784
+ } else if (p < 90) { // Delete
1785
+ k = RandomKey(&rnd);
1786
+ ASSERT_OK(model.Delete(WriteOptions(), k));
1787
+ ASSERT_OK(db_->Delete(WriteOptions(), k));
1788
+
1789
+
1790
+ } else { // Multi-element batch
1791
+ WriteBatch b;
1792
+ const int num = rnd.Uniform(8);
1793
+ for (int i = 0; i < num; i++) {
1794
+ if (i == 0 || !rnd.OneIn(10)) {
1795
+ k = RandomKey(&rnd);
1796
+ } else {
1797
+ // Periodically re-use the same key from the previous iter, so
1798
+ // we have multiple entries in the write batch for the same key
1799
+ }
1800
+ if (rnd.OneIn(2)) {
1801
+ v = RandomString(&rnd, rnd.Uniform(10));
1802
+ b.Put(k, v);
1803
+ } else {
1804
+ b.Delete(k);
1805
+ }
1806
+ }
1807
+ ASSERT_OK(model.Write(WriteOptions(), &b));
1808
+ ASSERT_OK(db_->Write(WriteOptions(), &b));
1809
+ }
1810
+
1811
+ if ((step % 100) == 0) {
1812
+ ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL));
1813
+ ASSERT_TRUE(CompareIterators(step, &model, db_, model_snap, db_snap));
1814
+ // Save a snapshot from each DB this time that we'll use next
1815
+ // time we compare things, to make sure the current state is
1816
+ // preserved with the snapshot
1817
+ if (model_snap != NULL) model.ReleaseSnapshot(model_snap);
1818
+ if (db_snap != NULL) db_->ReleaseSnapshot(db_snap);
1819
+
1820
+ Reopen();
1821
+ ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL));
1822
+
1823
+ model_snap = model.GetSnapshot();
1824
+ db_snap = db_->GetSnapshot();
1825
+ }
1826
+ }
1827
+ if (model_snap != NULL) model.ReleaseSnapshot(model_snap);
1828
+ if (db_snap != NULL) db_->ReleaseSnapshot(db_snap);
1829
+ } while (ChangeOptions());
1830
+ }
1831
+
1832
+ std::string MakeKey(unsigned int num) {
1833
+ char buf[30];
1834
+ snprintf(buf, sizeof(buf), "%016u", num);
1835
+ return std::string(buf);
1836
+ }
1837
+
1838
+ void BM_LogAndApply(int iters, int num_base_files) {
1839
+ std::string dbname = test::TmpDir() + "/leveldb_test_benchmark";
1840
+ DestroyDB(dbname, Options());
1841
+
1842
+ DB* db = NULL;
1843
+ Options opts;
1844
+ opts.create_if_missing = true;
1845
+ Status s = DB::Open(opts, dbname, &db);
1846
+ ASSERT_OK(s);
1847
+ ASSERT_TRUE(db != NULL);
1848
+
1849
+ delete db;
1850
+ db = NULL;
1851
+
1852
+ Env* env = Env::Default();
1853
+
1854
+ port::Mutex mu;
1855
+ MutexLock l(&mu);
1856
+
1857
+ InternalKeyComparator cmp(BytewiseComparator());
1858
+ Options options;
1859
+ VersionSet vset(dbname, &options, NULL, &cmp);
1860
+ ASSERT_OK(vset.Recover());
1861
+ VersionEdit vbase;
1862
+ uint64_t fnum = 1;
1863
+ for (int i = 0; i < num_base_files; i++) {
1864
+ InternalKey start(MakeKey(2*fnum), 1, kTypeValue);
1865
+ InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion);
1866
+ vbase.AddFile(2, fnum++, 1 /* file size */, start, limit);
1867
+ }
1868
+ ASSERT_OK(vset.LogAndApply(&vbase, &mu));
1869
+
1870
+ uint64_t start_micros = env->NowMicros();
1871
+
1872
+ for (int i = 0; i < iters; i++) {
1873
+ VersionEdit vedit;
1874
+ vedit.DeleteFile(2, fnum);
1875
+ InternalKey start(MakeKey(2*fnum), 1, kTypeValue);
1876
+ InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion);
1877
+ vedit.AddFile(2, fnum++, 1 /* file size */, start, limit);
1878
+ vset.LogAndApply(&vedit, &mu);
1879
+ }
1880
+ uint64_t stop_micros = env->NowMicros();
1881
+ unsigned int us = stop_micros - start_micros;
1882
+ char buf[16];
1883
+ snprintf(buf, sizeof(buf), "%d", num_base_files);
1884
+ fprintf(stderr,
1885
+ "BM_LogAndApply/%-6s %8d iters : %9u us (%7.0f us / iter)\n",
1886
+ buf, iters, us, ((float)us) / iters);
1887
+ }
1888
+
1889
+ } // namespace leveldb
1890
+
1891
+ int main(int argc, char** argv) {
1892
+ if (argc > 1 && std::string(argv[1]) == "--benchmark") {
1893
+ leveldb::BM_LogAndApply(1000, 1);
1894
+ leveldb::BM_LogAndApply(1000, 100);
1895
+ leveldb::BM_LogAndApply(1000, 10000);
1896
+ leveldb::BM_LogAndApply(100, 100000);
1897
+ return 0;
1898
+ }
1899
+
1900
+ return leveldb::test::RunAllTests();
1901
+ }