issue320_test.cc raw

   1  // Copyright (c) 2019 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 <cstdint>
   6  #include <cstdlib>
   7  #include <iostream>
   8  #include <memory>
   9  #include <string>
  10  #include <vector>
  11  
  12  #include "leveldb/db.h"
  13  #include "leveldb/write_batch.h"
  14  #include "util/testharness.h"
  15  
  16  namespace leveldb {
  17  
  18  namespace {
  19  
  20  // Creates a random number in the range of [0, max).
  21  int GenerateRandomNumber(int max) { return std::rand() % max; }
  22  
  23  std::string CreateRandomString(int32_t index) {
  24    static const size_t len = 1024;
  25    char bytes[len];
  26    size_t i = 0;
  27    while (i < 8) {
  28      bytes[i] = 'a' + ((index >> (4 * i)) & 0xf);
  29      ++i;
  30    }
  31    while (i < sizeof(bytes)) {
  32      bytes[i] = 'a' + GenerateRandomNumber(26);
  33      ++i;
  34    }
  35    return std::string(bytes, sizeof(bytes));
  36  }
  37  
  38  }  // namespace
  39  
  40  class Issue320 {};
  41  
  42  TEST(Issue320, Test) {
  43    std::srand(0);
  44  
  45    bool delete_before_put = false;
  46    bool keep_snapshots = true;
  47  
  48    std::vector<std::unique_ptr<std::pair<std::string, std::string>>> test_map(
  49        10000);
  50    std::vector<Snapshot const*> snapshots(100, nullptr);
  51  
  52    DB* db;
  53    Options options;
  54    options.create_if_missing = true;
  55  
  56    std::string dbpath = test::TmpDir() + "/leveldb_issue320_test";
  57    ASSERT_OK(DB::Open(options, dbpath, &db));
  58  
  59    uint32_t target_size = 10000;
  60    uint32_t num_items = 0;
  61    uint32_t count = 0;
  62    std::string key;
  63    std::string value, old_value;
  64  
  65    WriteOptions writeOptions;
  66    ReadOptions readOptions;
  67    while (count < 200000) {
  68      if ((++count % 1000) == 0) {
  69        std::cout << "count: " << count << std::endl;
  70      }
  71  
  72      int index = GenerateRandomNumber(test_map.size());
  73      WriteBatch batch;
  74  
  75      if (test_map[index] == nullptr) {
  76        num_items++;
  77        test_map[index].reset(new std::pair<std::string, std::string>(
  78            CreateRandomString(index), CreateRandomString(index)));
  79        batch.Put(test_map[index]->first, test_map[index]->second);
  80      } else {
  81        ASSERT_OK(db->Get(readOptions, test_map[index]->first, &old_value));
  82        if (old_value != test_map[index]->second) {
  83          std::cout << "ERROR incorrect value returned by Get" << std::endl;
  84          std::cout << "  count=" << count << std::endl;
  85          std::cout << "  old value=" << old_value << std::endl;
  86          std::cout << "  test_map[index]->second=" << test_map[index]->second
  87                    << std::endl;
  88          std::cout << "  test_map[index]->first=" << test_map[index]->first
  89                    << std::endl;
  90          std::cout << "  index=" << index << std::endl;
  91          ASSERT_EQ(old_value, test_map[index]->second);
  92        }
  93  
  94        if (num_items >= target_size && GenerateRandomNumber(100) > 30) {
  95          batch.Delete(test_map[index]->first);
  96          test_map[index] = nullptr;
  97          --num_items;
  98        } else {
  99          test_map[index]->second = CreateRandomString(index);
 100          if (delete_before_put) batch.Delete(test_map[index]->first);
 101          batch.Put(test_map[index]->first, test_map[index]->second);
 102        }
 103      }
 104  
 105      ASSERT_OK(db->Write(writeOptions, &batch));
 106  
 107      if (keep_snapshots && GenerateRandomNumber(10) == 0) {
 108        int i = GenerateRandomNumber(snapshots.size());
 109        if (snapshots[i] != nullptr) {
 110          db->ReleaseSnapshot(snapshots[i]);
 111        }
 112        snapshots[i] = db->GetSnapshot();
 113      }
 114    }
 115  
 116    for (Snapshot const* snapshot : snapshots) {
 117      if (snapshot) {
 118        db->ReleaseSnapshot(snapshot);
 119      }
 120    }
 121  
 122    delete db;
 123    DestroyDB(dbpath, options);
 124  }
 125  
 126  }  // namespace leveldb
 127  
 128  int main(int argc, char** argv) { return leveldb::test::RunAllTests(); }
 129