23#include <glog/logging.h>
50 .type() == CertificateKeyInfo::CLIENT) {
64 <<
" dir:" << std::filesystem::path(
file_path_).parent_path();
72 mkdir(std::filesystem::path(
file_path_).parent_path().c_str(), 0777);
74 LOG(INFO) <<
"mkdir fail:" << ret <<
" error:" << strerror(errno);
86 ckpt_thread_ = std::thread(&Recovery::UpdateStableCheckPoint,
this);
105void Recovery::UpdateStableCheckPoint() {
111 LOG(ERROR) <<
"get stable ckpt:" << latest_ckpt;
117 FinishFile(latest_ckpt);
121void Recovery::GetLastFile() {
122 std::string dir = std::filesystem::path(
file_path_).parent_path();
125 for (
const auto& entry : std::filesystem::directory_iterator(dir)) {
126 std::string dir = std::filesystem::path(entry.path()).parent_path();
127 std::string file_name = std::filesystem::path(entry.path()).stem();
128 std::string ext = std::filesystem::path(entry.path()).extension();
129 if (ext !=
".log")
continue;
130 int pos = file_name.rfind(
"_");
131 int64_t ckpt = std::stoll(file_name.substr(pos + 1));
132 int max_seq_pos = file_name.rfind(
"_", pos - 1);
133 int min_seq_pos = file_name.rfind(
"_", max_seq_pos - 1);
134 int time_pos = file_name.rfind(
"_", min_seq_pos - 1);
136 int64_t min_seq = std::stoll(
137 file_name.substr(min_seq_pos + 1, max_seq_pos - min_seq_pos - 1));
140 std::stoll(file_name.substr(time_pos + 1, min_seq_pos - time_pos - 1));
146 LOG(ERROR) <<
"get last path:" << file_name <<
" min:" << min_seq;
156std::string Recovery::GenerateFile(int64_t seq, int64_t min_seq,
158 std::string dir = std::filesystem::path(
file_path_).parent_path();
161 file_name = file_name +
"_" + std::to_string(time) +
"_" +
162 std::to_string(min_seq) +
"_" + std::to_string(max_seq) +
"_" +
165 if (ext ==
"") ext =
"log";
166 return dir +
"/" + file_name +
"." + ext;
169void Recovery::FinishFile(int64_t seq) {
170 std::unique_lock<std::mutex> lk(
mutex_);
183 std::rename(
file_path_.c_str(), new_file_path.c_str());
185 LOG(INFO) <<
"rename:" <<
file_path_ <<
" to:" << new_file_path;
186 std::string next_file_path = GenerateFile(seq, -1, -1);
192void Recovery::SwitchFile(
const std::string& file_path) {
193 std::unique_lock<std::mutex> lk(
mutex_);
199 file_path, 0, 0, [&](
const SystemInfoData&
data) {},
200 [&](std::unique_ptr<Context> context, std::unique_ptr<Request> request) {
203 : std::min(
min_seq_,
static_cast<int64_t
>(request->seq()));
208 LOG(INFO) <<
"switch to file:" << file_path <<
" seq:"
212void Recovery::OpenFile(
const std::string& path) {
216 fd_ = open(path.c_str(), O_CREAT | O_WRONLY, 0666);
218 LOG(ERROR) <<
"open file fail:" << path <<
" error:" << strerror(errno);
221 int pos = lseek(
fd_, 0, SEEK_END);
222 LOG(INFO) <<
"file path:" << path <<
" len:" << pos <<
" fd:" <<
fd_;
228 lseek(
fd_, 0, SEEK_END);
229 LOG(INFO) <<
"open file:" << path <<
" pos:" << lseek(
fd_, 0, SEEK_CUR)
234void Recovery::WriteSystemInfo() {
239 data.set_primary_id(primary_id);
241 std::string data_str;
242 data.SerializeToString(&data_str);
244 AppendData(data_str);
252 switch (request->type()) {
253 case Request::TYPE_PRE_PREPARE:
254 case Request::TYPE_PREPARE:
255 case Request::TYPE_COMMIT:
256 case Request::TYPE_CHECKPOINT:
257 case Request::TYPE_NEWVIEW:
258 return WriteLog(context, request);
264void Recovery::WriteLog(
const Context* context,
const Request* request) {
267 request->SerializeToString(&
data);
272 context->
signature.SerializeToString(&sig);
275 std::unique_lock<std::mutex> lk(
mutex_);
278 : std::min(
min_seq_,
static_cast<int64_t
>(request->seq()));
286void Recovery::AppendData(
const std::string&
data) {
287 size_t len =
data.size();
288 buffer_.append(
reinterpret_cast<const char*
>(&len),
sizeof(len));
292std::vector<std::unique_ptr<Recovery::RecoveryData>> Recovery::ParseData(
293 const std::string&
data) {
294 std::vector<std::unique_ptr<RecoveryData>> request_list;
296 std::vector<std::string> data_list;
298 while (pos <
data.size()) {
300 memcpy(&len,
data.c_str() + pos,
sizeof(len));
303 std::string item =
data.substr(pos, len);
305 data_list.push_back(item);
308 for (
size_t i = 0; i < data_list.size(); i += 2) {
309 std::unique_ptr<RecoveryData> recovery_data =
310 std::make_unique<RecoveryData>();
311 recovery_data->request = std::make_unique<Request>();
312 recovery_data->context = std::make_unique<Context>();
314 if (!recovery_data->request->ParseFromString(data_list[i])) {
315 LOG(ERROR) <<
"Parse from data fail";
319 if (!recovery_data->context->signature.ParseFromString(data_list[i + 1])) {
320 LOG(ERROR) <<
"Parse from data fail";
324 request_list.push_back(std::move(recovery_data));
329std::vector<std::string> Recovery::ParseRawData(
const std::string&
data) {
330 std::vector<std::string> data_list;
332 while (pos <
data.size()) {
334 memcpy(&len,
data.c_str() + pos,
sizeof(len));
337 std::string item =
data.substr(pos, len);
339 data_list.push_back(item);
344void Recovery::MayFlush() {
350void Recovery::Flush() {
356 Write(
reinterpret_cast<const char*
>(&len),
sizeof(len));
357 Write(
reinterpret_cast<const char*
>(
buffer_.c_str()), len);
362void Recovery::Write(
const char*
data,
size_t len) {
365 int write_len = write(
fd_,
data + pos, len);
371bool Recovery::Read(
int fd,
size_t len,
char*
data) {
374 int read_len = read(fd,
data + pos, len);
384std::pair<std::vector<std::pair<int64_t, std::string>>, int64_t>
385Recovery::GetRecoveryFiles() {
386 std::string dir = std::filesystem::path(
file_path_).parent_path();
387 int64_t last_ckpt = 0;
388 for (
const auto& entry : std::filesystem::directory_iterator(dir)) {
389 std::string dir = std::filesystem::path(entry.path()).parent_path();
390 std::string file_name = std::filesystem::path(entry.path()).stem();
391 std::string ext = std::filesystem::path(entry.path()).extension();
392 if (ext !=
".log")
continue;
393 int pos = file_name.rfind(
"_");
394 int64_t ckpt = std::stoll(file_name.substr(pos + 1));
395 if (ckpt > last_ckpt) {
399 std::vector<std::pair<int64_t, std::string>> list;
401 std::vector<std::pair<int64_t, std::string>> e_list;
403 for (
const auto& entry : std::filesystem::directory_iterator(dir)) {
404 std::string dir = std::filesystem::path(entry.path()).parent_path();
405 std::string file_name = std::filesystem::path(entry.path()).stem();
406 std::string ext = std::filesystem::path(entry.path()).extension();
407 if (ext !=
".log")
continue;
408 int pos = file_name.rfind(
"_");
410 int max_seq_pos = file_name.rfind(
"_", pos - 1);
412 std::stoll(file_name.substr(max_seq_pos + 1, pos - max_seq_pos - 1));
414 int min_seq_pos = file_name.rfind(
"_", max_seq_pos - 1);
415 int64_t min_seq = std::stoll(
416 file_name.substr(min_seq_pos + 1, max_seq_pos - min_seq_pos - 1));
418 int time_pos = file_name.rfind(
"_", min_seq_pos - 1);
420 std::stoll(file_name.substr(time_pos + 1, min_seq_pos - time_pos - 1));
423 e_list.push_back(std::make_pair(time, entry.path()));
424 }
else if ((min_seq <= last_ckpt && max_seq >= last_ckpt)) {
425 list.push_back(std::make_pair(time, entry.path()));
429 sort(e_list.begin(), e_list.end());
430 list.push_back(e_list.back());
432 sort(list.begin(), list.end());
433 return std::make_pair(list, last_ckpt);
437 std::function<
void(
const SystemInfoData&
data)> system_callback,
438 std::function<
void(std::unique_ptr<Context> context,
439 std::unique_ptr<Request> request)>
444 std::unique_lock<std::mutex> lk(
mutex_);
445 auto recovery_files_pair = GetRecoveryFiles();
446 int64_t ckpt = recovery_files_pair.second;
448 for (
auto path : recovery_files_pair.first) {
449 ReadLogsFromFiles(path.second, ckpt, idx++, system_callback, call_back);
453void Recovery::ReadLogsFromFiles(
454 const std::string& path, int64_t ckpt,
int file_idx,
455 std::function<
void(
const SystemInfoData&
data)> system_callback,
456 std::function<
void(std::unique_ptr<Context> context,
457 std::unique_ptr<Request> request)>
459 int fd = open(path.c_str(), O_CREAT | O_RDONLY, 0666);
461 LOG(ERROR) <<
" open file fail:" << path;
463 LOG(INFO) <<
"read logs:" << path <<
" pos:" << lseek(fd, 0, SEEK_CUR);
467 Read(fd,
sizeof(data_len),
reinterpret_cast<char*
>(&data_len));
470 char* buf =
new char[data_len];
471 if (!Read(fd, data_len, buf)) {
472 LOG(ERROR) <<
"Read system info fail";
475 data = std::string(buf, data_len);
477 std::vector<std::string> data_list = ParseRawData(
data);
480 if (data_list.empty() || !info.ParseFromString(data_list[0])) {
481 LOG(ERROR) <<
"parse info fail:" <<
data.size();
484 LOG(INFO) <<
"read system info:" << info.DebugString();
486 system_callback(info);
490 std::vector<std::unique_ptr<RecoveryData>> request_list;
492 while (Read(fd,
sizeof(data_len),
reinterpret_cast<char*
>(&data_len))) {
494 char* buf =
new char[data_len];
495 if (!Read(fd, data_len, buf)) {
496 LOG(ERROR) <<
"Read data log fail";
499 data = std::string(buf, data_len);
502 std::vector<std::unique_ptr<RecoveryData>> list = ParseData(
data);
503 if (list.size() == 0) {
504 request_list.clear();
507 for (
auto& l : list) {
508 request_list.push_back(std::move(l));
511 if (request_list.size() == 0) {
514 for (std::unique_ptr<RecoveryData>& recovery_data : request_list) {
515 if (ckpt < recovery_data->request->seq()) {
516 recovery_data->request->set_is_recovery(
true);
517 call_back(std::move(recovery_data->context),
518 std::move(recovery_data->request));
522 LOG(INFO) <<
"read log from files:" << path <<
" done";
virtual uint64_t GetStableCheckpoint()=0
std::atomic< bool > stop_
SystemInfo * system_info_
std::string base_file_path_
void ReadLogs(std::function< void(const SystemInfoData &data)> system_callback, std::function< void(std::unique_ptr< Context > context, std::unique_ptr< Request > request)> call_back)
virtual void AddRequest(const Context *context, const Request *request)
int recovery_ckpt_time_s_
Recovery(const ResDBConfig &config, CheckPoint *checkpoint, SystemInfo *system_info, Storage *storage)
ResConfigData GetConfigData() const
CertificateInfo GetPublicKeyCertificateInfo() const
uint32_t GetPrimaryId() const
uint64_t GetCurrentView() const
std::unique_ptr< Storage > storage
uint64_t GetCurrentTime()
MockCheckPoint checkpoint_
std::unique_ptr< ResDBConfig > config_