/Users/deen/code/yugabyte-db/src/yb/fs/fs_manager.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // The following only applies to changes made to this file as part of YugaByte development. |
19 | | // |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | // |
22 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
23 | | // in compliance with the License. You may obtain a copy of the License at |
24 | | // |
25 | | // http://www.apache.org/licenses/LICENSE-2.0 |
26 | | // |
27 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
28 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
29 | | // or implied. See the License for the specific language governing permissions and limitations |
30 | | // under the License. |
31 | | // |
32 | | |
33 | | #include "yb/fs/fs_manager.h" |
34 | | |
35 | | #include <map> |
36 | | #include <set> |
37 | | #include <unordered_set> |
38 | | |
39 | | #include <boost/algorithm/string/predicate.hpp> |
40 | | #include <boost/preprocessor/cat.hpp> |
41 | | #include <glog/logging.h> |
42 | | #include <glog/stl_logging.h> |
43 | | #include <google/protobuf/message.h> |
44 | | |
45 | | #include "yb/fs/fs.pb.h" |
46 | | |
47 | | #include "yb/gutil/map-util.h" |
48 | | #include "yb/gutil/strings/join.h" |
49 | | #include "yb/gutil/strings/numbers.h" |
50 | | #include "yb/gutil/strings/split.h" |
51 | | #include "yb/gutil/strings/strip.h" |
52 | | #include "yb/gutil/strings/util.h" |
53 | | #include "yb/gutil/walltime.h" |
54 | | |
55 | | #include "yb/util/env_util.h" |
56 | | #include "yb/util/flag_tags.h" |
57 | | #include "yb/util/format.h" |
58 | | #include "yb/util/metric_entity.h" |
59 | | #include "yb/util/net/net_util.h" |
60 | | #include "yb/util/oid_generator.h" |
61 | | #include "yb/util/path_util.h" |
62 | | #include "yb/util/pb_util.h" |
63 | | #include "yb/util/result.h" |
64 | | |
65 | | DEFINE_bool(enable_data_block_fsync, true, |
66 | | "Whether to enable fsync() of data blocks, metadata, and their parent directories. " |
67 | | "Disabling this flag may cause data loss in the event of a system crash."); |
68 | | TAG_FLAG(enable_data_block_fsync, unsafe); |
69 | | |
70 | | DECLARE_string(fs_data_dirs); |
71 | | |
72 | | DEFINE_string(fs_wal_dirs, "", |
73 | | "Comma-separated list of directories for write-ahead logs. This is an optional " |
74 | | "argument. If this is not specified, fs_data_dirs is used for write-ahead logs " |
75 | | "also and that's a reasonable default for most use cases."); |
76 | | TAG_FLAG(fs_wal_dirs, stable); |
77 | | |
78 | | DEFINE_string(instance_uuid_override, "", |
79 | | "When creating local instance metadata (for master or tserver) in an empty data " |
80 | | "directory, use this UUID instead of randomly-generated one. Can be used to replace " |
81 | | "a node that had its disk wiped in some scenarios."); |
82 | | |
83 | | DEFINE_test_flag(bool, simulate_fs_create_failure, false, |
84 | | "Simulate failure during initial creation of fs during the first time " |
85 | | "process creation."); |
86 | | |
87 | | using google::protobuf::Message; |
88 | | using yb::env_util::ScopedFileDeleter; |
89 | | using std::map; |
90 | | using std::unordered_set; |
91 | | using strings::Substitute; |
92 | | |
93 | | namespace yb { |
94 | | // ========================================================================== |
95 | | // FS Paths |
96 | | // ========================================================================== |
97 | | const char *FsManager::kWalDirName = "wals"; |
98 | | const char *FsManager::kWalFileNamePrefix = "wal"; |
99 | | const char *FsManager::kWalsRecoveryDirSuffix = ".recovery"; |
100 | | const char *FsManager::kRocksDBDirName = "rocksdb"; |
101 | | const char *FsManager::kDataDirName = "data"; |
102 | | |
103 | | namespace { |
104 | | |
105 | | static const char kRaftGroupMetadataDirName[] = "tablet-meta"; |
106 | | static const char kInstanceMetadataFileName[] = "instance"; |
107 | | static const char kFsLockFileName[] = "fs-lock"; |
108 | | static const char kConsensusMetadataDirName[] = "consensus-meta"; |
109 | | static const char kLogsDirName[] = "logs"; |
110 | | static const char kTmpInfix[] = ".tmp"; |
111 | | static const char kCheckFileTemplate[] = "check.XXXXXX"; |
112 | | static const char kMetricDescription[] = "Tablet Server isn't able to read/write on drive."; |
113 | | |
114 | 187k | std::string DataDir(const std::string& root, const std::string& server_type) { |
115 | 187k | return JoinPathSegments(GetServerTypeDataPath(root, server_type), FsManager::kDataDirName); |
116 | 187k | } |
117 | | |
118 | 169k | std::string WalDir(const std::string& root, const std::string& server_type) { |
119 | 169k | return JoinPathSegments(GetServerTypeDataPath(root, server_type), FsManager::kWalDirName); |
120 | 169k | } |
121 | | |
122 | | } // namespace |
123 | | |
124 | | FsManagerOpts::FsManagerOpts() |
125 | 58.9k | : read_only(false) { |
126 | 58.9k | if (FLAGS_fs_wal_dirs.empty() && !FLAGS_fs_data_dirs.empty()13.8k ) { |
127 | | // It is sufficient if user sets the data dirs. By default we use the same |
128 | | // directories for WALs as well. |
129 | 8.42k | FLAGS_fs_wal_dirs = FLAGS_fs_data_dirs; |
130 | 8.42k | } |
131 | 58.9k | wal_paths = strings::Split(FLAGS_fs_wal_dirs, ",", strings::SkipEmpty()); |
132 | 58.9k | data_paths = strings::Split(FLAGS_fs_data_dirs, ",", strings::SkipEmpty()); |
133 | 58.9k | } |
134 | | |
135 | 54.3k | FsManagerOpts::~FsManagerOpts() = default; |
136 | 70.5k | FsManagerOpts::FsManagerOpts(const FsManagerOpts&) = default; |
137 | 3 | FsManagerOpts& FsManagerOpts::operator=(const FsManagerOpts&) = default; |
138 | | |
139 | | FsManager::FsManager(Env* env, const string& root_path, const std::string& server_type) |
140 | | : env_(DCHECK_NOTNULL(env)), |
141 | | read_only_(false), |
142 | | wal_fs_roots_({ root_path }), |
143 | | data_fs_roots_({ root_path }), |
144 | | server_type_(server_type), |
145 | | metric_entity_(nullptr), |
146 | 155 | initted_(false) { |
147 | 155 | } |
148 | | |
149 | | FsManager::FsManager(Env* env, |
150 | | const FsManagerOpts& opts) |
151 | | : env_(DCHECK_NOTNULL(env)), |
152 | | read_only_(opts.read_only), |
153 | | wal_fs_roots_(opts.wal_paths), |
154 | | data_fs_roots_(opts.data_paths), |
155 | | server_type_(opts.server_type), |
156 | | metric_entity_(opts.metric_entity), |
157 | | parent_mem_tracker_(opts.parent_mem_tracker), |
158 | 26.4k | initted_(false) { |
159 | 26.4k | } |
160 | | |
161 | 453 | FsManager::~FsManager() { |
162 | 453 | } |
163 | | |
164 | 61.6k | Status FsManager::Init() { |
165 | 61.6k | if (initted_) { |
166 | 35.0k | return Status::OK(); |
167 | 35.0k | } |
168 | | |
169 | | // The wal root must be set. |
170 | 26.6k | if (data_fs_roots_.empty()) { |
171 | 2 | return STATUS(IOError, "List of data directories (fs_data_dirs) not provided"); |
172 | 2 | } |
173 | | |
174 | | // Deduplicate all of the roots. |
175 | 26.6k | set<string> all_roots; |
176 | 26.7k | for (const string& wal_fs_root : wal_fs_roots_) { |
177 | 26.7k | all_roots.insert(wal_fs_root); |
178 | 26.7k | } |
179 | 26.7k | for (const string& data_fs_root : data_fs_roots_) { |
180 | 26.7k | all_roots.insert(data_fs_root); |
181 | 26.7k | } |
182 | | |
183 | | // Build a map of original root --> canonicalized root, sanitizing each |
184 | | // root a bit as we go. |
185 | 26.6k | typedef map<string, string> RootMap; |
186 | 26.6k | RootMap canonicalized_roots; |
187 | 26.7k | for (const string& root : all_roots) { |
188 | 26.7k | if (root.empty()) { |
189 | 1 | return STATUS(IOError, "Empty string provided for filesystem root"); |
190 | 1 | } |
191 | 26.7k | if (root[0] != '/') { |
192 | 1 | return STATUS(IOError, |
193 | 1 | Substitute("Relative path $0 provided for filesystem root", root)); |
194 | 1 | } |
195 | 26.7k | { |
196 | 26.7k | string root_copy = root; |
197 | 26.7k | StripWhiteSpace(&root_copy); |
198 | 26.7k | if (root != root_copy) { |
199 | 1 | return STATUS(IOError, |
200 | 1 | Substitute("Filesystem root $0 contains illegal whitespace", root)); |
201 | 1 | } |
202 | 26.7k | } |
203 | | |
204 | | // Strip the basename when canonicalizing, as it may not exist. The |
205 | | // dirname, however, must exist. |
206 | 26.7k | string canonicalized; |
207 | 26.7k | Status s = env_->Canonicalize(DirName(root), &canonicalized); |
208 | 26.7k | if (!s.ok()) { |
209 | 0 | return STATUS( |
210 | 0 | InvalidArgument, strings::Substitute( |
211 | 0 | "Cannot create directory for YB data, please check the --fs_data_dirs parameter " |
212 | 0 | "(Passed: $0). Path does not exist: $1\nDetails: $2", |
213 | 0 | FLAGS_fs_data_dirs, root, s.ToString())); |
214 | 0 | } |
215 | 26.7k | canonicalized = JoinPathSegments(canonicalized, BaseName(root)); |
216 | 26.7k | InsertOrDie(&canonicalized_roots, root, canonicalized); |
217 | 26.7k | } |
218 | | |
219 | | // All done, use the map to set the canonicalized state. |
220 | 26.7k | for (const auto& wal_fs_root : wal_fs_roots_)26.5k { |
221 | 26.7k | canonicalized_wal_fs_roots_.insert(FindOrDie(canonicalized_roots, wal_fs_root)); |
222 | 26.7k | } |
223 | 26.5k | if (!data_fs_roots_.empty()) { |
224 | 26.5k | canonicalized_metadata_fs_root_ = FindOrDie(canonicalized_roots, data_fs_roots_[0]); |
225 | 26.7k | for (const string& data_fs_root : data_fs_roots_) { |
226 | 26.7k | canonicalized_data_fs_roots_.insert(FindOrDie(canonicalized_roots, data_fs_root)); |
227 | 26.7k | } |
228 | 26.5k | } else { |
229 | 1 | LOG(FATAL) << "Data directories (fs_data_dirs) must be specified"; |
230 | 1 | } |
231 | | |
232 | 26.7k | for (const RootMap::value_type& e : canonicalized_roots) { |
233 | 26.7k | canonicalized_all_fs_roots_.insert(e.second); |
234 | 26.7k | } |
235 | | |
236 | 26.5k | if (VLOG_IS_ON(1)) { |
237 | 0 | VLOG(1) << "WAL roots: " << canonicalized_wal_fs_roots_; |
238 | 0 | VLOG(1) << "Metadata root: " << canonicalized_metadata_fs_root_; |
239 | 0 | VLOG(1) << "Data roots: " << canonicalized_data_fs_roots_; |
240 | 0 | VLOG(1) << "All roots: " << canonicalized_all_fs_roots_; |
241 | 0 | } |
242 | | |
243 | 26.5k | initted_ = true; |
244 | 26.5k | return Status::OK(); |
245 | 26.6k | } |
246 | | |
247 | 43.8k | Status FsManager::CheckAndOpenFileSystemRoots() { |
248 | 43.8k | RETURN_NOT_OK(Init()); |
249 | | |
250 | 43.8k | if (HasAnyLockFiles()) { |
251 | 0 | return STATUS(Corruption, "Lock file is present, filesystem may be in inconsistent state"); |
252 | 0 | } |
253 | | |
254 | 43.8k | bool create_roots = false; |
255 | 44.0k | for (const string& root : canonicalized_all_fs_roots_) { |
256 | 44.0k | auto pb = std::make_unique<InstanceMetadataPB>(); |
257 | 44.0k | auto read_result = pb_util::ReadPBContainerFromPath(env_, GetInstanceMetadataPath(root), |
258 | 44.0k | pb.get()); |
259 | 44.0k | auto write_result = CheckWrite(root); |
260 | 44.0k | if ((!read_result.ok() && !read_result.IsNotFound()17.3k ) || !write_result.ok()44.0k ) { |
261 | 2 | LOG(WARNING) << "Path: " << root << " Read Result: "<< read_result |
262 | 2 | << " Write Result: " << write_result; |
263 | 2 | canonicalized_wal_fs_roots_.erase(root); |
264 | 2 | canonicalized_data_fs_roots_.erase(root); |
265 | 2 | CreateAndSetFaultDriveMetric(root); |
266 | 2 | continue; |
267 | 2 | } |
268 | 44.0k | if (read_result.IsNotFound()) { |
269 | 17.3k | create_roots = true; |
270 | 17.3k | continue; |
271 | 17.3k | } |
272 | 26.7k | if (!metadata_) { |
273 | 26.5k | metadata_.reset(pb.release()); |
274 | 26.5k | } else if (177 pb->uuid() != metadata_->uuid()177 ) { |
275 | 0 | return STATUS(Corruption, Substitute( |
276 | 0 | "Mismatched UUIDs across filesystem roots: $0 vs. $1", |
277 | 0 | metadata_->uuid(), pb->uuid())); |
278 | 0 | } |
279 | 26.7k | } |
280 | 43.8k | if (!metadata_) { |
281 | 17.2k | return STATUS(NotFound, "Metadata wasn't found"); |
282 | 17.2k | } |
283 | 26.5k | if (create_roots) { |
284 | 1 | RETURN_NOT_OK(CreateFileSystemRoots(/* create_metadata_dir = */ false, |
285 | 1 | *metadata_.get())); |
286 | 1 | } |
287 | | |
288 | 26.5k | LOG(INFO) << "Opened local filesystem: " << JoinStrings(canonicalized_all_fs_roots_, ",") |
289 | 26.5k | << std::endl << metadata_->DebugString(); |
290 | 26.5k | return Status::OK(); |
291 | 26.5k | } |
292 | | |
293 | 61.0k | bool FsManager::HasAnyLockFiles() { |
294 | 61.3k | for (const string& root : canonicalized_all_fs_roots_) { |
295 | 61.3k | if (Exists(GetFsLockFilePath(root))) { |
296 | 0 | LOG(INFO) << "Found lock file in dir " << root; |
297 | 0 | return true; |
298 | 0 | } |
299 | 61.3k | } |
300 | | |
301 | 61.0k | return false; |
302 | 61.0k | } |
303 | | |
304 | 18.2k | Status FsManager::DeleteLockFiles() { |
305 | 18.2k | CHECK(!read_only_); |
306 | 18.2k | vector<string> removal_list; |
307 | 18.3k | for (const string& root : canonicalized_all_fs_roots_) { |
308 | 18.3k | std::string lock_file_path = GetFsLockFilePath(root); |
309 | 18.3k | if (Exists(lock_file_path)) { |
310 | 0 | removal_list.push_back(lock_file_path); |
311 | 0 | } |
312 | 18.3k | } |
313 | | |
314 | 18.2k | for (const string& target : removal_list) { |
315 | 0 | RETURN_NOT_OK_PREPEND(env_->DeleteFile(target), "Lock file delete failed"); |
316 | 0 | } |
317 | | |
318 | 18.2k | return Status::OK(); |
319 | 18.2k | } |
320 | | |
321 | 438 | Status FsManager::DeleteFileSystemLayout(ShouldDeleteLogs also_delete_logs) { |
322 | 438 | CHECK(!read_only_); |
323 | 438 | set<string> removal_set; |
324 | 438 | if (also_delete_logs) { |
325 | 401 | removal_set = canonicalized_all_fs_roots_; |
326 | 401 | } else { |
327 | 37 | auto removal_list = GetWalRootDirs(); |
328 | 37 | removal_list.push_back(GetRaftGroupMetadataDir()); |
329 | 37 | removal_list.push_back(GetConsensusMetadataDir()); |
330 | 37 | for (const string& root : canonicalized_all_fs_roots_) { |
331 | 37 | removal_list.push_back(GetInstanceMetadataPath(root)); |
332 | 37 | } |
333 | 37 | auto data_dirs = GetDataRootDirs(); |
334 | 37 | removal_list.insert(removal_list.begin(), data_dirs.begin(), data_dirs.end()); |
335 | 37 | removal_set.insert(removal_list.begin(), removal_list.end()); |
336 | 37 | } |
337 | | |
338 | 585 | for (const string& target : removal_set) { |
339 | 585 | bool is_dir = false; |
340 | 585 | Status s = env_->IsDirectory(target, &is_dir); |
341 | 585 | if (!s.ok()) { |
342 | 0 | LOG(WARNING) << "Error: " << s.ToString() << " when checking if " << target |
343 | 0 | << " is a directory."; |
344 | 0 | continue; |
345 | 0 | } |
346 | 585 | if (is_dir) { |
347 | 548 | RETURN_NOT_OK(env_->DeleteRecursively(target)); |
348 | 548 | } else { |
349 | 37 | RETURN_NOT_OK(env_->DeleteFile(target)); |
350 | 37 | } |
351 | 585 | } |
352 | | |
353 | 438 | RETURN_NOT_OK(DeleteLockFiles()); |
354 | | |
355 | 438 | return Status::OK(); |
356 | 438 | } |
357 | | |
358 | 17.8k | Status FsManager::CreateInitialFileSystemLayout(bool delete_fs_if_lock_found) { |
359 | 17.8k | CHECK(!read_only_); |
360 | | |
361 | 17.8k | RETURN_NOT_OK(Init()); |
362 | | |
363 | 17.8k | bool fs_cleaned = false; |
364 | | |
365 | | // If lock file is present, delete existing filesystem layout before continuing. |
366 | 17.8k | if (delete_fs_if_lock_found && HasAnyLockFiles()17.2k ) { |
367 | 0 | RETURN_NOT_OK(DeleteFileSystemLayout()); |
368 | 0 | fs_cleaned = true; |
369 | 0 | } |
370 | | |
371 | | // It's OK if a root already exists as long as there's nothing in it. |
372 | 17.9k | for (const string& root : canonicalized_all_fs_roots_)17.8k { |
373 | 17.9k | if (!env_->FileExists(GetServerTypeDataPath(root, server_type_))) { |
374 | | // We'll create the directory below. |
375 | 15.9k | continue; |
376 | 15.9k | } |
377 | 1.94k | bool is_empty; |
378 | 1.94k | RETURN_NOT_OK_PREPEND(IsDirectoryEmpty(GetServerTypeDataPath(root, server_type_), &is_empty), |
379 | 1.94k | "Unable to check if FSManager root is empty"); |
380 | 1.94k | if (!is_empty) { |
381 | 1 | return STATUS(AlreadyPresent, "FSManager root is not empty", root); |
382 | 1 | } |
383 | 1.94k | } |
384 | | |
385 | | // All roots are either empty or non-existent. Create missing roots and all |
386 | | // subdirectories. |
387 | | // |
388 | | |
389 | 17.8k | InstanceMetadataPB metadata; |
390 | 17.8k | CreateInstanceMetadata(&metadata); |
391 | 17.8k | RETURN_NOT_OK(CreateFileSystemRoots(/* create_metadata_dir = */ true, |
392 | 17.8k | metadata, |
393 | 17.8k | /* create_lock = */ fs_cleaned)); |
394 | | |
395 | 17.8k | if (FLAGS_TEST_simulate_fs_create_failure) { |
396 | 1 | return STATUS(IOError, "Simulated fs creation error"); |
397 | 1 | } |
398 | 17.8k | RETURN_NOT_OK(DeleteLockFiles()); |
399 | 17.8k | return Status::OK(); |
400 | 17.8k | } |
401 | | |
402 | | Status FsManager::CreateFileSystemRoots(bool create_metadata_dir, |
403 | | const InstanceMetadataPB& metadata, |
404 | 17.8k | bool create_lock) { |
405 | | // In the event of failure, delete everything we created. |
406 | 17.8k | std::deque<ScopedFileDeleter> delete_on_failure; |
407 | 17.8k | unordered_set<string> to_sync; |
408 | | |
409 | 17.8k | std::set<std::string> roots = canonicalized_data_fs_roots_; |
410 | 17.8k | roots.insert(canonicalized_wal_fs_roots_.begin(), canonicalized_wal_fs_roots_.end()); |
411 | | |
412 | | // All roots are either empty or non-existent. Create missing roots and all |
413 | | // subdirectories. |
414 | 17.9k | for (const auto& root : roots) { |
415 | 17.9k | bool created; |
416 | 17.9k | std::string out_dir; |
417 | 17.9k | RETURN_NOT_OK(SetupRootDir(env_, root, server_type_, &out_dir, &created)); |
418 | 17.9k | if (created) { |
419 | 15.9k | delete_on_failure.emplace_front(env_, out_dir); |
420 | 15.9k | to_sync.insert(DirName(out_dir)); |
421 | 15.9k | } |
422 | | |
423 | 17.9k | const string lock_file_path = GetFsLockFilePath(root); |
424 | 17.9k | if (create_lock && !Exists(lock_file_path)0 ) { |
425 | 0 | std::unique_ptr<WritableFile> file; |
426 | 0 | RETURN_NOT_OK_PREPEND(env_->NewWritableFile(lock_file_path, &file), |
427 | 0 | "Unable to create lock file."); |
428 | | // Do not delete lock file on error. It is used to detect failed initial create. |
429 | 0 | } |
430 | 17.9k | const string instance_metadata_path = GetInstanceMetadataPath(root); |
431 | 17.9k | if (env_->FileExists(instance_metadata_path)) { |
432 | 2 | continue; |
433 | 2 | } |
434 | 17.9k | RETURN_NOT_OK_PREPEND(WriteInstanceMetadata(metadata, instance_metadata_path), |
435 | 17.9k | "Unable to write instance metadata"); |
436 | 17.9k | delete_on_failure.emplace_front(env_, instance_metadata_path); |
437 | 17.9k | } |
438 | | |
439 | 89.3k | for (const auto& dir : GetAncillaryDirs(create_metadata_dir))17.8k { |
440 | 89.3k | bool created; |
441 | 89.3k | RETURN_NOT_OK_PREPEND(CreateDirIfMissing(dir, &created), |
442 | 89.3k | Substitute("Unable to create directory $0", dir)); |
443 | 89.3k | if (created) { |
444 | 89.3k | delete_on_failure.emplace_front(env_, dir); |
445 | 89.3k | to_sync.insert(DirName(dir)); |
446 | 89.3k | } |
447 | 89.3k | } |
448 | | |
449 | | // Ensure newly created directories are synchronized to disk. |
450 | 17.8k | if (FLAGS_enable_data_block_fsync) { |
451 | 50.6k | for (const string& dir : to_sync) { |
452 | 50.6k | RETURN_NOT_OK_PREPEND(env_->SyncDir(dir), |
453 | 50.6k | Substitute("Unable to synchronize directory $0", dir)); |
454 | 50.6k | } |
455 | 17.4k | } |
456 | | |
457 | | // Success: don't delete any files. |
458 | 123k | for (auto& deleter : delete_on_failure)17.8k { |
459 | 123k | deleter.Cancel(); |
460 | 123k | } |
461 | | |
462 | 17.8k | return Status::OK(); |
463 | 17.8k | } |
464 | | |
465 | 17.8k | std::set<std::string> FsManager::GetAncillaryDirs(bool add_metadata_dirs) const { |
466 | 17.8k | std::set<std::string> ancillary_dirs; |
467 | 17.8k | if (add_metadata_dirs) { |
468 | 17.8k | ancillary_dirs.emplace(GetRaftGroupMetadataDir()); |
469 | 17.8k | ancillary_dirs.emplace(GetConsensusMetadataDir()); |
470 | 17.8k | } |
471 | 17.8k | for (const auto& wal_fs_root : canonicalized_wal_fs_roots_) { |
472 | 17.8k | ancillary_dirs.emplace(WalDir(wal_fs_root, server_type_)); |
473 | 17.8k | } |
474 | 17.9k | for (const string& data_fs_root : canonicalized_data_fs_roots_) { |
475 | 17.9k | const string data_dir = DataDir(data_fs_root, server_type_); |
476 | 17.9k | ancillary_dirs.emplace(data_dir); |
477 | 17.9k | ancillary_dirs.emplace(JoinPathSegments(data_dir, kRocksDBDirName)); |
478 | 17.9k | } |
479 | 17.8k | return ancillary_dirs; |
480 | 17.8k | } |
481 | | |
482 | 17.8k | void FsManager::CreateInstanceMetadata(InstanceMetadataPB* metadata) { |
483 | 17.8k | if (!FLAGS_instance_uuid_override.empty()) { |
484 | 0 | metadata->set_uuid(FLAGS_instance_uuid_override); |
485 | 17.8k | } else { |
486 | 17.8k | metadata->set_uuid(GenerateObjectId()); |
487 | 17.8k | } |
488 | | |
489 | 17.8k | string time_str; |
490 | 17.8k | StringAppendStrftime(&time_str, "%Y-%m-%d %H:%M:%S", time(nullptr), false); |
491 | 17.8k | string hostname; |
492 | 17.8k | if (!GetHostname(&hostname).ok()) { |
493 | 0 | hostname = "<unknown host>"; |
494 | 0 | } |
495 | 17.8k | metadata->set_format_stamp(Substitute("Formatted at $0 on $1", time_str, hostname)); |
496 | 17.8k | } |
497 | | |
498 | | Status FsManager::WriteInstanceMetadata(const InstanceMetadataPB& metadata, |
499 | 17.9k | const string& path) { |
500 | | // The instance metadata is written effectively once per TS, so the |
501 | | // durability cost is negligible. |
502 | 17.9k | RETURN_NOT_OK(pb_util::WritePBContainerToPath(env_, path, |
503 | 17.9k | metadata, |
504 | 17.9k | pb_util::NO_OVERWRITE, |
505 | 17.9k | pb_util::SYNC)); |
506 | 17.9k | LOG(INFO) << "Generated new instance metadata in path " << path << ":\n" |
507 | 17.9k | << metadata.DebugString(); |
508 | 17.9k | return Status::OK(); |
509 | 17.9k | } |
510 | | |
511 | 1.94k | Status FsManager::IsDirectoryEmpty(const string& path, bool* is_empty) { |
512 | 1.94k | vector<string> children; |
513 | 1.94k | RETURN_NOT_OK(env_->GetChildren(path, &children)); |
514 | 5.82k | for (const string& child : children)1.94k { |
515 | | // Excluding logs directory from the list of things to check for. |
516 | 5.82k | if (child == "." || child == ".."3.88k || child == kLogsDirName1.94k ) { |
517 | 5.81k | continue; |
518 | 5.81k | } else { |
519 | 1 | LOG(INFO) << "Found data " << child; |
520 | 1 | *is_empty = false; |
521 | 1 | return Status::OK(); |
522 | 1 | } |
523 | 5.82k | } |
524 | 1.93k | *is_empty = true; |
525 | 1.93k | return Status::OK(); |
526 | 1.94k | } |
527 | | |
528 | 44.0k | Status FsManager::CheckWrite(const std::string& root) { |
529 | 44.0k | RETURN_NOT_OK(env_->CreateDirs(root)); |
530 | 44.0k | const string tmp_file_temp = JoinPathSegments(root, kCheckFileTemplate); |
531 | 44.0k | string tmp_file; |
532 | 44.0k | std::unique_ptr<WritableFile> file; |
533 | 44.0k | Status write_result = env_->NewTempWritableFile(WritableFileOptions(), |
534 | 44.0k | tmp_file_temp, |
535 | 44.0k | &tmp_file, |
536 | 44.0k | &file); |
537 | 44.0k | if (!write_result.ok()) { |
538 | 2 | return write_result; |
539 | 2 | } |
540 | 44.0k | ScopedFileDeleter deleter(env_, tmp_file); |
541 | 44.0k | write_result = file->Append(Slice("0123456789")); |
542 | 44.0k | if (!write_result.ok()) { |
543 | 0 | return write_result; |
544 | 0 | } |
545 | 44.0k | write_result = file->Close(); |
546 | 44.0k | if (!write_result.ok()) { |
547 | 0 | return write_result; |
548 | 0 | } |
549 | 44.0k | return Status::OK(); |
550 | 44.0k | } |
551 | | |
552 | 2 | void FsManager::CreateAndSetFaultDriveMetric(const std::string& path) { |
553 | 2 | std::unique_ptr<CounterPrototype> counter = std::make_unique<OwningCounterPrototype>( |
554 | 2 | "server", Format("drive_fault_$0", counters_.size()), path, yb::MetricUnit::kThreads, |
555 | 2 | kMetricDescription, yb::MetricLevel::kWarn, yb::EXPOSE_AS_COUNTER); |
556 | 2 | auto pointer = metric_entity_->FindOrCreateCounter(std::move(counter)); |
557 | 2 | counters_[path] = pointer; |
558 | 2 | pointer->Increment(); |
559 | 2 | } |
560 | | |
561 | 2.30M | Status FsManager::CreateDirIfMissing(const string& path, bool* created) { |
562 | 2.30M | return env_util::CreateDirIfMissing(env_, path, created); |
563 | 2.30M | } |
564 | | |
565 | 1.10M | Status FsManager::CreateDirIfMissingAndSync(const std::string& path, bool* created) { |
566 | 1.10M | RETURN_NOT_OK_PREPEND(CreateDirIfMissing(path, created), |
567 | 1.10M | Substitute("Failed to create directory $0", path)); |
568 | 1.10M | RETURN_NOT_OK_PREPEND(env_->SyncDir(DirName(path)), |
569 | 1.10M | Substitute("Failed to sync root directory $0", DirName(path))); |
570 | 1.10M | return Status::OK(); |
571 | 1.10M | } |
572 | | |
573 | 240M | const string& FsManager::uuid() const { |
574 | 240M | return CHECK_NOTNULL(metadata_.get())->uuid(); |
575 | 240M | } |
576 | | |
577 | 1.07M | set<string> FsManager::GetFsRootDirs() const { |
578 | 1.07M | return canonicalized_all_fs_roots_; |
579 | 1.07M | } |
580 | | |
581 | 168k | vector<string> FsManager::GetDataRootDirs() const { |
582 | | // Add the data subdirectory to each data root. |
583 | 168k | vector<string> data_paths; |
584 | 169k | for (const string& data_fs_root : canonicalized_data_fs_roots_) { |
585 | 169k | data_paths.push_back(DataDir(data_fs_root, server_type_)); |
586 | 169k | } |
587 | 168k | return data_paths; |
588 | 168k | } |
589 | | |
590 | 150k | vector<string> FsManager::GetWalRootDirs() const { |
591 | 150k | DCHECK(initted_); |
592 | 150k | vector<string> wal_dirs; |
593 | 151k | for (const auto& canonicalized_wal_fs_root : canonicalized_wal_fs_roots_) { |
594 | 151k | wal_dirs.push_back(WalDir(canonicalized_wal_fs_root, server_type_)); |
595 | 151k | } |
596 | 150k | return wal_dirs; |
597 | 150k | } |
598 | | |
599 | 1.77M | std::string FsManager::GetRaftGroupMetadataDir(const std::string& data_dir) { |
600 | 1.77M | return JoinPathSegments(data_dir, kRaftGroupMetadataDirName); |
601 | 1.77M | } |
602 | | |
603 | 1.77M | string FsManager::GetRaftGroupMetadataDir() const { |
604 | 1.77M | DCHECK(initted_); |
605 | 1.77M | return GetRaftGroupMetadataDir( |
606 | 1.77M | GetServerTypeDataPath(canonicalized_metadata_fs_root_, server_type_)); |
607 | 1.77M | } |
608 | | |
609 | 1.72M | string FsManager::GetRaftGroupMetadataPath(const string& tablet_id) const { |
610 | 1.72M | return JoinPathSegments(GetRaftGroupMetadataDir(), tablet_id); |
611 | 1.72M | } |
612 | | |
613 | | namespace { |
614 | | // Return true if 'fname' is a valid tablet ID. |
615 | 17.7k | bool IsValidTabletId(const std::string& fname) { |
616 | 17.7k | if (fname.find(kTmpInfix) != string::npos) { |
617 | 2 | LOG(WARNING) << "Ignoring tmp file in tablet metadata dir: " << fname; |
618 | 2 | return false; |
619 | 2 | } |
620 | | |
621 | 17.7k | if (HasPrefixString(fname, ".")) { |
622 | | // Hidden file or ./.. |
623 | 17.5k | VLOG(1) << "Ignoring hidden file in tablet metadata dir: " << fname0 ; |
624 | 17.5k | return false; |
625 | 17.5k | } |
626 | | |
627 | 218 | return true; |
628 | 17.7k | } |
629 | | } // anonymous namespace |
630 | | |
631 | 8.75k | Status FsManager::ListTabletIds(vector<string>* tablet_ids) { |
632 | 8.75k | string dir = GetRaftGroupMetadataDir(); |
633 | 8.75k | vector<string> children; |
634 | 8.75k | RETURN_NOT_OK_PREPEND(ListDir(dir, &children), |
635 | 8.75k | Substitute("Couldn't list tablets in metadata directory $0", dir)); |
636 | | |
637 | 8.75k | vector<string> tablets; |
638 | 17.7k | for (const string& child : children) { |
639 | 17.7k | if (!IsValidTabletId(child)) { |
640 | 17.5k | continue; |
641 | 17.5k | } |
642 | 218 | tablet_ids->push_back(child); |
643 | 218 | } |
644 | 8.75k | return Status::OK(); |
645 | 8.75k | } |
646 | | |
647 | 62.0k | std::string FsManager::GetInstanceMetadataPath(const string& root) const { |
648 | 62.0k | return JoinPathSegments(GetServerTypeDataPath(root, server_type_), kInstanceMetadataFileName); |
649 | 62.0k | } |
650 | | |
651 | 97.6k | std::string FsManager::GetFsLockFilePath(const string& root) const { |
652 | 97.6k | return JoinPathSegments(GetServerTypeDataPath(root, server_type_), kFsLockFileName); |
653 | 97.6k | } |
654 | | |
655 | 2.84M | std::string FsManager::GetConsensusMetadataDir() const { |
656 | 2.84M | DCHECK(initted_); |
657 | 2.84M | return GetConsensusMetadataDir( |
658 | 2.84M | GetServerTypeDataPath(canonicalized_metadata_fs_root_, server_type_)); |
659 | 2.84M | } |
660 | | |
661 | 2.84M | std::string FsManager::GetConsensusMetadataDir(const std::string& data_dir) { |
662 | 2.84M | return JoinPathSegments(data_dir, kConsensusMetadataDirName); |
663 | 2.84M | } |
664 | | |
665 | | std::string FsManager::GetFirstTabletWalDirOrDie(const std::string& table_id, |
666 | 107 | const std::string& tablet_id) const { |
667 | 107 | auto wal_root_dirs = GetWalRootDirs(); |
668 | 107 | CHECK(!wal_root_dirs.empty()) << "No WAL directories specified"0 ; |
669 | 107 | auto table_wal_dir = JoinPathSegments(wal_root_dirs[0], Substitute("table-$0", table_id)); |
670 | 107 | return JoinPathSegments(table_wal_dir, Substitute("tablet-$0", tablet_id)); |
671 | 107 | } |
672 | | |
673 | 153k | std::string FsManager::GetTabletWalRecoveryDir(const string& tablet_wal_path) { |
674 | 153k | return tablet_wal_path + kWalsRecoveryDirSuffix; |
675 | 153k | } |
676 | | |
677 | | namespace { |
678 | | |
679 | | const auto kWalFileNameFullPrefix = std::string(FsManager::kWalFileNamePrefix) + "-"; |
680 | | |
681 | | } // namespace |
682 | | |
683 | 165k | std::string FsManager::GetWalSegmentFileName(uint64_t sequence_number) { |
684 | 165k | return Format("$0$1", kWalFileNameFullPrefix, StringPrintf("%09" PRIu64, sequence_number)); |
685 | 165k | } |
686 | | |
687 | 966 | bool FsManager::IsWalSegmentFileName(const std::string& file_name) { |
688 | 966 | return boost::starts_with(file_name, kWalFileNameFullPrefix); |
689 | 966 | } |
690 | | |
691 | | // ========================================================================== |
692 | | // Dump/Debug utils |
693 | | // ========================================================================== |
694 | | |
695 | 0 | void FsManager::DumpFileSystemTree(ostream& out) { |
696 | 0 | DCHECK(initted_); |
697 | |
|
698 | 0 | for (const string& root : canonicalized_all_fs_roots_) { |
699 | 0 | out << "File-System Root: " << root << std::endl; |
700 | |
|
701 | 0 | std::vector<string> objects; |
702 | 0 | Status s = env_->GetChildren(root, &objects); |
703 | 0 | if (!s.ok()) { |
704 | 0 | LOG(ERROR) << "Unable to list the fs-tree: " << s.ToString(); |
705 | 0 | return; |
706 | 0 | } |
707 | | |
708 | 0 | DumpFileSystemTree(out, "|-", root, objects); |
709 | 0 | } |
710 | 0 | } |
711 | | |
712 | | void FsManager::DumpFileSystemTree(ostream& out, const string& prefix, |
713 | 0 | const string& path, const vector<string>& objects) { |
714 | 0 | for (const string& name : objects) { |
715 | 0 | if (name == "." || name == "..") continue; |
716 | | |
717 | 0 | std::vector<string> sub_objects; |
718 | 0 | string sub_path = JoinPathSegments(path, name); |
719 | 0 | Status s = env_->GetChildren(sub_path, &sub_objects); |
720 | 0 | if (s.ok()) { |
721 | 0 | out << prefix << name << "/" << std::endl; |
722 | 0 | DumpFileSystemTree(out, prefix + "---", sub_path, sub_objects); |
723 | 0 | } else { |
724 | 0 | out << prefix << name << std::endl; |
725 | 0 | } |
726 | 0 | } |
727 | 0 | } |
728 | | |
729 | 1.67k | Result<std::vector<std::string>> FsManager::ListDir(const std::string& path) const { |
730 | 1.67k | std::vector<std::string> result; |
731 | 1.67k | RETURN_NOT_OK(env_->GetChildren(path, ExcludeDots::kTrue, &result)); |
732 | 1.67k | return result; |
733 | 1.67k | } |
734 | | |
735 | 8.75k | Status FsManager::ListDir(const std::string& path, std::vector<std::string> *objects) const { |
736 | 8.75k | return env_->GetChildren(path, objects); |
737 | 8.75k | } |
738 | | |
739 | | } // namespace yb |