/Users/deen/code/yugabyte-db/src/yb/tserver/remote_bootstrap_snapshots.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) YugaByte, Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
4 | | // in compliance with the License. You may obtain a copy of the License at |
5 | | // |
6 | | // http://www.apache.org/licenses/LICENSE-2.0 |
7 | | // |
8 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
9 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
10 | | // or implied. See the License for the specific language governing permissions and limitations |
11 | | // under the License. |
12 | | // |
13 | | |
14 | | #include "yb/tserver/remote_bootstrap_snapshots.h" |
15 | | |
16 | | #include <unordered_set> |
17 | | |
18 | | #include "yb/fs/fs_manager.h" |
19 | | |
20 | | #include "yb/tablet/tablet_metadata.h" |
21 | | #include "yb/tablet/tablet_peer.h" |
22 | | #include "yb/tablet/tablet_snapshots.h" |
23 | | |
24 | | #include "yb/util/result.h" |
25 | | |
26 | | namespace yb { |
27 | | namespace tserver { |
28 | | |
29 | | namespace { |
30 | | |
31 | | CHECKED_STATUS AddDirToSnapshotFiles( |
32 | | const std::string& dir, const std::string& prefix, const std::string& snapshot_id, |
33 | 11 | google::protobuf::RepeatedPtrField<tablet::SnapshotFilePB>* out) { |
34 | 11 | auto files = VERIFY_RESULT_PREPEND( |
35 | 11 | Env::Default()->GetChildren(dir, ExcludeDots::kTrue), |
36 | 11 | Format("Unable to list directory $0", dir)); |
37 | | |
38 | 64 | for (const string& file : files) { |
39 | 64 | LOG(INFO) << "Adding file " << file << " for snapshot " << snapshot_id; |
40 | 64 | const auto path = JoinPathSegments(dir, file); |
41 | 64 | const auto fname = prefix.empty() ? file : JoinPathSegments(prefix, file)0 ; |
42 | | |
43 | 64 | if (VERIFY_RESULT(Env::Default()->IsDirectory(path))) { |
44 | 0 | RETURN_NOT_OK(AddDirToSnapshotFiles(path, fname, snapshot_id, out)); |
45 | 0 | continue; |
46 | 0 | } |
47 | | |
48 | 64 | const uint64_t file_size = VERIFY_RESULT_PREPEND( |
49 | 64 | Env::Default()->GetFileSize(path), |
50 | 64 | Format("Unable to get file size for file $0", path)); |
51 | | |
52 | 0 | auto snapshot_file_pb = out->Add(); |
53 | 64 | auto& file_pb = *snapshot_file_pb->mutable_file(); |
54 | 64 | snapshot_file_pb->set_snapshot_id(snapshot_id); |
55 | 64 | file_pb.set_name(fname); |
56 | 64 | file_pb.set_size_bytes(file_size); |
57 | 64 | file_pb.set_inode(VERIFY_RESULT(Env::Default()->GetFileINode(path))); |
58 | 64 | } |
59 | | |
60 | 11 | return Status::OK(); |
61 | 11 | } |
62 | | |
63 | | } // namespace |
64 | | |
65 | | RemoteBootstrapSnapshotsComponent::RemoteBootstrapSnapshotsComponent( |
66 | | RemoteBootstrapFileDownloader* downloader, tablet::RaftGroupReplicaSuperBlockPB* new_superblock) |
67 | 2.02k | : downloader_(*downloader), new_superblock_(*new_superblock) {} |
68 | | |
69 | | Status RemoteBootstrapSnapshotsComponent::CreateDirectories( |
70 | 2.02k | const std::string& db_dir, FsManager* fs) { |
71 | 2.02k | const std::string top_snapshots_dir = tablet::TabletSnapshots::SnapshotsDirName(db_dir); |
72 | | // Create the snapshots directory. |
73 | 2.02k | RETURN_NOT_OK_PREPEND(fs->CreateDirIfMissingAndSync(top_snapshots_dir), |
74 | 2.02k | Format("Failed to create & sync top snapshots directory $0", |
75 | 2.02k | top_snapshots_dir)); |
76 | 2.02k | return Status::OK(); |
77 | 2.02k | } |
78 | | |
79 | 2.02k | Status RemoteBootstrapSnapshotsComponent::Download() { |
80 | 2.02k | const auto& kv_store = new_superblock_.kv_store(); |
81 | 2.02k | const string& rocksdb_dir = kv_store.rocksdb_dir(); |
82 | 2.02k | const string top_snapshots_dir = tablet::TabletSnapshots::SnapshotsDirName(rocksdb_dir); |
83 | | // Create the snapshots directory first. |
84 | 2.02k | RETURN_NOT_OK_PREPEND(fs_manager().CreateDirIfMissingAndSync(top_snapshots_dir), |
85 | 2.02k | Format("Failed to create & sync top snapshots directory $0", |
86 | 2.02k | top_snapshots_dir)); |
87 | | |
88 | 2.02k | DataIdPB data_id; |
89 | 2.02k | data_id.set_type(DataIdPB::SNAPSHOT_FILE); |
90 | | // Used to skip snapshot files from a failed download in a previous iteration of the loop. |
91 | 2.02k | std::unordered_set<SnapshotId> failed_snapshot_ids; |
92 | 2.02k | for (auto const& file_pb : kv_store.snapshot_files()) { |
93 | 60 | if (failed_snapshot_ids.find(file_pb.snapshot_id()) != failed_snapshot_ids.end()) { |
94 | 4 | LOG(WARNING) << "Skipping download for file " << file_pb.file().name() |
95 | 4 | << " because it is part of failed snapshot " << file_pb.snapshot_id(); |
96 | 4 | continue; |
97 | 4 | } |
98 | 56 | const string snapshot_dir = JoinPathSegments(top_snapshots_dir, file_pb.snapshot_id()); |
99 | | |
100 | 56 | RETURN_NOT_OK_PREPEND(fs_manager().CreateDirIfMissingAndSync(snapshot_dir), |
101 | 56 | Format("Failed to create & sync snapshot directory $0", snapshot_dir)); |
102 | | |
103 | 56 | const std::string file_path = JoinPathSegments(snapshot_dir, file_pb.file().name()); |
104 | 56 | data_id.set_snapshot_id(file_pb.snapshot_id()); |
105 | 56 | auto s = downloader_.DownloadFile(file_pb.file(), snapshot_dir, &data_id); |
106 | 56 | if (!s.ok()) { |
107 | | // If we fail to fetch a snapshot file, delete the snapshot directory, log the error, |
108 | | // but don't fail the remote bootstrap as snapshot files are not needed for running |
109 | | // the tablet. |
110 | 2 | LOG(ERROR) << "Error downloading snapshot file " << file_path << ": " << s; |
111 | 2 | failed_snapshot_ids.insert(file_pb.snapshot_id()); |
112 | 2 | LOG(INFO) << "Deleting snapshot dir " << snapshot_dir; |
113 | 2 | auto delete_status = Env::Default()->DeleteRecursively(snapshot_dir); |
114 | 2 | if (!delete_status.ok()) { |
115 | 0 | LOG(ERROR) << "Error deleting corrupted snapshot directory " |
116 | 0 | << snapshot_dir << ": " << delete_status; |
117 | 0 | } |
118 | 54 | } else { |
119 | 54 | LOG(INFO) << "Downloaded file " << file_path << " for snapshot " << file_pb.snapshot_id(); |
120 | 54 | } |
121 | 56 | } |
122 | | |
123 | 2.02k | return Status::OK(); |
124 | 2.02k | } |
125 | | |
126 | 2.03k | Status RemoteBootstrapSnapshotsSource::Init() { |
127 | 2.03k | const auto& metadata = tablet_peer_->tablet_metadata(); |
128 | 2.03k | auto* kv_store = tablet_superblock_.mutable_kv_store(); |
129 | 2.03k | kv_store->clear_snapshot_files(); |
130 | | |
131 | | // Add snapshot files to tablet superblock. |
132 | 2.03k | const std::string top_snapshots_dir = tablet::TabletSnapshots::SnapshotsDirName( |
133 | 2.03k | kv_store->rocksdb_dir()); |
134 | 2.03k | std::vector<std::string> snapshots; |
135 | | |
136 | 2.03k | if (metadata->fs_manager()->env()->FileExists(top_snapshots_dir)) { |
137 | 1.66k | snapshots = VERIFY_RESULT_PREPEND( |
138 | 1.66k | metadata->fs_manager()->ListDir(top_snapshots_dir), |
139 | 1.66k | Format("Unable to list directory $0", top_snapshots_dir)); |
140 | 1.66k | } |
141 | | |
142 | 2.03k | for (const string& dir_name : snapshots) { |
143 | 12 | const std::string snapshot_dir = JoinPathSegments(top_snapshots_dir, dir_name); |
144 | 12 | if (tablet::TabletSnapshots::IsTempSnapshotDir(snapshot_dir)) { |
145 | 0 | continue; |
146 | 0 | } |
147 | | |
148 | | // Ignore any non-directories (folder check-sum files, for example). |
149 | 12 | if (!VERIFY_RESULT(Env::Default()->IsDirectory(snapshot_dir))) { |
150 | 1 | continue; |
151 | 1 | } |
152 | | |
153 | 11 | RETURN_NOT_OK(AddDirToSnapshotFiles( |
154 | 11 | snapshot_dir, "", dir_name, kv_store->mutable_snapshot_files())); |
155 | 11 | } |
156 | | |
157 | 2.03k | return Status::OK(); |
158 | 2.03k | } |
159 | | |
160 | | Status RemoteBootstrapSnapshotsSource::GetDataPiece( |
161 | 18 | const DataIdPB& data_id, GetDataPieceInfo* info) { |
162 | 18 | const string snapshots_dir = |
163 | 18 | tablet::TabletSnapshots::SnapshotsDirName(tablet_superblock_.kv_store().rocksdb_dir()); |
164 | 18 | return RemoteBootstrapSession::GetFilePiece( |
165 | 18 | JoinPathSegments(snapshots_dir, data_id.snapshot_id()), data_id.file_name(), |
166 | 18 | tablet_peer_->tablet_metadata()->fs_manager()->env(), info); |
167 | 18 | } |
168 | | |
169 | 18 | Status RemoteBootstrapSnapshotsSource::ValidateDataId(const DataIdPB& data_id) { |
170 | 18 | if (data_id.snapshot_id().empty()) { |
171 | 0 | return STATUS(InvalidArgument, |
172 | 0 | "snapshot id must be specified for type == SNAPSHOT_FILE", |
173 | 0 | data_id.ShortDebugString()); |
174 | 0 | } |
175 | 18 | if (data_id.file_name().empty()) { |
176 | 0 | return STATUS(InvalidArgument, |
177 | 0 | "file name must be specified for type == SNAPSHOT_FILE", |
178 | 0 | data_id.ShortDebugString()); |
179 | 0 | } |
180 | 18 | return Status::OK(); |
181 | 18 | } |
182 | | |
183 | | } // namespace tserver |
184 | | } // namespace yb |