Loading...
Searching...
No Matches
recovery_test.cpp
Go to the documentation of this file.
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
21
22#include <glog/logging.h>
23#include <gmock/gmock.h>
24#include <gtest/gtest.h>
25
26#include <filesystem>
27#include <future>
28
33
34namespace resdb {
35namespace {
36
37using ::resdb::testing::EqualsProto;
38using ::testing::Invoke;
39using ::testing::Return;
40using ::testing::Test;
41
42const std::string log_path = "./log/test_log";
43
44ResConfigData GetConfigData(int buf_size = 10) {
45 ResConfigData data;
46 data.set_recovery_enabled(true);
47 data.set_recovery_path(log_path);
48 data.set_recovery_buffer_size(buf_size);
49 data.set_recovery_ckpt_time_s(1);
50
51 return data;
52}
53
54std::vector<std::string> Listlogs(const std::string &path) {
55 std::vector<std::string> ret;
56 std::string dir = std::filesystem::path(path).parent_path();
57 for (const auto &entry : std::filesystem::directory_iterator(dir)) {
58 LOG(ERROR) << "path:" << entry.path();
59 ret.push_back(entry.path());
60 }
61 return ret;
62}
63
64class RecoveryTest : public Test {
65 public:
66 RecoveryTest()
67 : config_(GetConfigData(), ReplicaInfo(), KeyInfo(), CertificateInfo()),
68 system_info_() {
69 std::string dir = std::filesystem::path(log_path).parent_path();
70 std::filesystem::remove_all(dir);
71 }
72
73 protected:
74 ResDBConfig config_;
75 SystemInfo system_info_;
76 MockCheckPoint checkpoint_;
77};
78
79TEST_F(RecoveryTest, ReadLog) {
80 std::vector<int> types = {Request::TYPE_PRE_PREPARE, Request::TYPE_PREPARE,
81 Request::TYPE_COMMIT, Request::TYPE_CHECKPOINT,
82 Request::TYPE_NEWVIEW, Request::TYPE_NEW_TXNS};
83
84 std::vector<int> expected_types = {
85 Request::TYPE_PRE_PREPARE, Request::TYPE_PREPARE, Request::TYPE_COMMIT,
86 Request::TYPE_CHECKPOINT, Request::TYPE_NEWVIEW,
87 };
88
89 {
90 Recovery recovery(config_, &checkpoint_, &system_info_, nullptr);
91
92 for (int t : types) {
93 std::unique_ptr<Request> request =
94 NewRequest(static_cast<resdb::Request_Type>(t), Request(), 0);
95 request->set_seq(1);
96 recovery.AddRequest(nullptr, request.get());
97 }
98 }
99 {
100 std::vector<Request> list;
101 Recovery recovery(config_, &checkpoint_, &system_info_, nullptr);
102 recovery.ReadLogs(
103 [&](const SystemInfoData &data) {},
104 [&](std::unique_ptr<Context> context,
105 std::unique_ptr<Request> request) { list.push_back(*request); });
106
107 EXPECT_EQ(list.size(), expected_types.size());
108
109 for (size_t i = 0; i < expected_types.size(); ++i) {
110 EXPECT_EQ(list[i].type(), expected_types[i]);
111 }
112 }
113}
114
115TEST_F(RecoveryTest, ReadLog_FlushOnce) {
116 ResDBConfig config(GetConfigData(1024), ReplicaInfo(), KeyInfo(),
117 CertificateInfo());
118
119 std::vector<int> types = {Request::TYPE_PRE_PREPARE, Request::TYPE_PREPARE,
120 Request::TYPE_COMMIT, Request::TYPE_CHECKPOINT,
121 Request::TYPE_NEWVIEW, Request::TYPE_NEW_TXNS};
122
123 std::vector<int> expected_types = {
124 Request::TYPE_PRE_PREPARE, Request::TYPE_PREPARE, Request::TYPE_COMMIT,
125 Request::TYPE_CHECKPOINT, Request::TYPE_NEWVIEW,
126 };
127
128 {
129 Recovery recovery(config, &checkpoint_, &system_info_, nullptr);
130
131 for (int t : types) {
132 std::unique_ptr<Request> request =
133 NewRequest(static_cast<resdb::Request_Type>(t), Request(), 0);
134 request->set_seq(1);
135 recovery.AddRequest(nullptr, request.get());
136 }
137 }
138 {
139 std::vector<Request> list;
140 Recovery recovery(config, &checkpoint_, &system_info_, nullptr);
141 recovery.ReadLogs([&](const SystemInfoData &data) {},
142 [&](std::unique_ptr<Context> context,
143 std::unique_ptr<Request> request) {
144 LOG(ERROR) << "call back:" << request->seq();
145 list.push_back(*request);
146 });
147
148 EXPECT_EQ(list.size(), expected_types.size());
149
150 for (size_t i = 0; i < expected_types.size(); ++i) {
151 EXPECT_EQ(list[i].type(), expected_types[i]);
152 }
153 }
154}
155
156TEST_F(RecoveryTest, CheckPoint) {
157 ResDBConfig config(GetConfigData(1024), ReplicaInfo(), KeyInfo(),
158 CertificateInfo());
159
160 std::vector<int> types = {Request::TYPE_PRE_PREPARE, Request::TYPE_PREPARE,
161 Request::TYPE_COMMIT};
162
163 std::vector<int> expected_types = {
164 Request::TYPE_PRE_PREPARE, Request::TYPE_PREPARE, Request::TYPE_COMMIT};
165
166 std::promise<bool> insert_done, ckpt;
167 std::future<bool> insert_done_future = insert_done.get_future(),
168 ckpt_future = ckpt.get_future();
169 int time = 1;
170 EXPECT_CALL(checkpoint_, GetStableCheckpoint()).WillRepeatedly(Invoke([&]() {
171 if (time == 1) {
172 insert_done_future.get();
173 } else if (time == 2) {
174 ckpt.set_value(true);
175 }
176 time++;
177 return 5;
178 }));
179
180 {
181 Recovery recovery(config, &checkpoint_, &system_info_, nullptr);
182
183 for (int i = 1; i < 10; ++i) {
184 for (int t : types) {
185 std::unique_ptr<Request> request =
186 NewRequest(static_cast<resdb::Request_Type>(t), Request(), i);
187 request->set_seq(i);
188 recovery.AddRequest(nullptr, request.get());
189 }
190 }
191 insert_done.set_value(true);
192 ckpt_future.get();
193 for (int i = 10; i < 20; ++i) {
194 for (int t : types) {
195 std::unique_ptr<Request> request =
196 NewRequest(static_cast<resdb::Request_Type>(t), Request(), i);
197 request->set_seq(i);
198 recovery.AddRequest(nullptr, request.get());
199 }
200 }
201 }
202 std::vector<std::string> log_list = Listlogs(log_path);
203 EXPECT_EQ(log_list.size(), 2);
204 {
205 std::vector<Request> list;
206 Recovery recovery(config, &checkpoint_, &system_info_, nullptr);
207 recovery.ReadLogs([&](const SystemInfoData &data) {},
208 [&](std::unique_ptr<Context> context,
209 std::unique_ptr<Request> request) {
210 list.push_back(*request);
211 // LOG(ERROR)<<"call back:"<<request->seq();
212 });
213
214 EXPECT_EQ(list.size(), types.size() * 14);
215
216 for (size_t i = 0; i < expected_types.size(); ++i) {
217 EXPECT_EQ(list[i].type(), expected_types[i]);
218 }
219 }
220}
221
222TEST_F(RecoveryTest, CheckPoint2) {
223 ResDBConfig config(GetConfigData(1024), ReplicaInfo(), KeyInfo(),
224 CertificateInfo());
225 MockStorage storage;
226 EXPECT_CALL(storage, Flush).Times(2).WillRepeatedly(Return(true));
227
228 std::vector<int> types = {Request::TYPE_PRE_PREPARE, Request::TYPE_PREPARE,
229 Request::TYPE_COMMIT};
230
231 std::vector<int> expected_types = {
232 Request::TYPE_PRE_PREPARE, Request::TYPE_PREPARE, Request::TYPE_COMMIT};
233
234 std::promise<bool> insert_done, ckpt, insert_done2, ckpt2;
235 std::future<bool> insert_done_future = insert_done.get_future(),
236 ckpt_future = ckpt.get_future();
237 std::future<bool> insert_done2_future = insert_done2.get_future();
238 std::future<bool> ckpt_future2 = ckpt2.get_future();
239 int time = 1;
240 EXPECT_CALL(checkpoint_, GetStableCheckpoint()).WillRepeatedly(Invoke([&]() {
241 if (time == 1) {
242 insert_done_future.get();
243 } else if (time == 2) {
244 ckpt.set_value(true);
245 } else if (time == 3) {
246 insert_done2_future.get();
247 } else if (time == 4) {
248 ckpt2.set_value(true);
249 }
250 time++;
251 if (time > 3) {
252 return 25;
253 }
254 return 5;
255 }));
256
257 {
258 Recovery recovery(config, &checkpoint_, &system_info_, &storage);
259
260 for (int i = 1; i < 10; ++i) {
261 for (int t : types) {
262 std::unique_ptr<Request> request =
263 NewRequest(static_cast<resdb::Request_Type>(t), Request(), i);
264 request->set_seq(i);
265 recovery.AddRequest(nullptr, request.get());
266 }
267 }
268 insert_done.set_value(true);
269 ckpt_future.get();
270 for (int i = 10; i < 20; ++i) {
271 for (int t : types) {
272 std::unique_ptr<Request> request =
273 NewRequest(static_cast<resdb::Request_Type>(t), Request(), i);
274 request->set_seq(i);
275 recovery.AddRequest(nullptr, request.get());
276 }
277 }
278 }
279 std::vector<std::string> log_list = Listlogs(log_path);
280 EXPECT_EQ(log_list.size(), 2);
281 {
282 std::vector<Request> list;
283 Recovery recovery(config, &checkpoint_, &system_info_, &storage);
284 recovery.ReadLogs([&](const SystemInfoData &data) {},
285 [&](std::unique_ptr<Context> context,
286 std::unique_ptr<Request> request) {
287 list.push_back(*request);
288 // LOG(ERROR)<<"call back:"<<request->seq();
289 });
290
291 EXPECT_EQ(list.size(), types.size() * 14);
292
293 for (size_t i = 0; i < expected_types.size(); ++i) {
294 EXPECT_EQ(list[i].type(), expected_types[i]);
295 }
296
297 for (int i = 20; i < 30; ++i) {
298 for (int t : types) {
299 std::unique_ptr<Request> request =
300 NewRequest(static_cast<resdb::Request_Type>(t), Request(), i);
301 request->set_seq(i);
302 recovery.AddRequest(nullptr, request.get());
303 }
304 }
305 insert_done2.set_value(true);
306 ckpt_future2.get();
307
308 for (int i = 30; i < 35; ++i) {
309 for (int t : types) {
310 std::unique_ptr<Request> request =
311 NewRequest(static_cast<resdb::Request_Type>(t), Request(), i);
312 request->set_seq(i);
313 recovery.AddRequest(nullptr, request.get());
314 }
315 }
316 }
317
318 {
319 std::vector<Request> list;
320 Recovery recovery(config, &checkpoint_, &system_info_, &storage);
321 recovery.ReadLogs([&](const SystemInfoData &data) {},
322 [&](std::unique_ptr<Context> context,
323 std::unique_ptr<Request> request) {
324 list.push_back(*request);
325 // LOG(ERROR)<<"call back:"<<request->seq();
326 });
327
328 EXPECT_EQ(list.size(), types.size() * 9);
329
330 for (size_t i = 0; i < expected_types.size(); ++i) {
331 EXPECT_EQ(list[i].type(), expected_types[i]);
332 }
333 EXPECT_EQ(recovery.GetMinSeq(), 30);
334 EXPECT_EQ(recovery.GetMaxSeq(), 34);
335 }
336}
337
338TEST_F(RecoveryTest, SystemInfo) {
339 ResDBConfig config(GetConfigData(1024), ReplicaInfo(), KeyInfo(),
340 CertificateInfo());
341 MockStorage storage;
342 EXPECT_CALL(storage, Flush).Times(2).WillRepeatedly(Return(true));
343
344 std::vector<int> types = {Request::TYPE_PRE_PREPARE, Request::TYPE_PREPARE,
345 Request::TYPE_COMMIT};
346
347 std::vector<int> expected_types = {
348 Request::TYPE_PRE_PREPARE, Request::TYPE_PREPARE, Request::TYPE_COMMIT};
349
350 std::promise<bool> insert_done, ckpt, insert_done2, ckpt2;
351 std::future<bool> insert_done_future = insert_done.get_future(),
352 ckpt_future = ckpt.get_future();
353 std::future<bool> insert_done2_future = insert_done2.get_future();
354 std::future<bool> ckpt_future2 = ckpt2.get_future();
355 int time = 1;
356 EXPECT_CALL(checkpoint_, GetStableCheckpoint()).WillRepeatedly(Invoke([&]() {
357 if (time == 1) {
358 insert_done_future.get();
359 } else if (time == 2) {
360 ckpt.set_value(true);
361 } else if (time == 3) {
362 insert_done2_future.get();
363 } else if (time == 4) {
364 ckpt2.set_value(true);
365 }
366 time++;
367 if (time > 3) {
368 return 25;
369 }
370 return 5;
371 }));
372
373 {
374 Recovery recovery(config, &checkpoint_, &system_info_, &storage);
377
378 for (int i = 1; i < 10; ++i) {
379 for (int t : types) {
380 std::unique_ptr<Request> request =
381 NewRequest(static_cast<resdb::Request_Type>(t), Request(), i);
382 request->set_seq(i);
383 recovery.AddRequest(nullptr, request.get());
384 }
385 }
386 insert_done.set_value(true);
387 ckpt_future.get();
388 for (int i = 10; i < 20; ++i) {
389 for (int t : types) {
390 std::unique_ptr<Request> request =
391 NewRequest(static_cast<resdb::Request_Type>(t), Request(), i);
392 request->set_seq(i);
393 recovery.AddRequest(nullptr, request.get());
394 }
395 }
396 }
397 std::vector<std::string> log_list = Listlogs(log_path);
398 EXPECT_EQ(log_list.size(), 2);
399 {
400 std::vector<Request> list;
401 SystemInfoData data;
402 Recovery recovery(config, &checkpoint_, &system_info_, &storage);
403 recovery.ReadLogs([&](const SystemInfoData &r_data) { data = r_data; },
404 [&](std::unique_ptr<Context> context,
405 std::unique_ptr<Request> request) {
406 list.push_back(*request);
407 // LOG(ERROR)<<"call back:"<<request->seq();
408 });
409
410 EXPECT_EQ(list.size(), types.size() * 14);
411
412 for (size_t i = 0; i < expected_types.size(); ++i) {
413 EXPECT_EQ(list[i].type(), expected_types[i]);
414 }
415
416 for (int i = 20; i < 30; ++i) {
417 for (int t : types) {
418 std::unique_ptr<Request> request =
419 NewRequest(static_cast<resdb::Request_Type>(t), Request(), i);
420 request->set_seq(i);
421 recovery.AddRequest(nullptr, request.get());
422 }
423 }
424 insert_done2.set_value(true);
425 ckpt_future2.get();
426
427 for (int i = 30; i < 35; ++i) {
428 for (int t : types) {
429 std::unique_ptr<Request> request =
430 NewRequest(static_cast<resdb::Request_Type>(t), Request(), i);
431 request->set_seq(i);
432 recovery.AddRequest(nullptr, request.get());
433 }
434 }
435 }
436
437 {
438 std::vector<Request> list;
439 SystemInfoData data;
440 Recovery recovery(config, &checkpoint_, &system_info_, &storage);
441 recovery.ReadLogs([&](const SystemInfoData &r_data) { data = r_data; },
442 [&](std::unique_ptr<Context> context,
443 std::unique_ptr<Request> request) {
444 list.push_back(*request);
445 // LOG(ERROR)<<"call back:"<<request->seq();
446 });
447
448 EXPECT_EQ(data.view(), 2);
449 EXPECT_EQ(data.primary_id(), 2);
450 EXPECT_EQ(list.size(), types.size() * 9);
451
452 for (size_t i = 0; i < expected_types.size(); ++i) {
453 EXPECT_EQ(list[i].type(), expected_types[i]);
454 }
455 EXPECT_EQ(recovery.GetMinSeq(), 30);
456 EXPECT_EQ(recovery.GetMaxSeq(), 34);
457 }
458}
459
460} // namespace
461
462} // namespace resdb
std::string data
void SetCurrentView(uint64_t)
void SetPrimary(uint32_t id)
SystemInfo system_info_
std::unique_ptr< Storage > storage
std::unique_ptr< Request > NewRequest(Request::Type type, const Request &request, int sender_id)
TEST_F(ResDBTest, TestPBFTService)
MockCheckPoint checkpoint_
std::unique_ptr< ResDBConfig > config_