/ src / leveldb / issues / issue320_test.cc
issue320_test.cc
  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(); }