Skip to content

Commit c6caca8

Browse files
author
wuxianrong
committed
The data backup and recovery functions have been added
1 parent 3e973c3 commit c6caca8

File tree

7 files changed

+247
-11
lines changed

7 files changed

+247
-11
lines changed

.github/workflows/pika.yml

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,7 @@ jobs:
3434
- name: Install Deps
3535
run: |
3636
sudo apt-get update
37-
sudo apt-get install -y gcc-11 g++-11 libssl-dev autoconf libprotobuf-dev protobuf-compiler clang-tidy
38-
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 100
39-
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-11 100
40-
gcc --version
41-
g++ --version
37+
sudo apt-get install -y autoconf libprotobuf-dev protobuf-compiler clang-tidy
4238
4339
- name: Configure CMake
4440
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
@@ -163,7 +159,7 @@ jobs:
163159
- name: Install deps
164160
run: |
165161
dnf update -y
166-
dnf install -y bash cmake wget git autoconf gcc perl-Digest-SHA tcl which tar g++ tar epel-release gcc-c++ libstdc++-devel openssl-devel gcc-toolset-11
162+
dnf install -y bash cmake wget git autoconf gcc perl-Digest-SHA tcl which tar g++ tar epel-release gcc-c++ libstdc++-devel gcc-toolset-13
167163
168164
- name: Set up Go
169165
uses: actions/setup-go@v5
@@ -177,7 +173,7 @@ jobs:
177173

178174
- name: Configure CMake
179175
run: |
180-
source /opt/rh/gcc-toolset-11/enable
176+
source /opt/rh/gcc-toolset-13/enable
181177
cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DUSE_PIKA_TOOLS=ON -DCMAKE_CXX_FLAGS_DEBUG=-fsanitize=address .
182178
183179
- uses: actions/cache@v3

src/praft/include/praft/praft.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "braft/raft.h"
1919
#include "braft/storage.h"
2020
#include "braft/util.h"
21+
#include "braft/file_system_adaptor.h"
2122
#include "pstd/include/pstd_mutex.h"
2223
#include "pstd/include/pstd_status.h"
2324
#include "rocksdb/status.h"
@@ -31,6 +32,7 @@ namespace storage {
3132
class Storage;
3233
}
3334

35+
// Forward declarations
3436
namespace pikiwidb {
3537
class Binlog;
3638
}
@@ -129,6 +131,9 @@ class PikaRaftNode {
129131

130132
// Get cluster status information
131133
void GetStatus(std::string* status_str);
134+
135+
// Trigger a snapshot creation
136+
pstd::Status DoSnapshot(int64_t self_snapshot_index = 0, bool is_sync = true);
132137

133138
braft::Node* GetRaftNode() { return node_.get(); }
134139

@@ -144,6 +149,9 @@ class PikaRaftNode {
144149
std::string raft_log_uri_;
145150
std::string raft_meta_uri_;
146151
std::string raft_snapshot_uri_;
152+
153+
// Snapshot adaptor
154+
scoped_refptr<braft::FileSystemAdaptor> snapshot_adaptor_;
147155
};
148156

149157
// Raft cluster manager
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (c) 2024-present, Qihoo, Inc. All rights reserved.
3+
* This source code is licensed under the BSD-style license found in the
4+
* LICENSE file in the root directory of this source tree. An additional grant
5+
* of patent rights can be found in the PATENTS file in the same directory.
6+
*/
7+
8+
#pragma once
9+
10+
#include <string>
11+
12+
#include "braft/file_system_adaptor.h"
13+
#include "braft/macros.h"
14+
#include "braft/snapshot.h"
15+
16+
#define PRAFT_SNAPSHOT_META_FILE "__raft_snapshot_meta"
17+
#define PRAFT_SNAPSHOT_PATH "snapshot/snapshot_"
18+
#define IS_RDONLY 0x01
19+
20+
// 自定义文件系统适配器,用于Braft快照生成
21+
class PPosixFileSystemAdaptor : public braft::PosixFileSystemAdaptor {
22+
public:
23+
PPosixFileSystemAdaptor() {}
24+
~PPosixFileSystemAdaptor() {}
25+
26+
braft::FileAdaptor* open(const std::string& path, int oflag, const ::google::protobuf::Message* file_meta,
27+
butil::File::Error* e) override;
28+
29+
void AddAllFiles(const std::string& dir, braft::LocalSnapshotMetaTable* snapshot_meta_memtable,
30+
const std::string& base_path);
31+
32+
private:
33+
braft::raft_mutex_t mutex_;
34+
};

src/praft/src/praft.cc

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include "storage/storage.h"
2323
#include "storage/batch.h"
2424
#include "pstd/include/env.h"
25+
#include "praft/psnapshot.h"
26+
#include "binlog.pb.h"
2527

2628
extern std::unique_ptr<PikaConf> g_pika_conf;
2729
extern std::unique_ptr<PikaServer> g_pika_server;
@@ -170,10 +172,14 @@ pstd::Status PikaRaftNode::Init(const std::vector<braft::PeerId>& peers) {
170172
node_options.fsm = state_machine_.get();
171173

172174
// Set election timeout
173-
node_options.election_timeout_ms = g_pika_conf->raft_election_timeout_ms();
175+
node_options.election_timeout_ms = g_pika_conf ? g_pika_conf->raft_election_timeout_ms() : 1000;
174176

175177
// Set snapshot interval
176-
node_options.snapshot_interval_s = g_pika_conf->raft_snapshot_interval_s();
178+
node_options.snapshot_interval_s = g_pika_conf ? g_pika_conf->raft_snapshot_interval_s() : 3600;
179+
180+
// Initialize custom snapshot adaptor
181+
snapshot_adaptor_ = new PPosixFileSystemAdaptor();
182+
node_options.snapshot_file_system_adaptor = &snapshot_adaptor_;
177183

178184
// Create and initialize Raft node
179185
node_ = std::make_unique<braft::Node>(group_id_, peer_id_);
@@ -318,6 +324,26 @@ void PikaRaftNode::GetStatus(std::string* status_str) {
318324
*status_str = oss.str();
319325
}
320326

327+
pstd::Status PikaRaftNode::DoSnapshot(int64_t self_snapshot_index, bool is_sync) {
328+
if (!node_) {
329+
return pstd::Status::Corruption("Raft node not initialized");
330+
}
331+
332+
if (is_sync) {
333+
braft::SynchronizedClosure done;
334+
node_->snapshot(&done);
335+
done.wait();
336+
337+
if (!done.status().ok()) {
338+
return pstd::Status::Corruption("Failed to create snapshot: " + done.status().error_str());
339+
}
340+
} else {
341+
node_->snapshot(nullptr);
342+
}
343+
344+
return pstd::Status::OK();
345+
}
346+
321347
// RaftManager implementation
322348
RaftManager::RaftManager()
323349
: initialized_(false),

src/praft/src/psnapshot.cc

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/*
2+
* Copyright (c) 2024-present, Qihoo, Inc. All rights reserved.
3+
* This source code is licensed under the BSD-style license found in the
4+
* LICENSE file in the root directory of this source tree. An additional grant
5+
* of patent rights can be found in the PATENTS file in the same directory.
6+
*/
7+
8+
#include "praft/psnapshot.h"
9+
10+
#include <dirent.h>
11+
#include <sys/stat.h>
12+
#include <glog/logging.h>
13+
14+
#include "braft/local_file_meta.pb.h"
15+
#include "butil/files/file_path.h"
16+
#include "include/pika_conf.h"
17+
#include "include/pika_server.h"
18+
#include "storage/storage.h"
19+
#include "storage/backupable.h"
20+
21+
extern std::unique_ptr<PikaConf> g_pika_conf;
22+
extern std::unique_ptr<PikaServer> g_pika_server;
23+
24+
static bool IsDirectory(const std::string& path) {
25+
struct stat st;
26+
if (stat(path.c_str(), &st) != 0) {
27+
return false;
28+
}
29+
return S_ISDIR(st.st_mode);
30+
}
31+
32+
static bool IsRegularFile(const std::string& path) {
33+
struct stat st;
34+
if (stat(path.c_str(), &st) != 0) {
35+
return false;
36+
}
37+
return S_ISREG(st.st_mode);
38+
}
39+
40+
static std::string GetRelativePath(const std::string& full_path, const std::string& base_path) {
41+
if (full_path.find(base_path) == 0) {
42+
std::string relative = full_path.substr(base_path.length());
43+
if (!relative.empty() && relative[0] == '/') {
44+
relative = relative.substr(1);
45+
}
46+
return relative;
47+
}
48+
return full_path;
49+
}
50+
51+
braft::FileAdaptor* PPosixFileSystemAdaptor::open(const std::string& path, int oflag,
52+
const ::google::protobuf::Message* file_meta,
53+
butil::File::Error* e) {
54+
if ((oflag & IS_RDONLY) == 0) { // This is a read operation
55+
bool snapshots_exists = false;
56+
std::string snapshot_path;
57+
58+
// parse snapshot path
59+
butil::FilePath parse_snapshot_path(path);
60+
std::vector<std::string> components;
61+
parse_snapshot_path.GetComponents(&components);
62+
for (const auto& component : components) {
63+
snapshot_path += component + "/";
64+
if (component.find("snapshot_") != std::string::npos) {
65+
break;
66+
}
67+
}
68+
69+
// check whether snapshots have been created
70+
std::lock_guard<braft::raft_mutex_t> guard(mutex_);
71+
if (!snapshot_path.empty()) {
72+
DIR* dir = opendir(snapshot_path.c_str());
73+
if (dir) {
74+
struct dirent* entry;
75+
while ((entry = readdir(dir)) != nullptr) {
76+
std::string filename = entry->d_name;
77+
if (filename != "." && filename != ".." && filename.find(PRAFT_SNAPSHOT_META_FILE) == std::string::npos) {
78+
std::string full_path = snapshot_path + "/" + filename;
79+
if (IsRegularFile(full_path) || IsDirectory(full_path)) {
80+
// If the path directory contains files other than raft_snapshot_meta, snapshots have been generated
81+
snapshots_exists = true;
82+
break;
83+
}
84+
}
85+
}
86+
closedir(dir);
87+
}
88+
}
89+
90+
// Snapshot generation
91+
if (!snapshots_exists && !snapshot_path.empty()) {
92+
braft::LocalSnapshotMetaTable snapshot_meta_memtable;
93+
std::string meta_path = snapshot_path + "/" PRAFT_SNAPSHOT_META_FILE;
94+
LOG(INFO) << "start to generate snapshot in path " << snapshot_path;
95+
braft::FileSystemAdaptor* fs = braft::default_file_system();
96+
assert(fs);
97+
snapshot_meta_memtable.load_from_file(fs, meta_path);
98+
99+
// Get storage and create checkpoint
100+
if (g_pika_server) {
101+
auto db = g_pika_server->GetDB("db0");
102+
if (db) {
103+
auto storage = db->storage();
104+
if (storage) {
105+
// Create checkpoint using storage's backup functionality
106+
std::shared_ptr<storage::BackupEngine> backup_engine_ptr;
107+
auto status = storage::BackupEngine::Open(storage.get(), backup_engine_ptr);
108+
if (status.ok() && backup_engine_ptr) {
109+
status = backup_engine_ptr->SetBackupContent();
110+
if (status.ok()) {
111+
status = backup_engine_ptr->CreateNewBackup(snapshot_path);
112+
if (status.ok()) {
113+
LOG(INFO) << "Created checkpoint at " << snapshot_path;
114+
} else {
115+
LOG(ERROR) << "Failed to create checkpoint: " << status.ToString();
116+
}
117+
} else {
118+
LOG(ERROR) << "Failed to set backup content: " << status.ToString();
119+
}
120+
} else {
121+
LOG(ERROR) << "Failed to open backup engine: " << status.ToString();
122+
}
123+
}
124+
}
125+
}
126+
127+
AddAllFiles(snapshot_path, &snapshot_meta_memtable, snapshot_path);
128+
129+
auto rc = snapshot_meta_memtable.save_to_file(fs, meta_path);
130+
if (rc == 0) {
131+
LOG(INFO) << "Succeed to save snapshot in path " << snapshot_path;
132+
} else {
133+
LOG(ERROR) << "Fail to save snapshot in path " << snapshot_path;
134+
}
135+
LOG(INFO) << "generate snapshot completed in path " << snapshot_path;
136+
}
137+
}
138+
139+
return braft::PosixFileSystemAdaptor::open(path, oflag, file_meta, e);
140+
}
141+
142+
void PPosixFileSystemAdaptor::AddAllFiles(const std::string& dir,
143+
braft::LocalSnapshotMetaTable* snapshot_meta_memtable,
144+
const std::string& base_path) {
145+
assert(snapshot_meta_memtable);
146+
DIR* dirp = opendir(dir.c_str());
147+
if (!dirp) {
148+
LOG(WARNING) << "Failed to open directory: " << dir;
149+
return;
150+
}
151+
152+
struct dirent* entry;
153+
while ((entry = readdir(dirp)) != nullptr) {
154+
std::string filename = entry->d_name;
155+
if (filename == "." || filename == "..") {
156+
continue;
157+
}
158+
159+
std::string full_path = dir + "/" + filename;
160+
if (IsDirectory(full_path)) {
161+
LOG(INFO) << "dir_path = " << full_path;
162+
AddAllFiles(full_path, snapshot_meta_memtable, base_path);
163+
} else if (IsRegularFile(full_path)) {
164+
std::string relative_path = GetRelativePath(full_path, base_path);
165+
LOG(INFO) << "file_path = " << relative_path;
166+
braft::LocalFileMeta meta;
167+
if (snapshot_meta_memtable->add_file(relative_path, meta) != 0) {
168+
LOG(WARNING) << "Failed to add file: " << relative_path;
169+
}
170+
}
171+
}
172+
closedir(dirp);
173+
}

src/storage/include/storage/batch.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,3 @@ class BinlogBatch : public Batch {
9292
};
9393

9494
} // namespace storage
95-

src/storage/src/batch.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#include "storage/storage.h"
66
#include "storage/batch.h"
7-
#include "src/redis.h"
7+
#include "src/redis.h"
88
#include "glog/logging.h"
99
#include "binlog.pb.h"
1010
#include <sys/time.h>

0 commit comments

Comments
 (0)