leveldb-ruby 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/README +17 -0
  2. data/ext/leveldb/extconf.rb +10 -0
  3. data/ext/leveldb/leveldb.cc +181 -0
  4. data/leveldb/Makefile +172 -0
  5. data/leveldb/db/builder.cc +90 -0
  6. data/leveldb/db/builder.h +36 -0
  7. data/leveldb/db/corruption_test.cc +354 -0
  8. data/leveldb/db/db_bench.cc +677 -0
  9. data/leveldb/db/db_impl.cc +1236 -0
  10. data/leveldb/db/db_impl.h +180 -0
  11. data/leveldb/db/db_iter.cc +298 -0
  12. data/leveldb/db/db_iter.h +26 -0
  13. data/leveldb/db/db_test.cc +1192 -0
  14. data/leveldb/db/dbformat.cc +87 -0
  15. data/leveldb/db/dbformat.h +165 -0
  16. data/leveldb/db/dbformat_test.cc +112 -0
  17. data/leveldb/db/filename.cc +135 -0
  18. data/leveldb/db/filename.h +80 -0
  19. data/leveldb/db/filename_test.cc +122 -0
  20. data/leveldb/db/log_format.h +35 -0
  21. data/leveldb/db/log_reader.cc +254 -0
  22. data/leveldb/db/log_reader.h +108 -0
  23. data/leveldb/db/log_test.cc +500 -0
  24. data/leveldb/db/log_writer.cc +103 -0
  25. data/leveldb/db/log_writer.h +48 -0
  26. data/leveldb/db/memtable.cc +108 -0
  27. data/leveldb/db/memtable.h +85 -0
  28. data/leveldb/db/repair.cc +384 -0
  29. data/leveldb/db/skiplist.h +378 -0
  30. data/leveldb/db/skiplist_test.cc +378 -0
  31. data/leveldb/db/snapshot.h +66 -0
  32. data/leveldb/db/table_cache.cc +95 -0
  33. data/leveldb/db/table_cache.h +50 -0
  34. data/leveldb/db/version_edit.cc +268 -0
  35. data/leveldb/db/version_edit.h +106 -0
  36. data/leveldb/db/version_edit_test.cc +46 -0
  37. data/leveldb/db/version_set.cc +1060 -0
  38. data/leveldb/db/version_set.h +306 -0
  39. data/leveldb/db/write_batch.cc +138 -0
  40. data/leveldb/db/write_batch_internal.h +45 -0
  41. data/leveldb/db/write_batch_test.cc +89 -0
  42. data/leveldb/include/leveldb/cache.h +99 -0
  43. data/leveldb/include/leveldb/comparator.h +63 -0
  44. data/leveldb/include/leveldb/db.h +148 -0
  45. data/leveldb/include/leveldb/env.h +302 -0
  46. data/leveldb/include/leveldb/iterator.h +100 -0
  47. data/leveldb/include/leveldb/options.h +198 -0
  48. data/leveldb/include/leveldb/slice.h +109 -0
  49. data/leveldb/include/leveldb/status.h +100 -0
  50. data/leveldb/include/leveldb/table.h +70 -0
  51. data/leveldb/include/leveldb/table_builder.h +91 -0
  52. data/leveldb/include/leveldb/write_batch.h +64 -0
  53. data/leveldb/port/port.h +23 -0
  54. data/leveldb/port/port_android.cc +64 -0
  55. data/leveldb/port/port_android.h +150 -0
  56. data/leveldb/port/port_chromium.cc +80 -0
  57. data/leveldb/port/port_chromium.h +97 -0
  58. data/leveldb/port/port_example.h +115 -0
  59. data/leveldb/port/port_osx.cc +50 -0
  60. data/leveldb/port/port_osx.h +125 -0
  61. data/leveldb/port/port_posix.cc +50 -0
  62. data/leveldb/port/port_posix.h +94 -0
  63. data/leveldb/port/sha1_portable.cc +298 -0
  64. data/leveldb/port/sha1_portable.h +25 -0
  65. data/leveldb/port/sha1_test.cc +39 -0
  66. data/leveldb/port/win/stdint.h +24 -0
  67. data/leveldb/table/block.cc +263 -0
  68. data/leveldb/table/block.h +43 -0
  69. data/leveldb/table/block_builder.cc +109 -0
  70. data/leveldb/table/block_builder.h +57 -0
  71. data/leveldb/table/format.cc +131 -0
  72. data/leveldb/table/format.h +103 -0
  73. data/leveldb/table/iterator.cc +67 -0
  74. data/leveldb/table/iterator_wrapper.h +63 -0
  75. data/leveldb/table/merger.cc +197 -0
  76. data/leveldb/table/merger.h +26 -0
  77. data/leveldb/table/table.cc +175 -0
  78. data/leveldb/table/table_builder.cc +227 -0
  79. data/leveldb/table/table_test.cc +845 -0
  80. data/leveldb/table/two_level_iterator.cc +182 -0
  81. data/leveldb/table/two_level_iterator.h +34 -0
  82. data/leveldb/util/arena.cc +68 -0
  83. data/leveldb/util/arena.h +68 -0
  84. data/leveldb/util/arena_test.cc +68 -0
  85. data/leveldb/util/cache.cc +255 -0
  86. data/leveldb/util/cache_test.cc +169 -0
  87. data/leveldb/util/coding.cc +194 -0
  88. data/leveldb/util/coding.h +104 -0
  89. data/leveldb/util/coding_test.cc +173 -0
  90. data/leveldb/util/comparator.cc +72 -0
  91. data/leveldb/util/crc32c.cc +332 -0
  92. data/leveldb/util/crc32c.h +45 -0
  93. data/leveldb/util/crc32c_test.cc +72 -0
  94. data/leveldb/util/env.cc +77 -0
  95. data/leveldb/util/env_chromium.cc +612 -0
  96. data/leveldb/util/env_posix.cc +606 -0
  97. data/leveldb/util/env_test.cc +102 -0
  98. data/leveldb/util/hash.cc +45 -0
  99. data/leveldb/util/hash.h +19 -0
  100. data/leveldb/util/histogram.cc +128 -0
  101. data/leveldb/util/histogram.h +41 -0
  102. data/leveldb/util/logging.cc +81 -0
  103. data/leveldb/util/logging.h +47 -0
  104. data/leveldb/util/mutexlock.h +39 -0
  105. data/leveldb/util/options.cc +28 -0
  106. data/leveldb/util/random.h +59 -0
  107. data/leveldb/util/status.cc +75 -0
  108. data/leveldb/util/testharness.cc +65 -0
  109. data/leveldb/util/testharness.h +129 -0
  110. data/leveldb/util/testutil.cc +51 -0
  111. data/leveldb/util/testutil.h +53 -0
  112. data/lib/leveldb.rb +36 -0
  113. metadata +183 -0
@@ -0,0 +1,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
+ }
25
+
26
+ #endif // STORAGE_LEVELDB_DB_DB_ITER_H_
@@ -0,0 +1,1192 @@
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 "db/db_impl.h"
7
+ #include "db/filename.h"
8
+ #include "db/version_set.h"
9
+ #include "db/write_batch_internal.h"
10
+ #include "leveldb/env.h"
11
+ #include "leveldb/table.h"
12
+ #include "util/logging.h"
13
+ #include "util/testharness.h"
14
+ #include "util/testutil.h"
15
+
16
+ namespace leveldb {
17
+
18
+ static std::string RandomString(Random* rnd, int len) {
19
+ std::string r;
20
+ test::RandomString(rnd, len, &r);
21
+ return r;
22
+ }
23
+
24
+ class DBTest {
25
+ public:
26
+ std::string dbname_;
27
+ Env* env_;
28
+ DB* db_;
29
+
30
+ Options last_options_;
31
+
32
+ DBTest() : env_(Env::Default()) {
33
+ dbname_ = test::TmpDir() + "/db_test";
34
+ DestroyDB(dbname_, Options());
35
+ db_ = NULL;
36
+ Reopen();
37
+ }
38
+
39
+ ~DBTest() {
40
+ delete db_;
41
+ DestroyDB(dbname_, Options());
42
+ }
43
+
44
+ DBImpl* dbfull() {
45
+ return reinterpret_cast<DBImpl*>(db_);
46
+ }
47
+
48
+ void Reopen(Options* options = NULL) {
49
+ ASSERT_OK(TryReopen(options));
50
+ }
51
+
52
+ void DestroyAndReopen(Options* options = NULL) {
53
+ delete db_;
54
+ db_ = NULL;
55
+ DestroyDB(dbname_, Options());
56
+ ASSERT_OK(TryReopen(options));
57
+ }
58
+
59
+ Status TryReopen(Options* options) {
60
+ delete db_;
61
+ db_ = NULL;
62
+ Options opts;
63
+ if (options != NULL) {
64
+ opts = *options;
65
+ } else {
66
+ opts.create_if_missing = true;
67
+ }
68
+ last_options_ = opts;
69
+
70
+ return DB::Open(opts, dbname_, &db_);
71
+ }
72
+
73
+ Status Put(const std::string& k, const std::string& v) {
74
+ return db_->Put(WriteOptions(), k, v);
75
+ }
76
+
77
+ Status Delete(const std::string& k) {
78
+ return db_->Delete(WriteOptions(), k);
79
+ }
80
+
81
+ std::string Get(const std::string& k, const Snapshot* snapshot = NULL) {
82
+ ReadOptions options;
83
+ options.snapshot = snapshot;
84
+ std::string result;
85
+ Status s = db_->Get(options, k, &result);
86
+ if (s.IsNotFound()) {
87
+ result = "NOT_FOUND";
88
+ } else if (!s.ok()) {
89
+ result = s.ToString();
90
+ }
91
+ return result;
92
+ }
93
+
94
+ std::string AllEntriesFor(const Slice& user_key) {
95
+ Iterator* iter = dbfull()->TEST_NewInternalIterator();
96
+ InternalKey target(user_key, kMaxSequenceNumber, kTypeValue);
97
+ iter->Seek(target.Encode());
98
+ std::string result;
99
+ if (!iter->status().ok()) {
100
+ result = iter->status().ToString();
101
+ } else {
102
+ result = "[ ";
103
+ bool first = true;
104
+ while (iter->Valid()) {
105
+ ParsedInternalKey ikey;
106
+ if (!ParseInternalKey(iter->key(), &ikey)) {
107
+ result += "CORRUPTED";
108
+ } else {
109
+ if (last_options_.comparator->Compare(
110
+ ikey.user_key, user_key) != 0) {
111
+ break;
112
+ }
113
+ if (!first) {
114
+ result += ", ";
115
+ }
116
+ first = false;
117
+ switch (ikey.type) {
118
+ case kTypeValue:
119
+ result += iter->value().ToString();
120
+ break;
121
+ case kTypeDeletion:
122
+ result += "DEL";
123
+ break;
124
+ }
125
+ }
126
+ iter->Next();
127
+ }
128
+ if (!first) {
129
+ result += " ";
130
+ }
131
+ result += "]";
132
+ }
133
+ delete iter;
134
+ return result;
135
+ }
136
+
137
+ int NumTableFilesAtLevel(int level) {
138
+ std::string property;
139
+ ASSERT_TRUE(
140
+ db_->GetProperty("leveldb.num-files-at-level" + NumberToString(level),
141
+ &property));
142
+ return atoi(property.c_str());
143
+ }
144
+
145
+ uint64_t Size(const Slice& start, const Slice& limit) {
146
+ Range r(start, limit);
147
+ uint64_t size;
148
+ db_->GetApproximateSizes(&r, 1, &size);
149
+ return size;
150
+ }
151
+
152
+ void Compact(const Slice& start, const Slice& limit) {
153
+ dbfull()->TEST_CompactMemTable();
154
+ int max_level_with_files = 1;
155
+ for (int level = 1; level < config::kNumLevels; level++) {
156
+ if (NumTableFilesAtLevel(level) > 0) {
157
+ max_level_with_files = level;
158
+ }
159
+ }
160
+ for (int level = 0; level < max_level_with_files; level++) {
161
+ dbfull()->TEST_CompactRange(level, "", "~");
162
+ }
163
+ }
164
+
165
+ void DumpFileCounts(const char* label) {
166
+ fprintf(stderr, "---\n%s:\n", label);
167
+ fprintf(stderr, "maxoverlap: %lld\n",
168
+ static_cast<long long>(
169
+ dbfull()->TEST_MaxNextLevelOverlappingBytes()));
170
+ for (int level = 0; level < config::kNumLevels; level++) {
171
+ int num = NumTableFilesAtLevel(level);
172
+ if (num > 0) {
173
+ fprintf(stderr, " level %3d : %d files\n", level, num);
174
+ }
175
+ }
176
+ }
177
+
178
+ std::string IterStatus(Iterator* iter) {
179
+ std::string result;
180
+ if (iter->Valid()) {
181
+ result = iter->key().ToString() + "->" + iter->value().ToString();
182
+ } else {
183
+ result = "(invalid)";
184
+ }
185
+ return result;
186
+ }
187
+ };
188
+
189
+ TEST(DBTest, Empty) {
190
+ ASSERT_TRUE(db_ != NULL);
191
+ ASSERT_EQ("NOT_FOUND", Get("foo"));
192
+ }
193
+
194
+ TEST(DBTest, ReadWrite) {
195
+ ASSERT_OK(Put("foo", "v1"));
196
+ ASSERT_EQ("v1", Get("foo"));
197
+ ASSERT_OK(Put("bar", "v2"));
198
+ ASSERT_OK(Put("foo", "v3"));
199
+ ASSERT_EQ("v3", Get("foo"));
200
+ ASSERT_EQ("v2", Get("bar"));
201
+ }
202
+
203
+ TEST(DBTest, PutDeleteGet) {
204
+ ASSERT_OK(db_->Put(WriteOptions(), "foo", "v1"));
205
+ ASSERT_EQ("v1", Get("foo"));
206
+ ASSERT_OK(db_->Put(WriteOptions(), "foo", "v2"));
207
+ ASSERT_EQ("v2", Get("foo"));
208
+ ASSERT_OK(db_->Delete(WriteOptions(), "foo"));
209
+ ASSERT_EQ("NOT_FOUND", Get("foo"));
210
+ }
211
+
212
+ TEST(DBTest, IterEmpty) {
213
+ Iterator* iter = db_->NewIterator(ReadOptions());
214
+
215
+ iter->SeekToFirst();
216
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
217
+
218
+ iter->SeekToLast();
219
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
220
+
221
+ iter->Seek("foo");
222
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
223
+
224
+ delete iter;
225
+ }
226
+
227
+ TEST(DBTest, IterSingle) {
228
+ ASSERT_OK(Put("a", "va"));
229
+ Iterator* iter = db_->NewIterator(ReadOptions());
230
+
231
+ iter->SeekToFirst();
232
+ ASSERT_EQ(IterStatus(iter), "a->va");
233
+ iter->Next();
234
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
235
+ iter->SeekToFirst();
236
+ ASSERT_EQ(IterStatus(iter), "a->va");
237
+ iter->Prev();
238
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
239
+
240
+ iter->SeekToLast();
241
+ ASSERT_EQ(IterStatus(iter), "a->va");
242
+ iter->Next();
243
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
244
+ iter->SeekToLast();
245
+ ASSERT_EQ(IterStatus(iter), "a->va");
246
+ iter->Prev();
247
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
248
+
249
+ iter->Seek("");
250
+ ASSERT_EQ(IterStatus(iter), "a->va");
251
+ iter->Next();
252
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
253
+
254
+ iter->Seek("a");
255
+ ASSERT_EQ(IterStatus(iter), "a->va");
256
+ iter->Next();
257
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
258
+
259
+ iter->Seek("b");
260
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
261
+
262
+ delete iter;
263
+ }
264
+
265
+ TEST(DBTest, IterMulti) {
266
+ ASSERT_OK(Put("a", "va"));
267
+ ASSERT_OK(Put("b", "vb"));
268
+ ASSERT_OK(Put("c", "vc"));
269
+ Iterator* iter = db_->NewIterator(ReadOptions());
270
+
271
+ iter->SeekToFirst();
272
+ ASSERT_EQ(IterStatus(iter), "a->va");
273
+ iter->Next();
274
+ ASSERT_EQ(IterStatus(iter), "b->vb");
275
+ iter->Next();
276
+ ASSERT_EQ(IterStatus(iter), "c->vc");
277
+ iter->Next();
278
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
279
+ iter->SeekToFirst();
280
+ ASSERT_EQ(IterStatus(iter), "a->va");
281
+ iter->Prev();
282
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
283
+
284
+ iter->SeekToLast();
285
+ ASSERT_EQ(IterStatus(iter), "c->vc");
286
+ iter->Prev();
287
+ ASSERT_EQ(IterStatus(iter), "b->vb");
288
+ iter->Prev();
289
+ ASSERT_EQ(IterStatus(iter), "a->va");
290
+ iter->Prev();
291
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
292
+ iter->SeekToLast();
293
+ ASSERT_EQ(IterStatus(iter), "c->vc");
294
+ iter->Next();
295
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
296
+
297
+ iter->Seek("");
298
+ ASSERT_EQ(IterStatus(iter), "a->va");
299
+ iter->Seek("a");
300
+ ASSERT_EQ(IterStatus(iter), "a->va");
301
+ iter->Seek("ax");
302
+ ASSERT_EQ(IterStatus(iter), "b->vb");
303
+ iter->Seek("b");
304
+ ASSERT_EQ(IterStatus(iter), "b->vb");
305
+ iter->Seek("z");
306
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
307
+
308
+ // Switch from reverse to forward
309
+ iter->SeekToLast();
310
+ iter->Prev();
311
+ iter->Prev();
312
+ iter->Next();
313
+ ASSERT_EQ(IterStatus(iter), "b->vb");
314
+
315
+ // Switch from forward to reverse
316
+ iter->SeekToFirst();
317
+ iter->Next();
318
+ iter->Next();
319
+ iter->Prev();
320
+ ASSERT_EQ(IterStatus(iter), "b->vb");
321
+
322
+ // Make sure iter stays at snapshot
323
+ ASSERT_OK(Put("a", "va2"));
324
+ ASSERT_OK(Put("a2", "va3"));
325
+ ASSERT_OK(Put("b", "vb2"));
326
+ ASSERT_OK(Put("c", "vc2"));
327
+ ASSERT_OK(Delete("b"));
328
+ iter->SeekToFirst();
329
+ ASSERT_EQ(IterStatus(iter), "a->va");
330
+ iter->Next();
331
+ ASSERT_EQ(IterStatus(iter), "b->vb");
332
+ iter->Next();
333
+ ASSERT_EQ(IterStatus(iter), "c->vc");
334
+ iter->Next();
335
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
336
+ iter->SeekToLast();
337
+ ASSERT_EQ(IterStatus(iter), "c->vc");
338
+ iter->Prev();
339
+ ASSERT_EQ(IterStatus(iter), "b->vb");
340
+ iter->Prev();
341
+ ASSERT_EQ(IterStatus(iter), "a->va");
342
+ iter->Prev();
343
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
344
+
345
+ delete iter;
346
+ }
347
+
348
+ TEST(DBTest, IterSmallAndLargeMix) {
349
+ ASSERT_OK(Put("a", "va"));
350
+ ASSERT_OK(Put("b", std::string(100000, 'b')));
351
+ ASSERT_OK(Put("c", "vc"));
352
+ ASSERT_OK(Put("d", std::string(100000, 'd')));
353
+ ASSERT_OK(Put("e", std::string(100000, 'e')));
354
+
355
+ Iterator* iter = db_->NewIterator(ReadOptions());
356
+
357
+ iter->SeekToFirst();
358
+ ASSERT_EQ(IterStatus(iter), "a->va");
359
+ iter->Next();
360
+ ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b'));
361
+ iter->Next();
362
+ ASSERT_EQ(IterStatus(iter), "c->vc");
363
+ iter->Next();
364
+ ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd'));
365
+ iter->Next();
366
+ ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e'));
367
+ iter->Next();
368
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
369
+
370
+ iter->SeekToLast();
371
+ ASSERT_EQ(IterStatus(iter), "e->" + std::string(100000, 'e'));
372
+ iter->Prev();
373
+ ASSERT_EQ(IterStatus(iter), "d->" + std::string(100000, 'd'));
374
+ iter->Prev();
375
+ ASSERT_EQ(IterStatus(iter), "c->vc");
376
+ iter->Prev();
377
+ ASSERT_EQ(IterStatus(iter), "b->" + std::string(100000, 'b'));
378
+ iter->Prev();
379
+ ASSERT_EQ(IterStatus(iter), "a->va");
380
+ iter->Prev();
381
+ ASSERT_EQ(IterStatus(iter), "(invalid)");
382
+
383
+ delete iter;
384
+ }
385
+
386
+ TEST(DBTest, Recover) {
387
+ ASSERT_OK(Put("foo", "v1"));
388
+ ASSERT_OK(Put("baz", "v5"));
389
+
390
+ Reopen();
391
+ ASSERT_EQ("v1", Get("foo"));
392
+
393
+ ASSERT_EQ("v1", Get("foo"));
394
+ ASSERT_EQ("v5", Get("baz"));
395
+ ASSERT_OK(Put("bar", "v2"));
396
+ ASSERT_OK(Put("foo", "v3"));
397
+
398
+ Reopen();
399
+ ASSERT_EQ("v3", Get("foo"));
400
+ ASSERT_OK(Put("foo", "v4"));
401
+ ASSERT_EQ("v4", Get("foo"));
402
+ ASSERT_EQ("v2", Get("bar"));
403
+ ASSERT_EQ("v5", Get("baz"));
404
+ }
405
+
406
+ TEST(DBTest, RecoveryWithEmptyLog) {
407
+ ASSERT_OK(Put("foo", "v1"));
408
+ ASSERT_OK(Put("foo", "v2"));
409
+ Reopen();
410
+ Reopen();
411
+ ASSERT_OK(Put("foo", "v3"));
412
+ Reopen();
413
+ ASSERT_EQ("v3", Get("foo"));
414
+ }
415
+
416
+ static std::string Key(int i) {
417
+ char buf[100];
418
+ snprintf(buf, sizeof(buf), "key%06d", i);
419
+ return std::string(buf);
420
+ }
421
+
422
+ TEST(DBTest, MinorCompactionsHappen) {
423
+ Options options;
424
+ options.write_buffer_size = 10000;
425
+ Reopen(&options);
426
+
427
+ const int N = 500;
428
+
429
+ int starting_num_tables = NumTableFilesAtLevel(0);
430
+ for (int i = 0; i < N; i++) {
431
+ ASSERT_OK(Put(Key(i), Key(i) + std::string(1000, 'v')));
432
+ }
433
+ int ending_num_tables = NumTableFilesAtLevel(0);
434
+ ASSERT_GT(ending_num_tables, starting_num_tables);
435
+
436
+ for (int i = 0; i < N; i++) {
437
+ ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));
438
+ }
439
+
440
+ Reopen();
441
+
442
+ for (int i = 0; i < N; i++) {
443
+ ASSERT_EQ(Key(i) + std::string(1000, 'v'), Get(Key(i)));
444
+ }
445
+ }
446
+
447
+ TEST(DBTest, RecoverWithLargeLog) {
448
+ {
449
+ Options options;
450
+ Reopen(&options);
451
+ ASSERT_OK(Put("big1", std::string(200000, '1')));
452
+ ASSERT_OK(Put("big2", std::string(200000, '2')));
453
+ ASSERT_OK(Put("small3", std::string(10, '3')));
454
+ ASSERT_OK(Put("small4", std::string(10, '4')));
455
+ ASSERT_EQ(NumTableFilesAtLevel(0), 0);
456
+ }
457
+
458
+ // Make sure that if we re-open with a small write buffer size that
459
+ // we flush table files in the middle of a large log file.
460
+ Options options;
461
+ options.write_buffer_size = 100000;
462
+ Reopen(&options);
463
+ ASSERT_EQ(NumTableFilesAtLevel(0), 3);
464
+ ASSERT_EQ(std::string(200000, '1'), Get("big1"));
465
+ ASSERT_EQ(std::string(200000, '2'), Get("big2"));
466
+ ASSERT_EQ(std::string(10, '3'), Get("small3"));
467
+ ASSERT_EQ(std::string(10, '4'), Get("small4"));
468
+ ASSERT_GT(NumTableFilesAtLevel(0), 1);
469
+ }
470
+
471
+ TEST(DBTest, CompactionsGenerateMultipleFiles) {
472
+ Options options;
473
+ options.write_buffer_size = 100000000; // Large write buffer
474
+ Reopen(&options);
475
+
476
+ Random rnd(301);
477
+
478
+ // Write 8MB (80 values, each 100K)
479
+ ASSERT_EQ(NumTableFilesAtLevel(0), 0);
480
+ std::vector<std::string> values;
481
+ for (int i = 0; i < 80; i++) {
482
+ values.push_back(RandomString(&rnd, 100000));
483
+ ASSERT_OK(Put(Key(i), values[i]));
484
+ }
485
+
486
+ // Reopening moves updates to level-0
487
+ Reopen(&options);
488
+ dbfull()->TEST_CompactRange(0, "", Key(100000));
489
+
490
+ ASSERT_EQ(NumTableFilesAtLevel(0), 0);
491
+ ASSERT_GT(NumTableFilesAtLevel(1), 1);
492
+ for (int i = 0; i < 80; i++) {
493
+ ASSERT_EQ(Get(Key(i)), values[i]);
494
+ }
495
+ }
496
+
497
+ TEST(DBTest, SparseMerge) {
498
+ Options options;
499
+ options.compression = kNoCompression;
500
+ Reopen(&options);
501
+
502
+ // Suppose there is:
503
+ // small amount of data with prefix A
504
+ // large amount of data with prefix B
505
+ // small amount of data with prefix C
506
+ // and that recent updates have made small changes to all three prefixes.
507
+ // Check that we do not do a compaction that merges all of B in one shot.
508
+ const std::string value(1000, 'x');
509
+ Put("A", "va");
510
+ // Write approximately 100MB of "B" values
511
+ for (int i = 0; i < 100000; i++) {
512
+ char key[100];
513
+ snprintf(key, sizeof(key), "B%010d", i);
514
+ Put(key, value);
515
+ }
516
+ Put("C", "vc");
517
+ Compact("", "z");
518
+
519
+ // Make sparse update
520
+ Put("A", "va2");
521
+ Put("B100", "bvalue2");
522
+ Put("C", "vc2");
523
+ dbfull()->TEST_CompactMemTable();
524
+
525
+ // Compactions should not cause us to create a situation where
526
+ // a file overlaps too much data at the next level.
527
+ ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);
528
+ dbfull()->TEST_CompactRange(0, "", "z");
529
+ ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);
530
+ dbfull()->TEST_CompactRange(1, "", "z");
531
+ ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(), 20*1048576);
532
+ }
533
+
534
+ static bool Between(uint64_t val, uint64_t low, uint64_t high) {
535
+ bool result = (val >= low) && (val <= high);
536
+ if (!result) {
537
+ fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n",
538
+ (unsigned long long)(val),
539
+ (unsigned long long)(low),
540
+ (unsigned long long)(high));
541
+ }
542
+ return result;
543
+ }
544
+
545
+ TEST(DBTest, ApproximateSizes) {
546
+ Options options;
547
+ options.write_buffer_size = 100000000; // Large write buffer
548
+ options.compression = kNoCompression;
549
+ DestroyAndReopen();
550
+
551
+ ASSERT_TRUE(Between(Size("", "xyz"), 0, 0));
552
+ Reopen(&options);
553
+ ASSERT_TRUE(Between(Size("", "xyz"), 0, 0));
554
+
555
+ // Write 8MB (80 values, each 100K)
556
+ ASSERT_EQ(NumTableFilesAtLevel(0), 0);
557
+ const int N = 80;
558
+ Random rnd(301);
559
+ for (int i = 0; i < N; i++) {
560
+ ASSERT_OK(Put(Key(i), RandomString(&rnd, 100000)));
561
+ }
562
+
563
+ // 0 because GetApproximateSizes() does not account for memtable space
564
+ ASSERT_TRUE(Between(Size("", Key(50)), 0, 0));
565
+
566
+ // Check sizes across recovery by reopening a few times
567
+ for (int run = 0; run < 3; run++) {
568
+ Reopen(&options);
569
+
570
+ for (int compact_start = 0; compact_start < N; compact_start += 10) {
571
+ for (int i = 0; i < N; i += 10) {
572
+ ASSERT_TRUE(Between(Size("", Key(i)), 100000*i, 100000*i + 10000));
573
+ ASSERT_TRUE(Between(Size("", Key(i)+".suffix"),
574
+ 100000 * (i+1), 100000 * (i+1) + 10000));
575
+ ASSERT_TRUE(Between(Size(Key(i), Key(i+10)),
576
+ 100000 * 10, 100000 * 10 + 10000));
577
+ }
578
+ ASSERT_TRUE(Between(Size("", Key(50)), 5000000, 5010000));
579
+ ASSERT_TRUE(Between(Size("", Key(50)+".suffix"), 5100000, 5110000));
580
+
581
+ dbfull()->TEST_CompactRange(0,
582
+ Key(compact_start),
583
+ Key(compact_start + 9));
584
+ }
585
+
586
+ ASSERT_EQ(NumTableFilesAtLevel(0), 0);
587
+ ASSERT_GT(NumTableFilesAtLevel(1), 0);
588
+ }
589
+ }
590
+
591
+ TEST(DBTest, ApproximateSizes_MixOfSmallAndLarge) {
592
+ Options options;
593
+ options.compression = kNoCompression;
594
+ Reopen();
595
+
596
+ Random rnd(301);
597
+ std::string big1 = RandomString(&rnd, 100000);
598
+ ASSERT_OK(Put(Key(0), RandomString(&rnd, 10000)));
599
+ ASSERT_OK(Put(Key(1), RandomString(&rnd, 10000)));
600
+ ASSERT_OK(Put(Key(2), big1));
601
+ ASSERT_OK(Put(Key(3), RandomString(&rnd, 10000)));
602
+ ASSERT_OK(Put(Key(4), big1));
603
+ ASSERT_OK(Put(Key(5), RandomString(&rnd, 10000)));
604
+ ASSERT_OK(Put(Key(6), RandomString(&rnd, 300000)));
605
+ ASSERT_OK(Put(Key(7), RandomString(&rnd, 10000)));
606
+
607
+ // Check sizes across recovery by reopening a few times
608
+ for (int run = 0; run < 3; run++) {
609
+ Reopen(&options);
610
+
611
+ ASSERT_TRUE(Between(Size("", Key(0)), 0, 0));
612
+ ASSERT_TRUE(Between(Size("", Key(1)), 10000, 11000));
613
+ ASSERT_TRUE(Between(Size("", Key(2)), 20000, 21000));
614
+ ASSERT_TRUE(Between(Size("", Key(3)), 120000, 121000));
615
+ ASSERT_TRUE(Between(Size("", Key(4)), 130000, 131000));
616
+ ASSERT_TRUE(Between(Size("", Key(5)), 230000, 231000));
617
+ ASSERT_TRUE(Between(Size("", Key(6)), 240000, 241000));
618
+ ASSERT_TRUE(Between(Size("", Key(7)), 540000, 541000));
619
+ ASSERT_TRUE(Between(Size("", Key(8)), 550000, 551000));
620
+
621
+ ASSERT_TRUE(Between(Size(Key(3), Key(5)), 110000, 111000));
622
+
623
+ dbfull()->TEST_CompactRange(0, Key(0), Key(100));
624
+ }
625
+ }
626
+
627
+ TEST(DBTest, IteratorPinsRef) {
628
+ Put("foo", "hello");
629
+
630
+ // Get iterator that will yield the current contents of the DB.
631
+ Iterator* iter = db_->NewIterator(ReadOptions());
632
+
633
+ // Write to force compactions
634
+ Put("foo", "newvalue1");
635
+ for (int i = 0; i < 100; i++) {
636
+ ASSERT_OK(Put(Key(i), Key(i) + std::string(100000, 'v'))); // 100K values
637
+ }
638
+ Put("foo", "newvalue2");
639
+
640
+ iter->SeekToFirst();
641
+ ASSERT_TRUE(iter->Valid());
642
+ ASSERT_EQ("foo", iter->key().ToString());
643
+ ASSERT_EQ("hello", iter->value().ToString());
644
+ iter->Next();
645
+ ASSERT_TRUE(!iter->Valid());
646
+ delete iter;
647
+ }
648
+
649
+ TEST(DBTest, Snapshot) {
650
+ Put("foo", "v1");
651
+ const Snapshot* s1 = db_->GetSnapshot();
652
+ Put("foo", "v2");
653
+ const Snapshot* s2 = db_->GetSnapshot();
654
+ Put("foo", "v3");
655
+ const Snapshot* s3 = db_->GetSnapshot();
656
+
657
+ Put("foo", "v4");
658
+ ASSERT_EQ("v1", Get("foo", s1));
659
+ ASSERT_EQ("v2", Get("foo", s2));
660
+ ASSERT_EQ("v3", Get("foo", s3));
661
+ ASSERT_EQ("v4", Get("foo"));
662
+
663
+ db_->ReleaseSnapshot(s3);
664
+ ASSERT_EQ("v1", Get("foo", s1));
665
+ ASSERT_EQ("v2", Get("foo", s2));
666
+ ASSERT_EQ("v4", Get("foo"));
667
+
668
+ db_->ReleaseSnapshot(s1);
669
+ ASSERT_EQ("v2", Get("foo", s2));
670
+ ASSERT_EQ("v4", Get("foo"));
671
+
672
+ db_->ReleaseSnapshot(s2);
673
+ ASSERT_EQ("v4", Get("foo"));
674
+ }
675
+
676
+ TEST(DBTest, HiddenValuesAreRemoved) {
677
+ Random rnd(301);
678
+ std::string big = RandomString(&rnd, 50000);
679
+ Put("foo", big);
680
+ Put("pastfoo", "v");
681
+ const Snapshot* snapshot = db_->GetSnapshot();
682
+ Put("foo", "tiny");
683
+ Put("pastfoo2", "v2"); // Advance sequence number one more
684
+
685
+ ASSERT_OK(dbfull()->TEST_CompactMemTable());
686
+ ASSERT_GT(NumTableFilesAtLevel(0), 0);
687
+
688
+ ASSERT_EQ(big, Get("foo", snapshot));
689
+ ASSERT_TRUE(Between(Size("", "pastfoo"), 50000, 60000));
690
+ db_->ReleaseSnapshot(snapshot);
691
+ ASSERT_EQ(AllEntriesFor("foo"), "[ tiny, " + big + " ]");
692
+ dbfull()->TEST_CompactRange(0, "", "x");
693
+ ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]");
694
+ ASSERT_EQ(NumTableFilesAtLevel(0), 0);
695
+ ASSERT_GE(NumTableFilesAtLevel(1), 1);
696
+ dbfull()->TEST_CompactRange(1, "", "x");
697
+ ASSERT_EQ(AllEntriesFor("foo"), "[ tiny ]");
698
+
699
+ ASSERT_TRUE(Between(Size("", "pastfoo"), 0, 1000));
700
+ }
701
+
702
+ TEST(DBTest, DeletionMarkers1) {
703
+ Put("foo", "v1");
704
+ ASSERT_OK(dbfull()->TEST_CompactMemTable());
705
+ dbfull()->TEST_CompactRange(0, "", "z");
706
+ dbfull()->TEST_CompactRange(1, "", "z");
707
+ ASSERT_EQ(NumTableFilesAtLevel(2), 1); // foo => v1 is now in level 2 file
708
+ Delete("foo");
709
+ Put("foo", "v2");
710
+ ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");
711
+ ASSERT_OK(dbfull()->TEST_CompactMemTable());
712
+ ASSERT_EQ(AllEntriesFor("foo"), "[ v2, DEL, v1 ]");
713
+ dbfull()->TEST_CompactRange(0, "", "z");
714
+ // DEL eliminated, but v1 remains because we aren't compacting that level
715
+ // (DEL can be eliminated because v2 hides v1).
716
+ ASSERT_EQ(AllEntriesFor("foo"), "[ v2, v1 ]");
717
+ dbfull()->TEST_CompactRange(1, "", "z");
718
+ // Merging L1 w/ L2, so we are the base level for "foo", so DEL is removed.
719
+ // (as is v1).
720
+ ASSERT_EQ(AllEntriesFor("foo"), "[ v2 ]");
721
+ }
722
+
723
+ TEST(DBTest, DeletionMarkers2) {
724
+ Put("foo", "v1");
725
+ ASSERT_OK(dbfull()->TEST_CompactMemTable());
726
+ dbfull()->TEST_CompactRange(0, "", "z");
727
+ dbfull()->TEST_CompactRange(1, "", "z");
728
+ ASSERT_EQ(NumTableFilesAtLevel(2), 1); // foo => v1 is now in level 2 file
729
+ Delete("foo");
730
+ ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
731
+ ASSERT_OK(dbfull()->TEST_CompactMemTable());
732
+ ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
733
+ dbfull()->TEST_CompactRange(0, "", "z");
734
+ // DEL kept: L2 file overlaps
735
+ ASSERT_EQ(AllEntriesFor("foo"), "[ DEL, v1 ]");
736
+ dbfull()->TEST_CompactRange(1, "", "z");
737
+ // Merging L1 w/ L2, so we are the base level for "foo", so DEL is removed.
738
+ // (as is v1).
739
+ ASSERT_EQ(AllEntriesFor("foo"), "[ ]");
740
+ }
741
+
742
+ TEST(DBTest, ComparatorCheck) {
743
+ class NewComparator : public Comparator {
744
+ public:
745
+ virtual const char* Name() const { return "leveldb.NewComparator"; }
746
+ virtual int Compare(const Slice& a, const Slice& b) const {
747
+ return BytewiseComparator()->Compare(a, b);
748
+ }
749
+ virtual void FindShortestSeparator(std::string* s, const Slice& l) const {
750
+ BytewiseComparator()->FindShortestSeparator(s, l);
751
+ }
752
+ virtual void FindShortSuccessor(std::string* key) const {
753
+ BytewiseComparator()->FindShortSuccessor(key);
754
+ }
755
+ };
756
+ NewComparator cmp;
757
+ Options new_options;
758
+ new_options.comparator = &cmp;
759
+ Status s = TryReopen(&new_options);
760
+ ASSERT_TRUE(!s.ok());
761
+ ASSERT_TRUE(s.ToString().find("comparator") != std::string::npos)
762
+ << s.ToString();
763
+ }
764
+
765
+ TEST(DBTest, DBOpen_Options) {
766
+ std::string dbname = test::TmpDir() + "/db_options_test";
767
+ DestroyDB(dbname, Options());
768
+
769
+ // Does not exist, and create_if_missing == false: error
770
+ DB* db = NULL;
771
+ Options opts;
772
+ opts.create_if_missing = false;
773
+ Status s = DB::Open(opts, dbname, &db);
774
+ ASSERT_TRUE(strstr(s.ToString().c_str(), "does not exist") != NULL);
775
+ ASSERT_TRUE(db == NULL);
776
+
777
+ // Does not exist, and create_if_missing == true: OK
778
+ opts.create_if_missing = true;
779
+ s = DB::Open(opts, dbname, &db);
780
+ ASSERT_OK(s);
781
+ ASSERT_TRUE(db != NULL);
782
+
783
+ delete db;
784
+ db = NULL;
785
+
786
+ // Does exist, and error_if_exists == true: error
787
+ opts.create_if_missing = false;
788
+ opts.error_if_exists = true;
789
+ s = DB::Open(opts, dbname, &db);
790
+ ASSERT_TRUE(strstr(s.ToString().c_str(), "exists") != NULL);
791
+ ASSERT_TRUE(db == NULL);
792
+
793
+ // Does exist, and error_if_exists == false: OK
794
+ opts.create_if_missing = true;
795
+ opts.error_if_exists = false;
796
+ s = DB::Open(opts, dbname, &db);
797
+ ASSERT_OK(s);
798
+ ASSERT_TRUE(db != NULL);
799
+
800
+ delete db;
801
+ db = NULL;
802
+ }
803
+
804
+ // Multi-threaded test:
805
+ namespace {
806
+
807
+ static const int kNumThreads = 4;
808
+ static const int kTestSeconds = 10;
809
+ static const int kNumKeys = 1000;
810
+
811
+ struct MTState {
812
+ DBTest* test;
813
+ port::AtomicPointer stop;
814
+ port::AtomicPointer counter[kNumThreads];
815
+ port::AtomicPointer thread_done[kNumThreads];
816
+ };
817
+
818
+ struct MTThread {
819
+ MTState* state;
820
+ int id;
821
+ };
822
+
823
+ static void MTThreadBody(void* arg) {
824
+ MTThread* t = reinterpret_cast<MTThread*>(arg);
825
+ DB* db = t->state->test->db_;
826
+ uintptr_t counter = 0;
827
+ fprintf(stderr, "... starting thread %d\n", t->id);
828
+ Random rnd(1000 + t->id);
829
+ std::string value;
830
+ char valbuf[1500];
831
+ while (t->state->stop.Acquire_Load() == NULL) {
832
+ t->state->counter[t->id].Release_Store(reinterpret_cast<void*>(counter));
833
+
834
+ int key = rnd.Uniform(kNumKeys);
835
+ char keybuf[20];
836
+ snprintf(keybuf, sizeof(keybuf), "%016d", key);
837
+
838
+ if (rnd.OneIn(2)) {
839
+ // Write values of the form <key, my id, counter>.
840
+ // We add some padding for force compactions.
841
+ snprintf(valbuf, sizeof(valbuf), "%d.%d.%-1000d",
842
+ key, t->id, static_cast<int>(counter));
843
+ ASSERT_OK(db->Put(WriteOptions(), Slice(keybuf), Slice(valbuf)));
844
+ } else {
845
+ // Read a value and verify that it matches the pattern written above.
846
+ Status s = db->Get(ReadOptions(), Slice(keybuf), &value);
847
+ if (s.IsNotFound()) {
848
+ // Key has not yet been written
849
+ } else {
850
+ // Check that the writer thread counter is >= the counter in the value
851
+ ASSERT_OK(s);
852
+ int k, w, c;
853
+ ASSERT_EQ(3, sscanf(value.c_str(), "%d.%d.%d", &k, &w, &c)) << value;
854
+ ASSERT_EQ(k, key);
855
+ ASSERT_GE(w, 0);
856
+ ASSERT_LT(w, kNumThreads);
857
+ ASSERT_LE(c, reinterpret_cast<uintptr_t>(
858
+ t->state->counter[w].Acquire_Load()));
859
+ }
860
+ }
861
+ counter++;
862
+ }
863
+ t->state->thread_done[t->id].Release_Store(t);
864
+ fprintf(stderr, "... stopping thread %d after %d ops\n", t->id, int(counter));
865
+ }
866
+
867
+ }
868
+
869
+ TEST(DBTest, MultiThreaded) {
870
+ // Initialize state
871
+ MTState mt;
872
+ mt.test = this;
873
+ mt.stop.Release_Store(0);
874
+ for (int id = 0; id < kNumThreads; id++) {
875
+ mt.counter[id].Release_Store(0);
876
+ mt.thread_done[id].Release_Store(0);
877
+ }
878
+
879
+ // Start threads
880
+ MTThread thread[kNumThreads];
881
+ for (int id = 0; id < kNumThreads; id++) {
882
+ thread[id].state = &mt;
883
+ thread[id].id = id;
884
+ env_->StartThread(MTThreadBody, &thread[id]);
885
+ }
886
+
887
+ // Let them run for a while
888
+ env_->SleepForMicroseconds(kTestSeconds * 1000000);
889
+
890
+ // Stop the threads and wait for them to finish
891
+ mt.stop.Release_Store(&mt);
892
+ for (int id = 0; id < kNumThreads; id++) {
893
+ while (mt.thread_done[id].Acquire_Load() == NULL) {
894
+ env_->SleepForMicroseconds(100000);
895
+ }
896
+ }
897
+ }
898
+
899
+ namespace {
900
+ typedef std::map<std::string, std::string> KVMap;
901
+ }
902
+
903
+ class ModelDB: public DB {
904
+ public:
905
+ class ModelSnapshot : public Snapshot {
906
+ public:
907
+ KVMap map_;
908
+ };
909
+
910
+ explicit ModelDB(const Options& options): options_(options) { }
911
+ ~ModelDB() { }
912
+ virtual Status Put(const WriteOptions& o, const Slice& k, const Slice& v) {
913
+ return DB::Put(o, k, v);
914
+ }
915
+ virtual Status Delete(const WriteOptions& o, const Slice& key) {
916
+ return DB::Delete(o, key);
917
+ }
918
+ virtual Status Get(const ReadOptions& options,
919
+ const Slice& key, std::string* value) {
920
+ assert(false); // Not implemented
921
+ return Status::NotFound(key);
922
+ }
923
+ virtual Iterator* NewIterator(const ReadOptions& options) {
924
+ if (options.snapshot == NULL) {
925
+ KVMap* saved = new KVMap;
926
+ *saved = map_;
927
+ return new ModelIter(saved, true);
928
+ } else {
929
+ const KVMap* snapshot_state =
930
+ &(reinterpret_cast<const ModelSnapshot*>(options.snapshot)->map_);
931
+ return new ModelIter(snapshot_state, false);
932
+ }
933
+ }
934
+ virtual const Snapshot* GetSnapshot() {
935
+ ModelSnapshot* snapshot = new ModelSnapshot;
936
+ snapshot->map_ = map_;
937
+ return snapshot;
938
+ }
939
+
940
+ virtual void ReleaseSnapshot(const Snapshot* snapshot) {
941
+ delete reinterpret_cast<const ModelSnapshot*>(snapshot);
942
+ }
943
+ virtual Status Write(const WriteOptions& options, WriteBatch* batch) {
944
+ assert(options.post_write_snapshot == NULL); // Not supported
945
+ class Handler : public WriteBatch::Handler {
946
+ public:
947
+ KVMap* map_;
948
+ virtual void Put(const Slice& key, const Slice& value) {
949
+ (*map_)[key.ToString()] = value.ToString();
950
+ }
951
+ virtual void Delete(const Slice& key) {
952
+ map_->erase(key.ToString());
953
+ }
954
+ };
955
+ Handler handler;
956
+ handler.map_ = &map_;
957
+ return batch->Iterate(&handler);
958
+ }
959
+
960
+ virtual bool GetProperty(const Slice& property, std::string* value) {
961
+ return false;
962
+ }
963
+ virtual void GetApproximateSizes(const Range* r, int n, uint64_t* sizes) {
964
+ for (int i = 0; i < n; i++) {
965
+ sizes[i] = 0;
966
+ }
967
+ }
968
+ private:
969
+ class ModelIter: public Iterator {
970
+ public:
971
+ ModelIter(const KVMap* map, bool owned)
972
+ : map_(map), owned_(owned), iter_(map_->end()) {
973
+ }
974
+ ~ModelIter() {
975
+ if (owned_) delete map_;
976
+ }
977
+ virtual bool Valid() const { return iter_ != map_->end(); }
978
+ virtual void SeekToFirst() { iter_ = map_->begin(); }
979
+ virtual void SeekToLast() {
980
+ if (map_->empty()) {
981
+ iter_ = map_->end();
982
+ } else {
983
+ iter_ = map_->find(map_->rbegin()->first);
984
+ }
985
+ }
986
+ virtual void Seek(const Slice& k) {
987
+ iter_ = map_->lower_bound(k.ToString());
988
+ }
989
+ virtual void Next() { ++iter_; }
990
+ virtual void Prev() { --iter_; }
991
+ virtual Slice key() const { return iter_->first; }
992
+ virtual Slice value() const { return iter_->second; }
993
+ virtual Status status() const { return Status::OK(); }
994
+ private:
995
+ const KVMap* const map_;
996
+ const bool owned_; // Do we own map_
997
+ KVMap::const_iterator iter_;
998
+ };
999
+ const Options options_;
1000
+ KVMap map_;
1001
+ };
1002
+
1003
+ static std::string RandomKey(Random* rnd) {
1004
+ int len = (rnd->OneIn(3)
1005
+ ? 1 // Short sometimes to encourage collisions
1006
+ : (rnd->OneIn(100) ? rnd->Skewed(10) : rnd->Uniform(10)));
1007
+ return test::RandomKey(rnd, len);
1008
+ }
1009
+
1010
+ static bool CompareIterators(int step,
1011
+ DB* model,
1012
+ DB* db,
1013
+ const Snapshot* model_snap,
1014
+ const Snapshot* db_snap) {
1015
+ ReadOptions options;
1016
+ options.snapshot = model_snap;
1017
+ Iterator* miter = model->NewIterator(options);
1018
+ options.snapshot = db_snap;
1019
+ Iterator* dbiter = db->NewIterator(options);
1020
+ bool ok = true;
1021
+ int count = 0;
1022
+ for (miter->SeekToFirst(), dbiter->SeekToFirst();
1023
+ ok && miter->Valid() && dbiter->Valid();
1024
+ miter->Next(), dbiter->Next()) {
1025
+ count++;
1026
+ if (miter->key().compare(dbiter->key()) != 0) {
1027
+ fprintf(stderr, "step %d: Key mismatch: '%s' vs. '%s'\n",
1028
+ step,
1029
+ EscapeString(miter->key()).c_str(),
1030
+ EscapeString(dbiter->key()).c_str());
1031
+ ok = false;
1032
+ break;
1033
+ }
1034
+
1035
+ if (miter->value().compare(dbiter->value()) != 0) {
1036
+ fprintf(stderr, "step %d: Value mismatch for key '%s': '%s' vs. '%s'\n",
1037
+ step,
1038
+ EscapeString(miter->key()).c_str(),
1039
+ EscapeString(miter->value()).c_str(),
1040
+ EscapeString(miter->value()).c_str());
1041
+ ok = false;
1042
+ }
1043
+ }
1044
+
1045
+ if (ok) {
1046
+ if (miter->Valid() != dbiter->Valid()) {
1047
+ fprintf(stderr, "step %d: Mismatch at end of iterators: %d vs. %d\n",
1048
+ step, miter->Valid(), dbiter->Valid());
1049
+ ok = false;
1050
+ }
1051
+ }
1052
+ fprintf(stderr, "%d entries compared: ok=%d\n", count, ok);
1053
+ delete miter;
1054
+ delete dbiter;
1055
+ return ok;
1056
+ }
1057
+
1058
+ TEST(DBTest, Randomized) {
1059
+ Random rnd(test::RandomSeed());
1060
+ ModelDB model(last_options_);
1061
+ const int N = 10000;
1062
+ const Snapshot* model_snap = NULL;
1063
+ const Snapshot* db_snap = NULL;
1064
+ std::string k, v;
1065
+ for (int step = 0; step < N; step++) {
1066
+ if (step % 100 == 0) {
1067
+ fprintf(stderr, "Step %d of %d\n", step, N);
1068
+ }
1069
+ int p = rnd.Uniform(100);
1070
+ if (p < 45) { // Put
1071
+ k = RandomKey(&rnd);
1072
+ v = RandomString(&rnd,
1073
+ rnd.OneIn(20)
1074
+ ? 100 + rnd.Uniform(100)
1075
+ : rnd.Uniform(8));
1076
+ ASSERT_OK(model.Put(WriteOptions(), k, v));
1077
+ ASSERT_OK(db_->Put(WriteOptions(), k, v));
1078
+
1079
+ } else if (p < 90) { // Delete
1080
+ k = RandomKey(&rnd);
1081
+ ASSERT_OK(model.Delete(WriteOptions(), k));
1082
+ ASSERT_OK(db_->Delete(WriteOptions(), k));
1083
+
1084
+
1085
+ } else { // Multi-element batch
1086
+ WriteBatch b;
1087
+ const int num = rnd.Uniform(8);
1088
+ for (int i = 0; i < num; i++) {
1089
+ if (i == 0 || !rnd.OneIn(10)) {
1090
+ k = RandomKey(&rnd);
1091
+ } else {
1092
+ // Periodically re-use the same key from the previous iter, so
1093
+ // we have multiple entries in the write batch for the same key
1094
+ }
1095
+ if (rnd.OneIn(2)) {
1096
+ v = RandomString(&rnd, rnd.Uniform(10));
1097
+ b.Put(k, v);
1098
+ } else {
1099
+ b.Delete(k);
1100
+ }
1101
+ }
1102
+ ASSERT_OK(model.Write(WriteOptions(), &b));
1103
+ ASSERT_OK(db_->Write(WriteOptions(), &b));
1104
+ }
1105
+
1106
+ if ((step % 100) == 0) {
1107
+ ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL));
1108
+ ASSERT_TRUE(CompareIterators(step, &model, db_, model_snap, db_snap));
1109
+ // Save a snapshot from each DB this time that we'll use next
1110
+ // time we compare things, to make sure the current state is
1111
+ // preserved with the snapshot
1112
+ if (model_snap != NULL) model.ReleaseSnapshot(model_snap);
1113
+ if (db_snap != NULL) db_->ReleaseSnapshot(db_snap);
1114
+
1115
+ Reopen();
1116
+ ASSERT_TRUE(CompareIterators(step, &model, db_, NULL, NULL));
1117
+
1118
+ model_snap = model.GetSnapshot();
1119
+ db_snap = db_->GetSnapshot();
1120
+ }
1121
+ }
1122
+ if (model_snap != NULL) model.ReleaseSnapshot(model_snap);
1123
+ if (db_snap != NULL) db_->ReleaseSnapshot(db_snap);
1124
+ }
1125
+
1126
+ std::string MakeKey(unsigned int num) {
1127
+ char buf[30];
1128
+ snprintf(buf, sizeof(buf), "%016u", num);
1129
+ return std::string(buf);
1130
+ }
1131
+
1132
+ void BM_LogAndApply(int iters, int num_base_files) {
1133
+ std::string dbname = test::TmpDir() + "/leveldb_test_benchmark";
1134
+ DestroyDB(dbname, Options());
1135
+
1136
+ DB* db = NULL;
1137
+ Options opts;
1138
+ opts.create_if_missing = true;
1139
+ Status s = DB::Open(opts, dbname, &db);
1140
+ ASSERT_OK(s);
1141
+ ASSERT_TRUE(db != NULL);
1142
+
1143
+ delete db;
1144
+ db = NULL;
1145
+
1146
+ Env* env = Env::Default();
1147
+
1148
+ InternalKeyComparator cmp(BytewiseComparator());
1149
+ Options options;
1150
+ VersionSet vset(dbname, &options, NULL, &cmp);
1151
+ ASSERT_OK(vset.Recover());
1152
+ VersionEdit vbase;
1153
+ uint64_t fnum = 1;
1154
+ for (int i = 0; i < num_base_files; i++) {
1155
+ InternalKey start(MakeKey(2*fnum), 1, kTypeValue);
1156
+ InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion);
1157
+ vbase.AddFile(2, fnum++, 1 /* file size */, start, limit);
1158
+ }
1159
+ ASSERT_OK(vset.LogAndApply(&vbase));
1160
+
1161
+ uint64_t start_micros = env->NowMicros();
1162
+
1163
+ for (int i = 0; i < iters; i++) {
1164
+ VersionEdit vedit;
1165
+ vedit.DeleteFile(2, fnum);
1166
+ InternalKey start(MakeKey(2*fnum), 1, kTypeValue);
1167
+ InternalKey limit(MakeKey(2*fnum+1), 1, kTypeDeletion);
1168
+ vedit.AddFile(2, fnum++, 1 /* file size */, start, limit);
1169
+ vset.LogAndApply(&vedit);
1170
+ }
1171
+ uint64_t stop_micros = env->NowMicros();
1172
+ unsigned int us = stop_micros - start_micros;
1173
+ char buf[16];
1174
+ snprintf(buf, sizeof(buf), "%d", num_base_files);
1175
+ fprintf(stderr,
1176
+ "BM_LogAndApply/%-6s %8d iters : %9u us (%7.0f us / iter)\n",
1177
+ buf, iters, us, ((float)us) / iters);
1178
+ }
1179
+
1180
+ }
1181
+
1182
+ int main(int argc, char** argv) {
1183
+ if (argc > 1 && std::string(argv[1]) == "--benchmark") {
1184
+ leveldb::BM_LogAndApply(1000, 1);
1185
+ leveldb::BM_LogAndApply(1000, 100);
1186
+ leveldb::BM_LogAndApply(1000, 10000);
1187
+ leveldb::BM_LogAndApply(100, 100000);
1188
+ return 0;
1189
+ }
1190
+
1191
+ return leveldb::test::RunAllTests();
1192
+ }