leveldb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +95 -0
  4. data/ext/Rakefile +11 -0
  5. data/ext/leveldb/LICENSE +27 -0
  6. data/ext/leveldb/Makefile +206 -0
  7. data/ext/leveldb/build_config.mk +13 -0
  8. data/ext/leveldb/db/builder.cc +88 -0
  9. data/ext/leveldb/db/builder.h +34 -0
  10. data/ext/leveldb/db/c.cc +595 -0
  11. data/ext/leveldb/db/c_test.c +390 -0
  12. data/ext/leveldb/db/corruption_test.cc +359 -0
  13. data/ext/leveldb/db/db_bench.cc +979 -0
  14. data/ext/leveldb/db/db_impl.cc +1485 -0
  15. data/ext/leveldb/db/db_impl.h +203 -0
  16. data/ext/leveldb/db/db_iter.cc +299 -0
  17. data/ext/leveldb/db/db_iter.h +26 -0
  18. data/ext/leveldb/db/db_test.cc +2092 -0
  19. data/ext/leveldb/db/dbformat.cc +140 -0
  20. data/ext/leveldb/db/dbformat.h +227 -0
  21. data/ext/leveldb/db/dbformat_test.cc +112 -0
  22. data/ext/leveldb/db/filename.cc +139 -0
  23. data/ext/leveldb/db/filename.h +80 -0
  24. data/ext/leveldb/db/filename_test.cc +122 -0
  25. data/ext/leveldb/db/leveldb_main.cc +238 -0
  26. data/ext/leveldb/db/log_format.h +35 -0
  27. data/ext/leveldb/db/log_reader.cc +259 -0
  28. data/ext/leveldb/db/log_reader.h +108 -0
  29. data/ext/leveldb/db/log_test.cc +500 -0
  30. data/ext/leveldb/db/log_writer.cc +103 -0
  31. data/ext/leveldb/db/log_writer.h +48 -0
  32. data/ext/leveldb/db/memtable.cc +145 -0
  33. data/ext/leveldb/db/memtable.h +91 -0
  34. data/ext/leveldb/db/repair.cc +389 -0
  35. data/ext/leveldb/db/skiplist.h +379 -0
  36. data/ext/leveldb/db/skiplist_test.cc +378 -0
  37. data/ext/leveldb/db/snapshot.h +66 -0
  38. data/ext/leveldb/db/table_cache.cc +121 -0
  39. data/ext/leveldb/db/table_cache.h +61 -0
  40. data/ext/leveldb/db/version_edit.cc +266 -0
  41. data/ext/leveldb/db/version_edit.h +107 -0
  42. data/ext/leveldb/db/version_edit_test.cc +46 -0
  43. data/ext/leveldb/db/version_set.cc +1443 -0
  44. data/ext/leveldb/db/version_set.h +383 -0
  45. data/ext/leveldb/db/version_set_test.cc +179 -0
  46. data/ext/leveldb/db/write_batch.cc +147 -0
  47. data/ext/leveldb/db/write_batch_internal.h +49 -0
  48. data/ext/leveldb/db/write_batch_test.cc +120 -0
  49. data/ext/leveldb/doc/bench/db_bench_sqlite3.cc +718 -0
  50. data/ext/leveldb/doc/bench/db_bench_tree_db.cc +528 -0
  51. data/ext/leveldb/helpers/memenv/memenv.cc +384 -0
  52. data/ext/leveldb/helpers/memenv/memenv.h +20 -0
  53. data/ext/leveldb/helpers/memenv/memenv_test.cc +232 -0
  54. data/ext/leveldb/include/leveldb/c.h +291 -0
  55. data/ext/leveldb/include/leveldb/cache.h +99 -0
  56. data/ext/leveldb/include/leveldb/comparator.h +63 -0
  57. data/ext/leveldb/include/leveldb/db.h +161 -0
  58. data/ext/leveldb/include/leveldb/env.h +333 -0
  59. data/ext/leveldb/include/leveldb/filter_policy.h +70 -0
  60. data/ext/leveldb/include/leveldb/iterator.h +100 -0
  61. data/ext/leveldb/include/leveldb/options.h +195 -0
  62. data/ext/leveldb/include/leveldb/slice.h +109 -0
  63. data/ext/leveldb/include/leveldb/status.h +106 -0
  64. data/ext/leveldb/include/leveldb/table.h +85 -0
  65. data/ext/leveldb/include/leveldb/table_builder.h +92 -0
  66. data/ext/leveldb/include/leveldb/write_batch.h +64 -0
  67. data/ext/leveldb/issues/issue178_test.cc +92 -0
  68. data/ext/leveldb/port/atomic_pointer.h +224 -0
  69. data/ext/leveldb/port/port.h +19 -0
  70. data/ext/leveldb/port/port_example.h +135 -0
  71. data/ext/leveldb/port/port_posix.cc +54 -0
  72. data/ext/leveldb/port/port_posix.h +157 -0
  73. data/ext/leveldb/port/thread_annotations.h +59 -0
  74. data/ext/leveldb/port/win/stdint.h +24 -0
  75. data/ext/leveldb/table/block.cc +268 -0
  76. data/ext/leveldb/table/block.h +44 -0
  77. data/ext/leveldb/table/block_builder.cc +109 -0
  78. data/ext/leveldb/table/block_builder.h +57 -0
  79. data/ext/leveldb/table/filter_block.cc +111 -0
  80. data/ext/leveldb/table/filter_block.h +68 -0
  81. data/ext/leveldb/table/filter_block_test.cc +128 -0
  82. data/ext/leveldb/table/format.cc +145 -0
  83. data/ext/leveldb/table/format.h +108 -0
  84. data/ext/leveldb/table/iterator.cc +67 -0
  85. data/ext/leveldb/table/iterator_wrapper.h +63 -0
  86. data/ext/leveldb/table/merger.cc +197 -0
  87. data/ext/leveldb/table/merger.h +26 -0
  88. data/ext/leveldb/table/table.cc +275 -0
  89. data/ext/leveldb/table/table_builder.cc +270 -0
  90. data/ext/leveldb/table/table_test.cc +868 -0
  91. data/ext/leveldb/table/two_level_iterator.cc +182 -0
  92. data/ext/leveldb/table/two_level_iterator.h +34 -0
  93. data/ext/leveldb/util/arena.cc +68 -0
  94. data/ext/leveldb/util/arena.h +68 -0
  95. data/ext/leveldb/util/arena_test.cc +68 -0
  96. data/ext/leveldb/util/bloom.cc +95 -0
  97. data/ext/leveldb/util/bloom_test.cc +160 -0
  98. data/ext/leveldb/util/cache.cc +325 -0
  99. data/ext/leveldb/util/cache_test.cc +186 -0
  100. data/ext/leveldb/util/coding.cc +194 -0
  101. data/ext/leveldb/util/coding.h +104 -0
  102. data/ext/leveldb/util/coding_test.cc +196 -0
  103. data/ext/leveldb/util/comparator.cc +81 -0
  104. data/ext/leveldb/util/crc32c.cc +332 -0
  105. data/ext/leveldb/util/crc32c.h +45 -0
  106. data/ext/leveldb/util/crc32c_test.cc +72 -0
  107. data/ext/leveldb/util/env.cc +96 -0
  108. data/ext/leveldb/util/env_posix.cc +698 -0
  109. data/ext/leveldb/util/env_test.cc +104 -0
  110. data/ext/leveldb/util/filter_policy.cc +11 -0
  111. data/ext/leveldb/util/hash.cc +52 -0
  112. data/ext/leveldb/util/hash.h +19 -0
  113. data/ext/leveldb/util/histogram.cc +139 -0
  114. data/ext/leveldb/util/histogram.h +42 -0
  115. data/ext/leveldb/util/logging.cc +81 -0
  116. data/ext/leveldb/util/logging.h +47 -0
  117. data/ext/leveldb/util/mutexlock.h +41 -0
  118. data/ext/leveldb/util/options.cc +29 -0
  119. data/ext/leveldb/util/posix_logger.h +98 -0
  120. data/ext/leveldb/util/random.h +59 -0
  121. data/ext/leveldb/util/status.cc +75 -0
  122. data/ext/leveldb/util/testharness.cc +77 -0
  123. data/ext/leveldb/util/testharness.h +138 -0
  124. data/ext/leveldb/util/testutil.cc +51 -0
  125. data/ext/leveldb/util/testutil.h +53 -0
  126. data/lib/leveldb/version.rb +3 -0
  127. data/lib/leveldb.rb +1006 -0
  128. metadata +228 -0
@@ -0,0 +1,868 @@
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/table.h"
6
+
7
+ #include <map>
8
+ #include <string>
9
+ #include "db/dbformat.h"
10
+ #include "db/memtable.h"
11
+ #include "db/write_batch_internal.h"
12
+ #include "leveldb/db.h"
13
+ #include "leveldb/env.h"
14
+ #include "leveldb/iterator.h"
15
+ #include "leveldb/table_builder.h"
16
+ #include "table/block.h"
17
+ #include "table/block_builder.h"
18
+ #include "table/format.h"
19
+ #include "util/random.h"
20
+ #include "util/testharness.h"
21
+ #include "util/testutil.h"
22
+
23
+ namespace leveldb {
24
+
25
+ // Return reverse of "key".
26
+ // Used to test non-lexicographic comparators.
27
+ static std::string Reverse(const Slice& key) {
28
+ std::string str(key.ToString());
29
+ std::string rev("");
30
+ for (std::string::reverse_iterator rit = str.rbegin();
31
+ rit != str.rend(); ++rit) {
32
+ rev.push_back(*rit);
33
+ }
34
+ return rev;
35
+ }
36
+
37
+ namespace {
38
+ class ReverseKeyComparator : public Comparator {
39
+ public:
40
+ virtual const char* Name() const {
41
+ return "leveldb.ReverseBytewiseComparator";
42
+ }
43
+
44
+ virtual int Compare(const Slice& a, const Slice& b) const {
45
+ return BytewiseComparator()->Compare(Reverse(a), Reverse(b));
46
+ }
47
+
48
+ virtual void FindShortestSeparator(
49
+ std::string* start,
50
+ const Slice& limit) const {
51
+ std::string s = Reverse(*start);
52
+ std::string l = Reverse(limit);
53
+ BytewiseComparator()->FindShortestSeparator(&s, l);
54
+ *start = Reverse(s);
55
+ }
56
+
57
+ virtual void FindShortSuccessor(std::string* key) const {
58
+ std::string s = Reverse(*key);
59
+ BytewiseComparator()->FindShortSuccessor(&s);
60
+ *key = Reverse(s);
61
+ }
62
+ };
63
+ } // namespace
64
+ static ReverseKeyComparator reverse_key_comparator;
65
+
66
+ static void Increment(const Comparator* cmp, std::string* key) {
67
+ if (cmp == BytewiseComparator()) {
68
+ key->push_back('\0');
69
+ } else {
70
+ assert(cmp == &reverse_key_comparator);
71
+ std::string rev = Reverse(*key);
72
+ rev.push_back('\0');
73
+ *key = Reverse(rev);
74
+ }
75
+ }
76
+
77
+ // An STL comparator that uses a Comparator
78
+ namespace {
79
+ struct STLLessThan {
80
+ const Comparator* cmp;
81
+
82
+ STLLessThan() : cmp(BytewiseComparator()) { }
83
+ STLLessThan(const Comparator* c) : cmp(c) { }
84
+ bool operator()(const std::string& a, const std::string& b) const {
85
+ return cmp->Compare(Slice(a), Slice(b)) < 0;
86
+ }
87
+ };
88
+ } // namespace
89
+
90
+ class StringSink: public WritableFile {
91
+ public:
92
+ ~StringSink() { }
93
+
94
+ const std::string& contents() const { return contents_; }
95
+
96
+ virtual Status Close() { return Status::OK(); }
97
+ virtual Status Flush() { return Status::OK(); }
98
+ virtual Status Sync() { return Status::OK(); }
99
+
100
+ virtual Status Append(const Slice& data) {
101
+ contents_.append(data.data(), data.size());
102
+ return Status::OK();
103
+ }
104
+
105
+ private:
106
+ std::string contents_;
107
+ };
108
+
109
+
110
+ class StringSource: public RandomAccessFile {
111
+ public:
112
+ StringSource(const Slice& contents)
113
+ : contents_(contents.data(), contents.size()) {
114
+ }
115
+
116
+ virtual ~StringSource() { }
117
+
118
+ uint64_t Size() const { return contents_.size(); }
119
+
120
+ virtual Status Read(uint64_t offset, size_t n, Slice* result,
121
+ char* scratch) const {
122
+ if (offset > contents_.size()) {
123
+ return Status::InvalidArgument("invalid Read offset");
124
+ }
125
+ if (offset + n > contents_.size()) {
126
+ n = contents_.size() - offset;
127
+ }
128
+ memcpy(scratch, &contents_[offset], n);
129
+ *result = Slice(scratch, n);
130
+ return Status::OK();
131
+ }
132
+
133
+ private:
134
+ std::string contents_;
135
+ };
136
+
137
+ typedef std::map<std::string, std::string, STLLessThan> KVMap;
138
+
139
+ // Helper class for tests to unify the interface between
140
+ // BlockBuilder/TableBuilder and Block/Table.
141
+ class Constructor {
142
+ public:
143
+ explicit Constructor(const Comparator* cmp) : data_(STLLessThan(cmp)) { }
144
+ virtual ~Constructor() { }
145
+
146
+ void Add(const std::string& key, const Slice& value) {
147
+ data_[key] = value.ToString();
148
+ }
149
+
150
+ // Finish constructing the data structure with all the keys that have
151
+ // been added so far. Returns the keys in sorted order in "*keys"
152
+ // and stores the key/value pairs in "*kvmap"
153
+ void Finish(const Options& options,
154
+ std::vector<std::string>* keys,
155
+ KVMap* kvmap) {
156
+ *kvmap = data_;
157
+ keys->clear();
158
+ for (KVMap::const_iterator it = data_.begin();
159
+ it != data_.end();
160
+ ++it) {
161
+ keys->push_back(it->first);
162
+ }
163
+ data_.clear();
164
+ Status s = FinishImpl(options, *kvmap);
165
+ ASSERT_TRUE(s.ok()) << s.ToString();
166
+ }
167
+
168
+ // Construct the data structure from the data in "data"
169
+ virtual Status FinishImpl(const Options& options, const KVMap& data) = 0;
170
+
171
+ virtual Iterator* NewIterator() const = 0;
172
+
173
+ virtual const KVMap& data() { return data_; }
174
+
175
+ virtual DB* db() const { return NULL; } // Overridden in DBConstructor
176
+
177
+ private:
178
+ KVMap data_;
179
+ };
180
+
181
+ class BlockConstructor: public Constructor {
182
+ public:
183
+ explicit BlockConstructor(const Comparator* cmp)
184
+ : Constructor(cmp),
185
+ comparator_(cmp),
186
+ block_(NULL) { }
187
+ ~BlockConstructor() {
188
+ delete block_;
189
+ }
190
+ virtual Status FinishImpl(const Options& options, const KVMap& data) {
191
+ delete block_;
192
+ block_ = NULL;
193
+ BlockBuilder builder(&options);
194
+
195
+ for (KVMap::const_iterator it = data.begin();
196
+ it != data.end();
197
+ ++it) {
198
+ builder.Add(it->first, it->second);
199
+ }
200
+ // Open the block
201
+ data_ = builder.Finish().ToString();
202
+ BlockContents contents;
203
+ contents.data = data_;
204
+ contents.cachable = false;
205
+ contents.heap_allocated = false;
206
+ block_ = new Block(contents);
207
+ return Status::OK();
208
+ }
209
+ virtual Iterator* NewIterator() const {
210
+ return block_->NewIterator(comparator_);
211
+ }
212
+
213
+ private:
214
+ const Comparator* comparator_;
215
+ std::string data_;
216
+ Block* block_;
217
+
218
+ BlockConstructor();
219
+ };
220
+
221
+ class TableConstructor: public Constructor {
222
+ public:
223
+ TableConstructor(const Comparator* cmp)
224
+ : Constructor(cmp),
225
+ source_(NULL), table_(NULL) {
226
+ }
227
+ ~TableConstructor() {
228
+ Reset();
229
+ }
230
+ virtual Status FinishImpl(const Options& options, const KVMap& data) {
231
+ Reset();
232
+ StringSink sink;
233
+ TableBuilder builder(options, &sink);
234
+
235
+ for (KVMap::const_iterator it = data.begin();
236
+ it != data.end();
237
+ ++it) {
238
+ builder.Add(it->first, it->second);
239
+ ASSERT_TRUE(builder.status().ok());
240
+ }
241
+ Status s = builder.Finish();
242
+ ASSERT_TRUE(s.ok()) << s.ToString();
243
+
244
+ ASSERT_EQ(sink.contents().size(), builder.FileSize());
245
+
246
+ // Open the table
247
+ source_ = new StringSource(sink.contents());
248
+ Options table_options;
249
+ table_options.comparator = options.comparator;
250
+ return Table::Open(table_options, source_, sink.contents().size(), &table_);
251
+ }
252
+
253
+ virtual Iterator* NewIterator() const {
254
+ return table_->NewIterator(ReadOptions());
255
+ }
256
+
257
+ uint64_t ApproximateOffsetOf(const Slice& key) const {
258
+ return table_->ApproximateOffsetOf(key);
259
+ }
260
+
261
+ private:
262
+ void Reset() {
263
+ delete table_;
264
+ delete source_;
265
+ table_ = NULL;
266
+ source_ = NULL;
267
+ }
268
+
269
+ StringSource* source_;
270
+ Table* table_;
271
+
272
+ TableConstructor();
273
+ };
274
+
275
+ // A helper class that converts internal format keys into user keys
276
+ class KeyConvertingIterator: public Iterator {
277
+ public:
278
+ explicit KeyConvertingIterator(Iterator* iter) : iter_(iter) { }
279
+ virtual ~KeyConvertingIterator() { delete iter_; }
280
+ virtual bool Valid() const { return iter_->Valid(); }
281
+ virtual void Seek(const Slice& target) {
282
+ ParsedInternalKey ikey(target, kMaxSequenceNumber, kTypeValue);
283
+ std::string encoded;
284
+ AppendInternalKey(&encoded, ikey);
285
+ iter_->Seek(encoded);
286
+ }
287
+ virtual void SeekToFirst() { iter_->SeekToFirst(); }
288
+ virtual void SeekToLast() { iter_->SeekToLast(); }
289
+ virtual void Next() { iter_->Next(); }
290
+ virtual void Prev() { iter_->Prev(); }
291
+
292
+ virtual Slice key() const {
293
+ assert(Valid());
294
+ ParsedInternalKey key;
295
+ if (!ParseInternalKey(iter_->key(), &key)) {
296
+ status_ = Status::Corruption("malformed internal key");
297
+ return Slice("corrupted key");
298
+ }
299
+ return key.user_key;
300
+ }
301
+
302
+ virtual Slice value() const { return iter_->value(); }
303
+ virtual Status status() const {
304
+ return status_.ok() ? iter_->status() : status_;
305
+ }
306
+
307
+ private:
308
+ mutable Status status_;
309
+ Iterator* iter_;
310
+
311
+ // No copying allowed
312
+ KeyConvertingIterator(const KeyConvertingIterator&);
313
+ void operator=(const KeyConvertingIterator&);
314
+ };
315
+
316
+ class MemTableConstructor: public Constructor {
317
+ public:
318
+ explicit MemTableConstructor(const Comparator* cmp)
319
+ : Constructor(cmp),
320
+ internal_comparator_(cmp) {
321
+ memtable_ = new MemTable(internal_comparator_);
322
+ memtable_->Ref();
323
+ }
324
+ ~MemTableConstructor() {
325
+ memtable_->Unref();
326
+ }
327
+ virtual Status FinishImpl(const Options& options, const KVMap& data) {
328
+ memtable_->Unref();
329
+ memtable_ = new MemTable(internal_comparator_);
330
+ memtable_->Ref();
331
+ int seq = 1;
332
+ for (KVMap::const_iterator it = data.begin();
333
+ it != data.end();
334
+ ++it) {
335
+ memtable_->Add(seq, kTypeValue, it->first, it->second);
336
+ seq++;
337
+ }
338
+ return Status::OK();
339
+ }
340
+ virtual Iterator* NewIterator() const {
341
+ return new KeyConvertingIterator(memtable_->NewIterator());
342
+ }
343
+
344
+ private:
345
+ InternalKeyComparator internal_comparator_;
346
+ MemTable* memtable_;
347
+ };
348
+
349
+ class DBConstructor: public Constructor {
350
+ public:
351
+ explicit DBConstructor(const Comparator* cmp)
352
+ : Constructor(cmp),
353
+ comparator_(cmp) {
354
+ db_ = NULL;
355
+ NewDB();
356
+ }
357
+ ~DBConstructor() {
358
+ delete db_;
359
+ }
360
+ virtual Status FinishImpl(const Options& options, const KVMap& data) {
361
+ delete db_;
362
+ db_ = NULL;
363
+ NewDB();
364
+ for (KVMap::const_iterator it = data.begin();
365
+ it != data.end();
366
+ ++it) {
367
+ WriteBatch batch;
368
+ batch.Put(it->first, it->second);
369
+ ASSERT_TRUE(db_->Write(WriteOptions(), &batch).ok());
370
+ }
371
+ return Status::OK();
372
+ }
373
+ virtual Iterator* NewIterator() const {
374
+ return db_->NewIterator(ReadOptions());
375
+ }
376
+
377
+ virtual DB* db() const { return db_; }
378
+
379
+ private:
380
+ void NewDB() {
381
+ std::string name = test::TmpDir() + "/table_testdb";
382
+
383
+ Options options;
384
+ options.comparator = comparator_;
385
+ Status status = DestroyDB(name, options);
386
+ ASSERT_TRUE(status.ok()) << status.ToString();
387
+
388
+ options.create_if_missing = true;
389
+ options.error_if_exists = true;
390
+ options.write_buffer_size = 10000; // Something small to force merging
391
+ status = DB::Open(options, name, &db_);
392
+ ASSERT_TRUE(status.ok()) << status.ToString();
393
+ }
394
+
395
+ const Comparator* comparator_;
396
+ DB* db_;
397
+ };
398
+
399
+ enum TestType {
400
+ TABLE_TEST,
401
+ BLOCK_TEST,
402
+ MEMTABLE_TEST,
403
+ DB_TEST
404
+ };
405
+
406
+ struct TestArgs {
407
+ TestType type;
408
+ bool reverse_compare;
409
+ int restart_interval;
410
+ };
411
+
412
+ static const TestArgs kTestArgList[] = {
413
+ { TABLE_TEST, false, 16 },
414
+ { TABLE_TEST, false, 1 },
415
+ { TABLE_TEST, false, 1024 },
416
+ { TABLE_TEST, true, 16 },
417
+ { TABLE_TEST, true, 1 },
418
+ { TABLE_TEST, true, 1024 },
419
+
420
+ { BLOCK_TEST, false, 16 },
421
+ { BLOCK_TEST, false, 1 },
422
+ { BLOCK_TEST, false, 1024 },
423
+ { BLOCK_TEST, true, 16 },
424
+ { BLOCK_TEST, true, 1 },
425
+ { BLOCK_TEST, true, 1024 },
426
+
427
+ // Restart interval does not matter for memtables
428
+ { MEMTABLE_TEST, false, 16 },
429
+ { MEMTABLE_TEST, true, 16 },
430
+
431
+ // Do not bother with restart interval variations for DB
432
+ { DB_TEST, false, 16 },
433
+ { DB_TEST, true, 16 },
434
+ };
435
+ static const int kNumTestArgs = sizeof(kTestArgList) / sizeof(kTestArgList[0]);
436
+
437
+ class Harness {
438
+ public:
439
+ Harness() : constructor_(NULL) { }
440
+
441
+ void Init(const TestArgs& args) {
442
+ delete constructor_;
443
+ constructor_ = NULL;
444
+ options_ = Options();
445
+
446
+ options_.block_restart_interval = args.restart_interval;
447
+ // Use shorter block size for tests to exercise block boundary
448
+ // conditions more.
449
+ options_.block_size = 256;
450
+ if (args.reverse_compare) {
451
+ options_.comparator = &reverse_key_comparator;
452
+ }
453
+ switch (args.type) {
454
+ case TABLE_TEST:
455
+ constructor_ = new TableConstructor(options_.comparator);
456
+ break;
457
+ case BLOCK_TEST:
458
+ constructor_ = new BlockConstructor(options_.comparator);
459
+ break;
460
+ case MEMTABLE_TEST:
461
+ constructor_ = new MemTableConstructor(options_.comparator);
462
+ break;
463
+ case DB_TEST:
464
+ constructor_ = new DBConstructor(options_.comparator);
465
+ break;
466
+ }
467
+ }
468
+
469
+ ~Harness() {
470
+ delete constructor_;
471
+ }
472
+
473
+ void Add(const std::string& key, const std::string& value) {
474
+ constructor_->Add(key, value);
475
+ }
476
+
477
+ void Test(Random* rnd) {
478
+ std::vector<std::string> keys;
479
+ KVMap data;
480
+ constructor_->Finish(options_, &keys, &data);
481
+
482
+ TestForwardScan(keys, data);
483
+ TestBackwardScan(keys, data);
484
+ TestRandomAccess(rnd, keys, data);
485
+ }
486
+
487
+ void TestForwardScan(const std::vector<std::string>& keys,
488
+ const KVMap& data) {
489
+ Iterator* iter = constructor_->NewIterator();
490
+ ASSERT_TRUE(!iter->Valid());
491
+ iter->SeekToFirst();
492
+ for (KVMap::const_iterator model_iter = data.begin();
493
+ model_iter != data.end();
494
+ ++model_iter) {
495
+ ASSERT_EQ(ToString(data, model_iter), ToString(iter));
496
+ iter->Next();
497
+ }
498
+ ASSERT_TRUE(!iter->Valid());
499
+ delete iter;
500
+ }
501
+
502
+ void TestBackwardScan(const std::vector<std::string>& keys,
503
+ const KVMap& data) {
504
+ Iterator* iter = constructor_->NewIterator();
505
+ ASSERT_TRUE(!iter->Valid());
506
+ iter->SeekToLast();
507
+ for (KVMap::const_reverse_iterator model_iter = data.rbegin();
508
+ model_iter != data.rend();
509
+ ++model_iter) {
510
+ ASSERT_EQ(ToString(data, model_iter), ToString(iter));
511
+ iter->Prev();
512
+ }
513
+ ASSERT_TRUE(!iter->Valid());
514
+ delete iter;
515
+ }
516
+
517
+ void TestRandomAccess(Random* rnd,
518
+ const std::vector<std::string>& keys,
519
+ const KVMap& data) {
520
+ static const bool kVerbose = false;
521
+ Iterator* iter = constructor_->NewIterator();
522
+ ASSERT_TRUE(!iter->Valid());
523
+ KVMap::const_iterator model_iter = data.begin();
524
+ if (kVerbose) fprintf(stderr, "---\n");
525
+ for (int i = 0; i < 200; i++) {
526
+ const int toss = rnd->Uniform(5);
527
+ switch (toss) {
528
+ case 0: {
529
+ if (iter->Valid()) {
530
+ if (kVerbose) fprintf(stderr, "Next\n");
531
+ iter->Next();
532
+ ++model_iter;
533
+ ASSERT_EQ(ToString(data, model_iter), ToString(iter));
534
+ }
535
+ break;
536
+ }
537
+
538
+ case 1: {
539
+ if (kVerbose) fprintf(stderr, "SeekToFirst\n");
540
+ iter->SeekToFirst();
541
+ model_iter = data.begin();
542
+ ASSERT_EQ(ToString(data, model_iter), ToString(iter));
543
+ break;
544
+ }
545
+
546
+ case 2: {
547
+ std::string key = PickRandomKey(rnd, keys);
548
+ model_iter = data.lower_bound(key);
549
+ if (kVerbose) fprintf(stderr, "Seek '%s'\n",
550
+ EscapeString(key).c_str());
551
+ iter->Seek(Slice(key));
552
+ ASSERT_EQ(ToString(data, model_iter), ToString(iter));
553
+ break;
554
+ }
555
+
556
+ case 3: {
557
+ if (iter->Valid()) {
558
+ if (kVerbose) fprintf(stderr, "Prev\n");
559
+ iter->Prev();
560
+ if (model_iter == data.begin()) {
561
+ model_iter = data.end(); // Wrap around to invalid value
562
+ } else {
563
+ --model_iter;
564
+ }
565
+ ASSERT_EQ(ToString(data, model_iter), ToString(iter));
566
+ }
567
+ break;
568
+ }
569
+
570
+ case 4: {
571
+ if (kVerbose) fprintf(stderr, "SeekToLast\n");
572
+ iter->SeekToLast();
573
+ if (keys.empty()) {
574
+ model_iter = data.end();
575
+ } else {
576
+ std::string last = data.rbegin()->first;
577
+ model_iter = data.lower_bound(last);
578
+ }
579
+ ASSERT_EQ(ToString(data, model_iter), ToString(iter));
580
+ break;
581
+ }
582
+ }
583
+ }
584
+ delete iter;
585
+ }
586
+
587
+ std::string ToString(const KVMap& data, const KVMap::const_iterator& it) {
588
+ if (it == data.end()) {
589
+ return "END";
590
+ } else {
591
+ return "'" + it->first + "->" + it->second + "'";
592
+ }
593
+ }
594
+
595
+ std::string ToString(const KVMap& data,
596
+ const KVMap::const_reverse_iterator& it) {
597
+ if (it == data.rend()) {
598
+ return "END";
599
+ } else {
600
+ return "'" + it->first + "->" + it->second + "'";
601
+ }
602
+ }
603
+
604
+ std::string ToString(const Iterator* it) {
605
+ if (!it->Valid()) {
606
+ return "END";
607
+ } else {
608
+ return "'" + it->key().ToString() + "->" + it->value().ToString() + "'";
609
+ }
610
+ }
611
+
612
+ std::string PickRandomKey(Random* rnd, const std::vector<std::string>& keys) {
613
+ if (keys.empty()) {
614
+ return "foo";
615
+ } else {
616
+ const int index = rnd->Uniform(keys.size());
617
+ std::string result = keys[index];
618
+ switch (rnd->Uniform(3)) {
619
+ case 0:
620
+ // Return an existing key
621
+ break;
622
+ case 1: {
623
+ // Attempt to return something smaller than an existing key
624
+ if (result.size() > 0 && result[result.size()-1] > '\0') {
625
+ result[result.size()-1]--;
626
+ }
627
+ break;
628
+ }
629
+ case 2: {
630
+ // Return something larger than an existing key
631
+ Increment(options_.comparator, &result);
632
+ break;
633
+ }
634
+ }
635
+ return result;
636
+ }
637
+ }
638
+
639
+ // Returns NULL if not running against a DB
640
+ DB* db() const { return constructor_->db(); }
641
+
642
+ private:
643
+ Options options_;
644
+ Constructor* constructor_;
645
+ };
646
+
647
+ // Test empty table/block.
648
+ TEST(Harness, Empty) {
649
+ for (int i = 0; i < kNumTestArgs; i++) {
650
+ Init(kTestArgList[i]);
651
+ Random rnd(test::RandomSeed() + 1);
652
+ Test(&rnd);
653
+ }
654
+ }
655
+
656
+ // Special test for a block with no restart entries. The C++ leveldb
657
+ // code never generates such blocks, but the Java version of leveldb
658
+ // seems to.
659
+ TEST(Harness, ZeroRestartPointsInBlock) {
660
+ char data[sizeof(uint32_t)];
661
+ memset(data, 0, sizeof(data));
662
+ BlockContents contents;
663
+ contents.data = Slice(data, sizeof(data));
664
+ contents.cachable = false;
665
+ contents.heap_allocated = false;
666
+ Block block(contents);
667
+ Iterator* iter = block.NewIterator(BytewiseComparator());
668
+ iter->SeekToFirst();
669
+ ASSERT_TRUE(!iter->Valid());
670
+ iter->SeekToLast();
671
+ ASSERT_TRUE(!iter->Valid());
672
+ iter->Seek("foo");
673
+ ASSERT_TRUE(!iter->Valid());
674
+ delete iter;
675
+ }
676
+
677
+ // Test the empty key
678
+ TEST(Harness, SimpleEmptyKey) {
679
+ for (int i = 0; i < kNumTestArgs; i++) {
680
+ Init(kTestArgList[i]);
681
+ Random rnd(test::RandomSeed() + 1);
682
+ Add("", "v");
683
+ Test(&rnd);
684
+ }
685
+ }
686
+
687
+ TEST(Harness, SimpleSingle) {
688
+ for (int i = 0; i < kNumTestArgs; i++) {
689
+ Init(kTestArgList[i]);
690
+ Random rnd(test::RandomSeed() + 2);
691
+ Add("abc", "v");
692
+ Test(&rnd);
693
+ }
694
+ }
695
+
696
+ TEST(Harness, SimpleMulti) {
697
+ for (int i = 0; i < kNumTestArgs; i++) {
698
+ Init(kTestArgList[i]);
699
+ Random rnd(test::RandomSeed() + 3);
700
+ Add("abc", "v");
701
+ Add("abcd", "v");
702
+ Add("ac", "v2");
703
+ Test(&rnd);
704
+ }
705
+ }
706
+
707
+ TEST(Harness, SimpleSpecialKey) {
708
+ for (int i = 0; i < kNumTestArgs; i++) {
709
+ Init(kTestArgList[i]);
710
+ Random rnd(test::RandomSeed() + 4);
711
+ Add("\xff\xff", "v3");
712
+ Test(&rnd);
713
+ }
714
+ }
715
+
716
+ TEST(Harness, Randomized) {
717
+ for (int i = 0; i < kNumTestArgs; i++) {
718
+ Init(kTestArgList[i]);
719
+ Random rnd(test::RandomSeed() + 5);
720
+ for (int num_entries = 0; num_entries < 2000;
721
+ num_entries += (num_entries < 50 ? 1 : 200)) {
722
+ if ((num_entries % 10) == 0) {
723
+ fprintf(stderr, "case %d of %d: num_entries = %d\n",
724
+ (i + 1), int(kNumTestArgs), num_entries);
725
+ }
726
+ for (int e = 0; e < num_entries; e++) {
727
+ std::string v;
728
+ Add(test::RandomKey(&rnd, rnd.Skewed(4)),
729
+ test::RandomString(&rnd, rnd.Skewed(5), &v).ToString());
730
+ }
731
+ Test(&rnd);
732
+ }
733
+ }
734
+ }
735
+
736
+ TEST(Harness, RandomizedLongDB) {
737
+ Random rnd(test::RandomSeed());
738
+ TestArgs args = { DB_TEST, false, 16 };
739
+ Init(args);
740
+ int num_entries = 100000;
741
+ for (int e = 0; e < num_entries; e++) {
742
+ std::string v;
743
+ Add(test::RandomKey(&rnd, rnd.Skewed(4)),
744
+ test::RandomString(&rnd, rnd.Skewed(5), &v).ToString());
745
+ }
746
+ Test(&rnd);
747
+
748
+ // We must have created enough data to force merging
749
+ int files = 0;
750
+ for (int level = 0; level < config::kNumLevels; level++) {
751
+ std::string value;
752
+ char name[100];
753
+ snprintf(name, sizeof(name), "leveldb.num-files-at-level%d", level);
754
+ ASSERT_TRUE(db()->GetProperty(name, &value));
755
+ files += atoi(value.c_str());
756
+ }
757
+ ASSERT_GT(files, 0);
758
+ }
759
+
760
+ class MemTableTest { };
761
+
762
+ TEST(MemTableTest, Simple) {
763
+ InternalKeyComparator cmp(BytewiseComparator());
764
+ MemTable* memtable = new MemTable(cmp);
765
+ memtable->Ref();
766
+ WriteBatch batch;
767
+ WriteBatchInternal::SetSequence(&batch, 100);
768
+ batch.Put(std::string("k1"), std::string("v1"));
769
+ batch.Put(std::string("k2"), std::string("v2"));
770
+ batch.Put(std::string("k3"), std::string("v3"));
771
+ batch.Put(std::string("largekey"), std::string("vlarge"));
772
+ ASSERT_TRUE(WriteBatchInternal::InsertInto(&batch, memtable).ok());
773
+
774
+ Iterator* iter = memtable->NewIterator();
775
+ iter->SeekToFirst();
776
+ while (iter->Valid()) {
777
+ fprintf(stderr, "key: '%s' -> '%s'\n",
778
+ iter->key().ToString().c_str(),
779
+ iter->value().ToString().c_str());
780
+ iter->Next();
781
+ }
782
+
783
+ delete iter;
784
+ memtable->Unref();
785
+ }
786
+
787
+ static bool Between(uint64_t val, uint64_t low, uint64_t high) {
788
+ bool result = (val >= low) && (val <= high);
789
+ if (!result) {
790
+ fprintf(stderr, "Value %llu is not in range [%llu, %llu]\n",
791
+ (unsigned long long)(val),
792
+ (unsigned long long)(low),
793
+ (unsigned long long)(high));
794
+ }
795
+ return result;
796
+ }
797
+
798
+ class TableTest { };
799
+
800
+ TEST(TableTest, ApproximateOffsetOfPlain) {
801
+ TableConstructor c(BytewiseComparator());
802
+ c.Add("k01", "hello");
803
+ c.Add("k02", "hello2");
804
+ c.Add("k03", std::string(10000, 'x'));
805
+ c.Add("k04", std::string(200000, 'x'));
806
+ c.Add("k05", std::string(300000, 'x'));
807
+ c.Add("k06", "hello3");
808
+ c.Add("k07", std::string(100000, 'x'));
809
+ std::vector<std::string> keys;
810
+ KVMap kvmap;
811
+ Options options;
812
+ options.block_size = 1024;
813
+ options.compression = kNoCompression;
814
+ c.Finish(options, &keys, &kvmap);
815
+
816
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0));
817
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0));
818
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01a"), 0, 0));
819
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0));
820
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 0, 0));
821
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 10000, 11000));
822
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04a"), 210000, 211000));
823
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k05"), 210000, 211000));
824
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k06"), 510000, 511000));
825
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k07"), 510000, 511000));
826
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 610000, 612000));
827
+
828
+ }
829
+
830
+ static bool SnappyCompressionSupported() {
831
+ std::string out;
832
+ Slice in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
833
+ return port::Snappy_Compress(in.data(), in.size(), &out);
834
+ }
835
+
836
+ TEST(TableTest, ApproximateOffsetOfCompressed) {
837
+ if (!SnappyCompressionSupported()) {
838
+ fprintf(stderr, "skipping compression tests\n");
839
+ return;
840
+ }
841
+
842
+ Random rnd(301);
843
+ TableConstructor c(BytewiseComparator());
844
+ std::string tmp;
845
+ c.Add("k01", "hello");
846
+ c.Add("k02", test::CompressibleString(&rnd, 0.25, 10000, &tmp));
847
+ c.Add("k03", "hello3");
848
+ c.Add("k04", test::CompressibleString(&rnd, 0.25, 10000, &tmp));
849
+ std::vector<std::string> keys;
850
+ KVMap kvmap;
851
+ Options options;
852
+ options.block_size = 1024;
853
+ options.compression = kSnappyCompression;
854
+ c.Finish(options, &keys, &kvmap);
855
+
856
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("abc"), 0, 0));
857
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k01"), 0, 0));
858
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k02"), 0, 0));
859
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k03"), 2000, 3000));
860
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("k04"), 2000, 3000));
861
+ ASSERT_TRUE(Between(c.ApproximateOffsetOf("xyz"), 4000, 6000));
862
+ }
863
+
864
+ } // namespace leveldb
865
+
866
+ int main(int argc, char** argv) {
867
+ return leveldb::test::RunAllTests();
868
+ }