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 "gtest/gtest.h"
13 #include "leveldb/db.h"
14 #include "leveldb/write_batch.h"
15 #include "util/testutil.h"
16
17 namespace leveldb {
18
19 namespace {
20
21 // Creates a random number in the range of [0, max).
GenerateRandomNumber(int max)22 int GenerateRandomNumber(int max) { return std::rand() % max; }
23
CreateRandomString(int32_t index)24 std::string CreateRandomString(int32_t index) {
25 static const size_t len = 1024;
26 char bytes[len];
27 size_t i = 0;
28 while (i < 8) {
29 bytes[i] = 'a' + ((index >> (4 * i)) & 0xf);
30 ++i;
31 }
32 while (i < sizeof(bytes)) {
33 bytes[i] = 'a' + GenerateRandomNumber(26);
34 ++i;
35 }
36 return std::string(bytes, sizeof(bytes));
37 }
38
39 } // namespace
40
TEST(Issue320,Test)41 TEST(Issue320, Test) {
42 std::srand(0);
43
44 bool delete_before_put = false;
45 bool keep_snapshots = true;
46
47 std::vector<std::unique_ptr<std::pair<std::string, std::string>>> test_map(
48 10000);
49 std::vector<Snapshot const*> snapshots(100, nullptr);
50
51 DB* db;
52 Options options;
53 options.create_if_missing = true;
54
55 std::string dbpath = testing::TempDir() + "leveldb_issue320_test";
56 ASSERT_LEVELDB_OK(DB::Open(options, dbpath, &db));
57
58 uint32_t target_size = 10000;
59 uint32_t num_items = 0;
60 uint32_t count = 0;
61 std::string key;
62 std::string value, old_value;
63
64 WriteOptions writeOptions;
65 ReadOptions readOptions;
66 while (count < 200000) {
67 if ((++count % 1000) == 0) {
68 std::cout << "count: " << count << std::endl;
69 }
70
71 int index = GenerateRandomNumber(test_map.size());
72 WriteBatch batch;
73
74 if (test_map[index] == nullptr) {
75 num_items++;
76 test_map[index].reset(new std::pair<std::string, std::string>(
77 CreateRandomString(index), CreateRandomString(index)));
78 batch.Put(test_map[index]->first, test_map[index]->second);
79 } else {
80 ASSERT_LEVELDB_OK(
81 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_LEVELDB_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
main(int argc,char ** argv)128 int main(int argc, char** argv) {
129 testing::InitGoogleTest(&argc, argv);
130 return RUN_ALL_TESTS();
131 }
132