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