/src/rocksdb/env/file_system.cc
Line | Count | Source |
1 | | // Copyright (c) 2019-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under both the GPLv2 (found in the |
3 | | // COPYING file in the root directory) and Apache 2.0 License |
4 | | // (found in the LICENSE.Apache file in the root directory). |
5 | | // |
6 | | #include "rocksdb/file_system.h" |
7 | | |
8 | | #include "env/composite_env_wrapper.h" |
9 | | #include "env/env_chroot.h" |
10 | | #include "env/env_encryption_ctr.h" |
11 | | #include "env/fs_readonly.h" |
12 | | #include "env/mock_env.h" |
13 | | #include "logging/env_logger.h" |
14 | | #include "options/db_options.h" |
15 | | #include "rocksdb/convenience.h" |
16 | | #include "rocksdb/utilities/customizable_util.h" |
17 | | #include "rocksdb/utilities/object_registry.h" |
18 | | #include "rocksdb/utilities/options_type.h" |
19 | | #include "util/string_util.h" |
20 | | #include "utilities/counted_fs.h" |
21 | | #include "utilities/env_timed.h" |
22 | | |
23 | | namespace ROCKSDB_NAMESPACE { |
24 | | |
25 | 149k | FileSystem::FileSystem() = default; |
26 | | |
27 | 149k | FileSystem::~FileSystem() = default; |
28 | | |
29 | | static int RegisterBuiltinFileSystems(ObjectLibrary& library, |
30 | 0 | const std::string& /*arg*/) { |
31 | 0 | library.AddFactory<FileSystem>( |
32 | 0 | TimedFileSystem::kClassName(), |
33 | 0 | [](const std::string& /*uri*/, std::unique_ptr<FileSystem>* guard, |
34 | 0 | std::string* /* errmsg */) { |
35 | 0 | guard->reset(new TimedFileSystem(nullptr)); |
36 | 0 | return guard->get(); |
37 | 0 | }); |
38 | 0 | library.AddFactory<FileSystem>( |
39 | 0 | ReadOnlyFileSystem::kClassName(), |
40 | 0 | [](const std::string& /*uri*/, std::unique_ptr<FileSystem>* guard, |
41 | 0 | std::string* /* errmsg */) { |
42 | 0 | guard->reset(new ReadOnlyFileSystem(nullptr)); |
43 | 0 | return guard->get(); |
44 | 0 | }); |
45 | 0 | library.AddFactory<FileSystem>( |
46 | 0 | EncryptedFileSystem::kClassName(), |
47 | 0 | [](const std::string& /*uri*/, std::unique_ptr<FileSystem>* guard, |
48 | 0 | std::string* errmsg) { |
49 | 0 | Status s = NewEncryptedFileSystemImpl(nullptr, nullptr, guard); |
50 | 0 | if (!s.ok()) { |
51 | 0 | *errmsg = s.ToString(); |
52 | 0 | } |
53 | 0 | return guard->get(); |
54 | 0 | }); |
55 | 0 | library.AddFactory<FileSystem>( |
56 | 0 | CountedFileSystem::kClassName(), |
57 | 0 | [](const std::string& /*uri*/, std::unique_ptr<FileSystem>* guard, |
58 | 0 | std::string* /*errmsg*/) { |
59 | 0 | guard->reset(new CountedFileSystem(FileSystem::Default())); |
60 | 0 | return guard->get(); |
61 | 0 | }); |
62 | 0 | library.AddFactory<FileSystem>( |
63 | 0 | MockFileSystem::kClassName(), |
64 | 0 | [](const std::string& /*uri*/, std::unique_ptr<FileSystem>* guard, |
65 | 0 | std::string* /*errmsg*/) { |
66 | 0 | guard->reset(new MockFileSystem(SystemClock::Default())); |
67 | 0 | return guard->get(); |
68 | 0 | }); |
69 | 0 | #ifndef OS_WIN |
70 | 0 | library.AddFactory<FileSystem>( |
71 | 0 | ChrootFileSystem::kClassName(), |
72 | 0 | [](const std::string& /*uri*/, std::unique_ptr<FileSystem>* guard, |
73 | 0 | std::string* /* errmsg */) { |
74 | 0 | guard->reset(new ChrootFileSystem(nullptr, "")); |
75 | 0 | return guard->get(); |
76 | 0 | }); |
77 | 0 | #endif // OS_WIN |
78 | 0 | size_t num_types; |
79 | 0 | return static_cast<int>(library.GetFactoryCount(&num_types)); |
80 | 0 | } |
81 | | |
82 | | Status FileSystem::CreateFromString(const ConfigOptions& config_options, |
83 | | const std::string& value, |
84 | 0 | std::shared_ptr<FileSystem>* result) { |
85 | 0 | auto default_fs = FileSystem::Default(); |
86 | 0 | if (default_fs->IsInstanceOf(value)) { |
87 | 0 | *result = default_fs; |
88 | 0 | return Status::OK(); |
89 | 0 | } else { |
90 | 0 | static std::once_flag once; |
91 | 0 | std::call_once(once, [&]() { |
92 | 0 | RegisterBuiltinFileSystems(*(ObjectLibrary::Default().get()), ""); |
93 | 0 | }); |
94 | 0 | return LoadSharedObject<FileSystem>(config_options, value, result); |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | | IOStatus FileSystem::ReuseWritableFile(const std::string& fname, |
99 | | const std::string& old_fname, |
100 | | const FileOptions& opts, |
101 | | std::unique_ptr<FSWritableFile>* result, |
102 | 0 | IODebugContext* dbg) { |
103 | 0 | IOStatus s = RenameFile(old_fname, fname, opts.io_options, dbg); |
104 | 0 | if (!s.ok()) { |
105 | 0 | return s; |
106 | 0 | } |
107 | 0 | return NewWritableFile(fname, opts, result, dbg); |
108 | 0 | } |
109 | | |
110 | | IOStatus FileSystem::NewLogger(const std::string& fname, |
111 | | const IOOptions& io_opts, |
112 | | std::shared_ptr<Logger>* result, |
113 | 57.6k | IODebugContext* dbg) { |
114 | 57.6k | FileOptions options; |
115 | 57.6k | options.io_options = io_opts; |
116 | | // TODO: Tune the buffer size. |
117 | 57.6k | options.writable_file_max_buffer_size = 1024 * 1024; |
118 | 57.6k | std::unique_ptr<FSWritableFile> writable_file; |
119 | 57.6k | const IOStatus status = NewWritableFile(fname, options, &writable_file, dbg); |
120 | 57.6k | if (!status.ok()) { |
121 | 0 | return status; |
122 | 0 | } |
123 | | |
124 | 57.6k | *result = std::make_shared<EnvLogger>(std::move(writable_file), fname, |
125 | 57.6k | options, Env::Default()); |
126 | 57.6k | return IOStatus::OK(); |
127 | 57.6k | } |
128 | | |
129 | | FileOptions FileSystem::OptimizeForLogRead( |
130 | 39.2k | const FileOptions& file_options) const { |
131 | 39.2k | FileOptions optimized_file_options(file_options); |
132 | 39.2k | optimized_file_options.use_direct_reads = false; |
133 | 39.2k | return optimized_file_options; |
134 | 39.2k | } |
135 | | |
136 | | FileOptions FileSystem::OptimizeForManifestRead( |
137 | 48.4k | const FileOptions& file_options) const { |
138 | 48.4k | FileOptions optimized_file_options(file_options); |
139 | 48.4k | optimized_file_options.use_direct_reads = false; |
140 | 48.4k | return optimized_file_options; |
141 | 48.4k | } |
142 | | |
143 | | FileOptions FileSystem::OptimizeForLogWrite(const FileOptions& file_options, |
144 | 0 | const DBOptions& db_options) const { |
145 | 0 | FileOptions optimized_file_options(file_options); |
146 | 0 | optimized_file_options.bytes_per_sync = db_options.wal_bytes_per_sync; |
147 | 0 | optimized_file_options.writable_file_max_buffer_size = |
148 | 0 | db_options.writable_file_max_buffer_size; |
149 | 0 | return optimized_file_options; |
150 | 0 | } |
151 | | |
152 | | FileOptions FileSystem::OptimizeForManifestWrite( |
153 | 0 | const FileOptions& file_options) const { |
154 | 0 | return file_options; |
155 | 0 | } |
156 | | |
157 | | FileOptions FileSystem::OptimizeForCompactionTableWrite( |
158 | | const FileOptions& file_options, |
159 | 48.4k | const ImmutableDBOptions& db_options) const { |
160 | 48.4k | FileOptions optimized_file_options(file_options); |
161 | 48.4k | optimized_file_options.use_direct_writes = |
162 | 48.4k | db_options.use_direct_io_for_flush_and_compaction; |
163 | 48.4k | return optimized_file_options; |
164 | 48.4k | } |
165 | | |
166 | | FileOptions FileSystem::OptimizeForCompactionTableRead( |
167 | | const FileOptions& file_options, |
168 | 0 | const ImmutableDBOptions& db_options) const { |
169 | 0 | FileOptions optimized_file_options(file_options); |
170 | 0 | optimized_file_options.use_direct_reads = db_options.use_direct_reads; |
171 | 0 | return optimized_file_options; |
172 | 0 | } |
173 | | |
174 | | FileOptions FileSystem::OptimizeForBlobFileRead( |
175 | | const FileOptions& file_options, |
176 | 0 | const ImmutableDBOptions& db_options) const { |
177 | 0 | FileOptions optimized_file_options(file_options); |
178 | 0 | optimized_file_options.use_direct_reads = db_options.use_direct_reads; |
179 | 0 | return optimized_file_options; |
180 | 0 | } |
181 | | |
182 | | IOStatus WriteStringToFile(FileSystem* fs, const Slice& data, |
183 | | const std::string& fname, bool should_sync, |
184 | | const IOOptions& io_options, |
185 | 66.9k | const FileOptions& file_options) { |
186 | 66.9k | std::unique_ptr<FSWritableFile> file; |
187 | 66.9k | IOStatus s = fs->NewWritableFile(fname, file_options, &file, nullptr); |
188 | 66.9k | if (!s.ok()) { |
189 | 0 | return s; |
190 | 0 | } |
191 | 66.9k | s = file->Append(data, io_options, nullptr); |
192 | 66.9k | if (s.ok() && should_sync) { |
193 | 66.9k | s = file->Sync(io_options, nullptr); |
194 | 66.9k | } |
195 | 66.9k | if (!s.ok()) { |
196 | 0 | fs->DeleteFile(fname, io_options, nullptr); |
197 | 0 | } |
198 | 66.9k | return s; |
199 | 66.9k | } |
200 | | |
201 | | IOStatus ReadFileToString(FileSystem* fs, const std::string& fname, |
202 | 0 | std::string* data) { |
203 | 0 | return ReadFileToString(fs, fname, IOOptions(), data); |
204 | 0 | } |
205 | | |
206 | | IOStatus ReadFileToString(FileSystem* fs, const std::string& fname, |
207 | 87.6k | const IOOptions& opts, std::string* data) { |
208 | 87.6k | FileOptions soptions; |
209 | 87.6k | data->clear(); |
210 | 87.6k | std::unique_ptr<FSSequentialFile> file; |
211 | 87.6k | IOStatus s = status_to_io_status( |
212 | 87.6k | fs->NewSequentialFile(fname, soptions, &file, nullptr)); |
213 | 87.6k | if (!s.ok()) { |
214 | 0 | return s; |
215 | 0 | } |
216 | 87.6k | static const int kBufferSize = 8192; |
217 | 87.6k | char* space = new char[kBufferSize]; |
218 | 175k | while (true) { |
219 | 175k | Slice fragment; |
220 | 175k | s = file->Read(kBufferSize, opts, &fragment, space, nullptr); |
221 | 175k | if (!s.ok()) { |
222 | 0 | break; |
223 | 0 | } |
224 | 175k | data->append(fragment.data(), fragment.size()); |
225 | 175k | if (fragment.empty()) { |
226 | 87.6k | break; |
227 | 87.6k | } |
228 | 175k | } |
229 | 87.6k | delete[] space; |
230 | 87.6k | return s; |
231 | 87.6k | } |
232 | | |
233 | | namespace { |
234 | | static std::unordered_map<std::string, OptionTypeInfo> fs_wrapper_type_info = { |
235 | | {"target", |
236 | | OptionTypeInfo::AsCustomSharedPtr<FileSystem>( |
237 | | 0, OptionVerificationType::kByName, OptionTypeFlags::kDontSerialize)}, |
238 | | }; |
239 | | } // namespace |
240 | | FileSystemWrapper::FileSystemWrapper(const std::shared_ptr<FileSystem>& t) |
241 | 149k | : target_(t) { |
242 | 149k | RegisterOptions("", &target_, &fs_wrapper_type_info); |
243 | 149k | } |
244 | | |
245 | 0 | Status FileSystemWrapper::PrepareOptions(const ConfigOptions& options) { |
246 | 0 | if (target_ == nullptr) { |
247 | 0 | target_ = FileSystem::Default(); |
248 | 0 | } |
249 | 0 | return FileSystem::PrepareOptions(options); |
250 | 0 | } |
251 | | |
252 | | std::string FileSystemWrapper::SerializeOptions( |
253 | 0 | const ConfigOptions& config_options, const std::string& header) const { |
254 | 0 | auto parent = FileSystem::SerializeOptions(config_options, ""); |
255 | 0 | if (config_options.IsShallow() || target_ == nullptr || |
256 | 0 | target_->IsInstanceOf(FileSystem::kDefaultName())) { |
257 | 0 | return parent; |
258 | 0 | } else { |
259 | 0 | std::string result = header; |
260 | 0 | if (!StartsWith(parent, OptionTypeInfo::kIdPropName())) { |
261 | 0 | result.append(OptionTypeInfo::kIdPropName()).append("="); |
262 | 0 | } |
263 | 0 | result.append(parent); |
264 | 0 | if (!EndsWith(result, config_options.delimiter)) { |
265 | 0 | result.append(config_options.delimiter); |
266 | 0 | } |
267 | 0 | result.append("target=").append(target_->ToString(config_options)); |
268 | 0 | return result; |
269 | 0 | } |
270 | 0 | } |
271 | | |
272 | 0 | DirFsyncOptions::DirFsyncOptions() { reason = kDefault; } |
273 | | |
274 | 149k | DirFsyncOptions::DirFsyncOptions(std::string file_renamed_new_name) { |
275 | 149k | reason = kFileRenamed; |
276 | 149k | renamed_new_name = file_renamed_new_name; |
277 | 149k | } |
278 | | |
279 | 4.10k | DirFsyncOptions::DirFsyncOptions(FsyncReason fsync_reason) { |
280 | | assert(fsync_reason != kFileRenamed); |
281 | 4.10k | reason = fsync_reason; |
282 | 4.10k | } |
283 | | } // namespace ROCKSDB_NAMESPACE |