Feathercoin  0.5.0
P2P Digital Currency
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
table_test.cc
Go to the documentation of this file.
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"
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);
54  *start = Reverse(s);
55  }
56 
57  virtual void FindShortSuccessor(std::string* key) const {
58  std::string s = Reverse(*key);
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:
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 
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 
182  public:
183  explicit BlockConstructor(const Comparator* cmp)
184  : Constructor(cmp),
185  comparator_(cmp),
186  block_(NULL) { }
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:
215  std::string data_;
217 
219 };
220 
222  public:
224  : Constructor(cmp),
225  source_(NULL), table_(NULL) {
226  }
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 
271 
273 };
274 
275 // A helper class that converts internal format keys into user keys
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());
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_;
310 
311  // No copying allowed
313  void operator=(const KeyConvertingIterator&);
314 };
315 
317  public:
318  explicit MemTableConstructor(const Comparator* cmp)
319  : Constructor(cmp),
320  internal_comparator_(cmp) {
322  memtable_->Ref();
323  }
325  memtable_->Unref();
326  }
327  virtual Status FinishImpl(const Options& options, const KVMap& data) {
328  memtable_->Unref();
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 {
342  }
343 
344  private:
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  }
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 
396  DB* db_;
397 };
398 
399 enum TestType {
404 };
405 
406 struct TestArgs {
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 
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:
456  break;
457  case BLOCK_TEST:
459  break;
460  case MEMTABLE_TEST:
462  break;
463  case DB_TEST:
465  break;
466  }
467  }
468 
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 
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:
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) {
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) {
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);
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;
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) {
868 }
std::string PickRandomKey(Random *rnd, const std::vector< std::string > &keys)
Definition: table_test.cc:612
void Add(const Slice &key, const Slice &value)
DB * db() const
Definition: table_test.cc:640
virtual DB * db() const
Definition: table_test.cc:377
virtual void Prev()=0
virtual Status Write(const WriteOptions &options, WriteBatch *updates)=0
std::string * value
Definition: version_set.cc:270
bool create_if_missing
Definition: options.h:45
std::string TmpDir()
Definition: testharness.cc:60
uint64_t ApproximateOffsetOf(const Slice &key) const
Definition: table.cc:248
std::string contents_
Definition: table_test.cc:106
virtual bool Valid() const
Definition: table_test.cc:280
const char * data() const
Definition: slice.h:40
void Test(Random *rnd)
Definition: table_test.cc:477
int RandomSeed()
Definition: testharness.cc:67
#define ASSERT_GT(a, b)
Definition: testharness.h:110
virtual Status Append(const Slice &data)
Definition: table_test.cc:100
virtual DB * db() const
Definition: table_test.cc:175
virtual Status FinishImpl(const Options &options, const KVMap &data)
Definition: table_test.cc:230
void Add(const std::string &key, const Slice &value)
Definition: table_test.cc:146
static Status Corruption(const Slice &msg, const Slice &msg2=Slice())
Definition: status.h:38
bool start
Definition: db_bench.cc:282
void operator=(const KeyConvertingIterator &)
virtual Iterator * NewIterator() const =0
Status status() const
virtual Slice value() const
Definition: table_test.cc:302
void TestRandomAccess(Random *rnd, const std::vector< std::string > &keys, const KVMap &data)
Definition: table_test.cc:517
InternalKeyComparator internal_comparator_
Definition: table_test.cc:345
static void SetSequence(WriteBatch *batch, SequenceNumber seq)
Definition: write_batch.cc:94
virtual void Seek(const Slice &target)
Definition: table_test.cc:281
std::map< std::string, std::string, STLLessThan > KVMap
Definition: table_test.cc:137
virtual Status FinishImpl(const Options &options, const KVMap &data)
Definition: table_test.cc:327
virtual Status status() const =0
Constructor * constructor_
Definition: table_test.cc:644
int RunAllTests()
Definition: testharness.cc:36
int main(int argc, char **argv)
Definition: table_test.cc:866
virtual void FindShortSuccessor(std::string *key) const =0
void Init(const TestArgs &args)
Definition: table_test.cc:441
Slice CompressibleString(Random *rnd, double compressed_fraction, int len, std::string *dst)
Definition: testutil.cc:34
virtual Iterator * NewIterator() const
Definition: table_test.cc:209
const Comparator * comparator_
Definition: table_test.cc:395
virtual ~Constructor()
Definition: table_test.cc:144
virtual Status FinishImpl(const Options &options, const KVMap &data)=0
virtual Iterator * NewIterator() const
Definition: table_test.cc:253
size_t block_size
Definition: options.h:106
virtual Iterator * NewIterator(const ReadOptions &options)=0
bool ParseInternalKey(const Slice &internal_key, ParsedInternalKey *result)
Definition: dbformat.h:176
void AppendInternalKey(std::string *result, const ParsedInternalKey &key)
Definition: dbformat.cc:18
static Status OK()
Definition: status.h:32
virtual Slice value() const =0
#define ASSERT_EQ(a, b)
Definition: testharness.h:107
virtual void Next()=0
Status DestroyDB(const std::string &dbname, const Options &options)
Definition: db_impl.cc:1467
virtual void SeekToLast()=0
Iterator * NewIterator(const ReadOptions &) const
Definition: table.cc:210
Definition: db.h:44
virtual Status Close()
Definition: table_test.cc:96
static Status InvalidArgument(const Slice &msg, const Slice &msg2=Slice())
Definition: status.h:44
Iterator * NewIterator(const Comparator *comparator)
Definition: block.cc:256
std::string ToString(const Iterator *it)
Definition: table_test.cc:604
bool error_if_exists
Definition: options.h:49
unsigned int uint32_t
Definition: stdint.h:21
bool Snappy_Compress(const char *input, size_t input_length, std::string *output)
KeyConvertingIterator(Iterator *iter)
Definition: table_test.cc:278
StringSource(const Slice &contents)
Definition: table_test.cc:112
size_t size() const
Definition: slice.h:43
unsigned long long uint64_t
Definition: stdint.h:22
static Status Open(const Options &options, const std::string &name, DB **dbptr)
Definition: db_impl.cc:1430
DBConstructor(const Comparator *cmp)
Definition: table_test.cc:351
TEST(CorruptionTest, Recovery)
Iterator * NewIterator()
Definition: memtable.cc:78
virtual void Seek(const Slice &target)=0
std::string EscapeString(const Slice &value)
Definition: logging.cc:42
#define ASSERT_TRUE(c)
Definition: testharness.h:105
virtual void SeekToFirst()=0
uint64_t ApproximateOffsetOf(const Slice &key) const
Definition: table_test.cc:257
std::string ToString(const KVMap &data, const KVMap::const_reverse_iterator &it)
Definition: table_test.cc:595
uint64_t FileSize() const
uint32_t Uniform(int n)
Definition: random.h:48
virtual Iterator * NewIterator() const
Definition: table_test.cc:340
uint32_t Skewed(int max_log)
Definition: random.h:57
const std::string & contents() const
Definition: table_test.cc:94
void TestForwardScan(const std::vector< std::string > &keys, const KVMap &data)
Definition: table_test.cc:487
virtual Status FinishImpl(const Options &options, const KVMap &data)
Definition: table_test.cc:360
static Status InsertInto(const WriteBatch *batch, MemTable *memtable)
Definition: write_batch.cc:128
std::string contents_
Definition: table_test.cc:134
const Comparator * BytewiseComparator()
Definition: comparator.cc:76
CompressionType compression
Definition: options.h:129
uint64_t Size() const
Definition: table_test.cc:118
StringSource * source_
Definition: table_test.cc:269
virtual void FindShortestSeparator(std::string *start, const Slice &limit) const =0
void TestBackwardScan(const std::vector< std::string > &keys, const KVMap &data)
Definition: table_test.cc:502
virtual int Compare(const Slice &a, const Slice &b) const =0
virtual Status status() const
Definition: table_test.cc:303
virtual bool Valid() const =0
const Comparator * comparator_
Definition: table_test.cc:214
const Comparator * cmp
Definition: table_test.cc:80
virtual Iterator * NewIterator() const
Definition: table_test.cc:373
static Status Open(const Options &options, RandomAccessFile *file, uint64_t file_size, Table **table)
Definition: table.cc:38
MemTableConstructor(const Comparator *cmp)
Definition: table_test.cc:318
int block_restart_interval
Definition: options.h:113
virtual Slice key() const =0
BlockConstructor(const Comparator *cmp)
Definition: table_test.cc:183
virtual Status Flush()
Definition: table_test.cc:97
bool ok() const
Definition: status.h:52
void Add(SequenceNumber seq, ValueType type, const Slice &key, const Slice &value)
Definition: memtable.cc:82
size_t write_buffer_size
Definition: options.h:83
virtual Status Sync()
Definition: table_test.cc:98
void Finish(const Options &options, std::vector< std::string > *keys, KVMap *kvmap)
Definition: table_test.cc:153
std::string RandomKey(Random *rnd, int len)
Definition: testutil.cc:20
TableConstructor(const Comparator *cmp)
Definition: table_test.cc:223
Slice RandomString(Random *rnd, int len, std::string *dst)
Definition: testutil.cc:12
virtual Slice key() const
Definition: table_test.cc:292
std::string ToString(const KVMap &data, const KVMap::const_iterator &it)
Definition: table_test.cc:587
std::string ToString() const
Definition: slice.h:66
virtual Status FinishImpl(const Options &options, const KVMap &data)
Definition: table_test.cc:190
virtual const KVMap & data()
Definition: table_test.cc:173
void Put(const Slice &key, const Slice &value)
Definition: write_batch.cc:98
const Comparator * comparator
Definition: options.h:41
void Add(const Slice &key, const Slice &value)
int atoi(const std::string &str)
Definition: util.h:271
void Add(const std::string &key, const std::string &value)
Definition: table_test.cc:473
virtual Status Read(uint64_t offset, size_t n, Slice *result, char *scratch) const
Definition: table_test.cc:120
const char * name
Definition: testharness.cc:18
Constructor(const Comparator *cmp)
Definition: table_test.cc:143
std::string ToString() const
Definition: status.cc:36