Home | History | Annotate | Download | only in table
      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 }
    869