]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | // This source code is licensed under both the GPLv2 (found in the | |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
5 | ||
6 | #include "db/wal_edit.h" | |
7 | ||
8 | #include "db/db_test_util.h" | |
9 | #include "file/file_util.h" | |
10 | #include "port/port.h" | |
11 | #include "port/stack_trace.h" | |
12 | #include "test_util/testharness.h" | |
13 | #include "test_util/testutil.h" | |
14 | ||
15 | namespace ROCKSDB_NAMESPACE { | |
16 | ||
17 | TEST(WalSet, AddDeleteReset) { | |
18 | WalSet wals; | |
19 | ASSERT_TRUE(wals.GetWals().empty()); | |
20 | ||
21 | // Create WAL 1 - 10. | |
22 | for (WalNumber log_number = 1; log_number <= 10; log_number++) { | |
23 | wals.AddWal(WalAddition(log_number)); | |
24 | } | |
25 | ASSERT_EQ(wals.GetWals().size(), 10); | |
26 | ||
27 | // Delete WAL 1 - 5. | |
28 | wals.DeleteWalsBefore(6); | |
29 | ASSERT_EQ(wals.GetWals().size(), 5); | |
30 | ||
31 | WalNumber expected_log_number = 6; | |
32 | for (auto it : wals.GetWals()) { | |
33 | WalNumber log_number = it.first; | |
34 | ASSERT_EQ(log_number, expected_log_number++); | |
35 | } | |
36 | ||
37 | wals.Reset(); | |
38 | ASSERT_TRUE(wals.GetWals().empty()); | |
39 | } | |
40 | ||
41 | TEST(WalSet, Overwrite) { | |
42 | constexpr WalNumber kNumber = 100; | |
43 | constexpr uint64_t kBytes = 200; | |
44 | WalSet wals; | |
45 | wals.AddWal(WalAddition(kNumber)); | |
46 | ASSERT_FALSE(wals.GetWals().at(kNumber).HasSyncedSize()); | |
47 | wals.AddWal(WalAddition(kNumber, WalMetadata(kBytes))); | |
48 | ASSERT_TRUE(wals.GetWals().at(kNumber).HasSyncedSize()); | |
49 | ASSERT_EQ(wals.GetWals().at(kNumber).GetSyncedSizeInBytes(), kBytes); | |
50 | } | |
51 | ||
52 | TEST(WalSet, SmallerSyncedSize) { | |
53 | constexpr WalNumber kNumber = 100; | |
54 | constexpr uint64_t kBytes = 100; | |
55 | WalSet wals; | |
56 | ASSERT_OK(wals.AddWal(WalAddition(kNumber, WalMetadata(kBytes)))); | |
57 | Status s = wals.AddWal(WalAddition(kNumber, WalMetadata(0))); | |
58 | ASSERT_TRUE(s.IsCorruption()); | |
59 | ASSERT_TRUE( | |
60 | s.ToString().find( | |
61 | "WAL 100 must not have smaller synced size than previous one") != | |
62 | std::string::npos); | |
63 | } | |
64 | ||
65 | TEST(WalSet, CreateTwice) { | |
66 | constexpr WalNumber kNumber = 100; | |
67 | WalSet wals; | |
68 | ASSERT_OK(wals.AddWal(WalAddition(kNumber))); | |
69 | Status s = wals.AddWal(WalAddition(kNumber)); | |
70 | ASSERT_TRUE(s.IsCorruption()); | |
71 | ASSERT_TRUE(s.ToString().find("WAL 100 is created more than once") != | |
72 | std::string::npos); | |
73 | } | |
74 | ||
75 | TEST(WalSet, DeleteAllWals) { | |
76 | constexpr WalNumber kMaxWalNumber = 10; | |
77 | WalSet wals; | |
78 | for (WalNumber i = 1; i <= kMaxWalNumber; i++) { | |
79 | wals.AddWal(WalAddition(i)); | |
80 | } | |
81 | ASSERT_OK(wals.DeleteWalsBefore(kMaxWalNumber + 1)); | |
82 | } | |
83 | ||
84 | class WalSetTest : public DBTestBase { | |
85 | public: | |
86 | WalSetTest() : DBTestBase("WalSetTest", /* env_do_fsync */ true) {} | |
87 | ||
88 | void SetUp() override { | |
89 | test_dir_ = test::PerThreadDBPath("wal_set_test"); | |
90 | ASSERT_OK(env_->CreateDir(test_dir_)); | |
91 | } | |
92 | ||
93 | void TearDown() override { | |
94 | EXPECT_OK(DestroyDir(env_, test_dir_)); | |
95 | logs_on_disk_.clear(); | |
96 | wals_.Reset(); | |
97 | } | |
98 | ||
99 | void CreateWalOnDisk(WalNumber number, const std::string& fname, | |
100 | uint64_t size_bytes) { | |
101 | std::unique_ptr<WritableFile> f; | |
102 | std::string fpath = Path(fname); | |
103 | ASSERT_OK(env_->NewWritableFile(fpath, &f, EnvOptions())); | |
104 | std::string content(size_bytes, '0'); | |
105 | ASSERT_OK(f->Append(content)); | |
106 | ASSERT_OK(f->Close()); | |
107 | ||
108 | logs_on_disk_[number] = fpath; | |
109 | } | |
110 | ||
111 | void AddWalToWalSet(WalNumber number, uint64_t size_bytes) { | |
112 | // Create WAL. | |
113 | ASSERT_OK(wals_.AddWal(WalAddition(number))); | |
114 | // Close WAL. | |
115 | WalMetadata wal(size_bytes); | |
116 | ASSERT_OK(wals_.AddWal(WalAddition(number, wal))); | |
117 | } | |
118 | ||
119 | Status CheckWals() const { return wals_.CheckWals(env_, logs_on_disk_); } | |
120 | ||
121 | private: | |
122 | std::string test_dir_; | |
123 | std::unordered_map<WalNumber, std::string> logs_on_disk_; | |
124 | WalSet wals_; | |
125 | ||
126 | std::string Path(const std::string& fname) { return test_dir_ + "/" + fname; } | |
127 | }; | |
128 | ||
129 | TEST_F(WalSetTest, CheckEmptyWals) { ASSERT_OK(CheckWals()); } | |
130 | ||
131 | TEST_F(WalSetTest, CheckWals) { | |
132 | for (int number = 1; number < 10; number++) { | |
133 | uint64_t size = rand() % 100; | |
134 | std::stringstream ss; | |
135 | ss << "log" << number; | |
136 | std::string fname = ss.str(); | |
137 | CreateWalOnDisk(number, fname, size); | |
138 | // log 0 - 5 are obsolete. | |
139 | if (number > 5) { | |
140 | AddWalToWalSet(number, size); | |
141 | } | |
142 | } | |
143 | ASSERT_OK(CheckWals()); | |
144 | } | |
145 | ||
146 | TEST_F(WalSetTest, CheckMissingWals) { | |
147 | for (int number = 1; number < 10; number++) { | |
148 | uint64_t size = rand() % 100; | |
149 | AddWalToWalSet(number, size); | |
150 | // logs with even number are missing from disk. | |
151 | if (number % 2) { | |
152 | std::stringstream ss; | |
153 | ss << "log" << number; | |
154 | std::string fname = ss.str(); | |
155 | CreateWalOnDisk(number, fname, size); | |
156 | } | |
157 | } | |
158 | ||
159 | Status s = CheckWals(); | |
160 | ASSERT_TRUE(s.IsCorruption()) << s.ToString(); | |
161 | // The first log with even number is missing. | |
162 | std::stringstream expected_err; | |
163 | expected_err << "Missing WAL with log number: " << 2; | |
164 | ASSERT_TRUE(s.ToString().find(expected_err.str()) != std::string::npos) | |
165 | << s.ToString(); | |
166 | } | |
167 | ||
168 | TEST_F(WalSetTest, CheckWalsWithShrinkedSize) { | |
169 | for (int number = 1; number < 10; number++) { | |
170 | uint64_t size = rand() % 100 + 1; | |
171 | AddWalToWalSet(number, size); | |
172 | // logs with even number have shrinked size. | |
173 | std::stringstream ss; | |
174 | ss << "log" << number; | |
175 | std::string fname = ss.str(); | |
176 | CreateWalOnDisk(number, fname, (number % 2) ? size : size - 1); | |
177 | } | |
178 | ||
179 | Status s = CheckWals(); | |
180 | ASSERT_TRUE(s.IsCorruption()) << s.ToString(); | |
181 | // The first log with even number has wrong size. | |
182 | std::stringstream expected_err; | |
183 | expected_err << "Size mismatch: WAL (log number: " << 2 << ")"; | |
184 | ASSERT_TRUE(s.ToString().find(expected_err.str()) != std::string::npos) | |
185 | << s.ToString(); | |
186 | } | |
187 | ||
188 | } // namespace ROCKSDB_NAMESPACE | |
189 | ||
190 | int main(int argc, char** argv) { | |
191 | ROCKSDB_NAMESPACE::port::InstallStackTraceHandler(); | |
192 | ::testing::InitGoogleTest(&argc, argv); | |
193 | return RUN_ALL_TESTS(); | |
194 | } |