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(); }