/src/rocksdb/env/composite_env_wrapper.h
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 | | #pragma once |
7 | | |
8 | | #include "rocksdb/env.h" |
9 | | #include "rocksdb/file_system.h" |
10 | | #include "rocksdb/system_clock.h" |
11 | | |
12 | | #ifdef _WIN32 |
13 | | // Windows API macro interference |
14 | | #undef DeleteFile |
15 | | #undef GetCurrentTime |
16 | | #undef LoadLibrary |
17 | | #endif |
18 | | |
19 | | namespace ROCKSDB_NAMESPACE { |
20 | | |
21 | | // This class supports abstracting different types of an `Env`'s functionality |
22 | | // into separate interfaces. It is constructed with a `FileSystem` and a |
23 | | // `SystemClock` and delegates: |
24 | | // * File system operations to member `file_system_`. |
25 | | // * Time related misc operations to member `clock_`. |
26 | | // A subclass needs to inherit `CompositeEnv` and provide implementations for |
27 | | // the thread management related APIs. |
28 | | class CompositeEnv : public Env { |
29 | | public: |
30 | | // Initialize a CompositeEnvWrapper that delegates all thread/time related |
31 | | // calls to env, and all file operations to fs |
32 | | explicit CompositeEnv(const std::shared_ptr<FileSystem>& fs, |
33 | | const std::shared_ptr<SystemClock>& clock) |
34 | 2 | : Env(fs, clock) {} |
35 | | |
36 | 95.3k | Status RegisterDbPaths(const std::vector<std::string>& paths) override { |
37 | 95.3k | return file_system_->RegisterDbPaths(paths); |
38 | 95.3k | } |
39 | 95.3k | Status UnregisterDbPaths(const std::vector<std::string>& paths) override { |
40 | 95.3k | return file_system_->UnregisterDbPaths(paths); |
41 | 95.3k | } |
42 | | |
43 | | // The following text is boilerplate that forwards all methods to target() |
44 | | Status NewSequentialFile(const std::string& f, |
45 | | std::unique_ptr<SequentialFile>* r, |
46 | | const EnvOptions& options) override; |
47 | | |
48 | | Status NewRandomAccessFile(const std::string& f, |
49 | | std::unique_ptr<RandomAccessFile>* r, |
50 | | const EnvOptions& options) override; |
51 | | |
52 | | Status NewWritableFile(const std::string& f, std::unique_ptr<WritableFile>* r, |
53 | | const EnvOptions& options) override; |
54 | | |
55 | | Status ReopenWritableFile(const std::string& fname, |
56 | | std::unique_ptr<WritableFile>* result, |
57 | | const EnvOptions& options) override; |
58 | | |
59 | | Status ReuseWritableFile(const std::string& fname, |
60 | | const std::string& old_fname, |
61 | | std::unique_ptr<WritableFile>* r, |
62 | | const EnvOptions& options) override; |
63 | | |
64 | | Status NewRandomRWFile(const std::string& fname, |
65 | | std::unique_ptr<RandomRWFile>* result, |
66 | | const EnvOptions& options) override; |
67 | | |
68 | | Status NewMemoryMappedFileBuffer( |
69 | | const std::string& fname, |
70 | 0 | std::unique_ptr<MemoryMappedFileBuffer>* result) override { |
71 | 0 | return file_system_->NewMemoryMappedFileBuffer(fname, result); |
72 | 0 | } |
73 | | |
74 | | Status NewDirectory(const std::string& name, |
75 | | std::unique_ptr<Directory>* result) override; |
76 | | |
77 | 106k | Status FileExists(const std::string& f) override { |
78 | 106k | IOOptions io_opts; |
79 | 106k | IODebugContext dbg; |
80 | 106k | return file_system_->FileExists(f, io_opts, &dbg); |
81 | 106k | } |
82 | | Status GetChildren(const std::string& dir, |
83 | 96.8k | std::vector<std::string>* r) override { |
84 | 96.8k | IOOptions io_opts; |
85 | 96.8k | IODebugContext dbg; |
86 | 96.8k | return file_system_->GetChildren(dir, io_opts, r, &dbg); |
87 | 96.8k | } |
88 | | Status GetChildrenFileAttributes( |
89 | 0 | const std::string& dir, std::vector<FileAttributes>* result) override { |
90 | 0 | IOOptions io_opts; |
91 | 0 | IODebugContext dbg; |
92 | 0 | return file_system_->GetChildrenFileAttributes(dir, io_opts, result, &dbg); |
93 | 0 | } |
94 | 225k | Status DeleteFile(const std::string& f) override { |
95 | 225k | IOOptions io_opts; |
96 | 225k | IODebugContext dbg; |
97 | 225k | return file_system_->DeleteFile(f, io_opts, &dbg); |
98 | 225k | } |
99 | 0 | Status Truncate(const std::string& fname, size_t size) override { |
100 | 0 | IOOptions io_opts; |
101 | 0 | IODebugContext dbg; |
102 | 0 | return file_system_->Truncate(fname, size, io_opts, &dbg); |
103 | 0 | } |
104 | 0 | Status CreateDir(const std::string& d) override { |
105 | 0 | IOOptions io_opts; |
106 | 0 | IODebugContext dbg; |
107 | 0 | return file_system_->CreateDir(d, io_opts, &dbg); |
108 | 0 | } |
109 | 154k | Status CreateDirIfMissing(const std::string& d) override { |
110 | 154k | IOOptions io_opts; |
111 | 154k | IODebugContext dbg; |
112 | 154k | return file_system_->CreateDirIfMissing(d, io_opts, &dbg); |
113 | 154k | } |
114 | 9.23k | Status DeleteDir(const std::string& d) override { |
115 | 9.23k | IOOptions io_opts; |
116 | 9.23k | IODebugContext dbg; |
117 | 9.23k | return file_system_->DeleteDir(d, io_opts, &dbg); |
118 | 9.23k | } |
119 | 239k | Status GetFileSize(const std::string& f, uint64_t* s) override { |
120 | 239k | IOOptions io_opts; |
121 | 239k | IODebugContext dbg; |
122 | 239k | return file_system_->GetFileSize(f, io_opts, s, &dbg); |
123 | 239k | } |
124 | | |
125 | | Status GetFileModificationTime(const std::string& fname, |
126 | 0 | uint64_t* file_mtime) override { |
127 | 0 | IOOptions io_opts; |
128 | 0 | IODebugContext dbg; |
129 | 0 | return file_system_->GetFileModificationTime(fname, io_opts, file_mtime, |
130 | 0 | &dbg); |
131 | 0 | } |
132 | | |
133 | 140k | Status RenameFile(const std::string& s, const std::string& t) override { |
134 | 140k | IOOptions io_opts; |
135 | 140k | IODebugContext dbg; |
136 | 140k | return file_system_->RenameFile(s, t, io_opts, &dbg); |
137 | 140k | } |
138 | | |
139 | 0 | Status LinkFile(const std::string& s, const std::string& t) override { |
140 | 0 | IOOptions io_opts; |
141 | 0 | IODebugContext dbg; |
142 | 0 | return file_system_->LinkFile(s, t, io_opts, &dbg); |
143 | 0 | } |
144 | | |
145 | 0 | Status NumFileLinks(const std::string& fname, uint64_t* count) override { |
146 | 0 | IOOptions io_opts; |
147 | 0 | IODebugContext dbg; |
148 | 0 | return file_system_->NumFileLinks(fname, io_opts, count, &dbg); |
149 | 0 | } |
150 | | |
151 | | Status AreFilesSame(const std::string& first, const std::string& second, |
152 | 0 | bool* res) override { |
153 | 0 | IOOptions io_opts; |
154 | 0 | IODebugContext dbg; |
155 | 0 | return file_system_->AreFilesSame(first, second, io_opts, res, &dbg); |
156 | 0 | } |
157 | | |
158 | 57.6k | Status LockFile(const std::string& f, FileLock** l) override { |
159 | 57.6k | IOOptions io_opts; |
160 | 57.6k | IODebugContext dbg; |
161 | 57.6k | return file_system_->LockFile(f, io_opts, l, &dbg); |
162 | 57.6k | } |
163 | | |
164 | 57.6k | Status UnlockFile(FileLock* l) override { |
165 | 57.6k | IOOptions io_opts; |
166 | 57.6k | IODebugContext dbg; |
167 | 57.6k | return file_system_->UnlockFile(l, io_opts, &dbg); |
168 | 57.6k | } |
169 | | |
170 | | Status GetAbsolutePath(const std::string& db_path, |
171 | 57.6k | std::string* output_path) override { |
172 | 57.6k | IOOptions io_opts; |
173 | 57.6k | IODebugContext dbg; |
174 | 57.6k | return file_system_->GetAbsolutePath(db_path, io_opts, output_path, &dbg); |
175 | 57.6k | } |
176 | | |
177 | | Status NewLogger(const std::string& fname, |
178 | 57.6k | std::shared_ptr<Logger>* result) override { |
179 | 57.6k | IOOptions io_opts; |
180 | 57.6k | IODebugContext dbg; |
181 | 57.6k | return file_system_->NewLogger(fname, io_opts, result, &dbg); |
182 | 57.6k | } |
183 | | |
184 | 0 | Status IsDirectory(const std::string& path, bool* is_dir) override { |
185 | 0 | IOOptions io_opts; |
186 | 0 | IODebugContext dbg; |
187 | 0 | return file_system_->IsDirectory(path, io_opts, is_dir, &dbg); |
188 | 0 | } |
189 | | |
190 | 0 | Status GetTestDirectory(std::string* path) override { |
191 | 0 | IOOptions io_opts; |
192 | 0 | IODebugContext dbg; |
193 | 0 | return file_system_->GetTestDirectory(io_opts, path, &dbg); |
194 | 0 | } |
195 | | |
196 | 0 | EnvOptions OptimizeForLogRead(const EnvOptions& env_options) const override { |
197 | 0 | return file_system_->OptimizeForLogRead(FileOptions(env_options)); |
198 | 0 | } |
199 | | |
200 | | EnvOptions OptimizeForManifestRead( |
201 | 0 | const EnvOptions& env_options) const override { |
202 | 0 | return file_system_->OptimizeForManifestRead(FileOptions(env_options)); |
203 | 0 | } |
204 | | |
205 | | EnvOptions OptimizeForLogWrite(const EnvOptions& env_options, |
206 | 0 | const DBOptions& db_options) const override { |
207 | 0 | return file_system_->OptimizeForLogWrite(FileOptions(env_options), |
208 | 0 | db_options); |
209 | 0 | } |
210 | | |
211 | | EnvOptions OptimizeForManifestWrite( |
212 | 0 | const EnvOptions& env_options) const override { |
213 | 0 | return file_system_->OptimizeForManifestWrite(FileOptions(env_options)); |
214 | 0 | } |
215 | | |
216 | | EnvOptions OptimizeForCompactionTableWrite( |
217 | | const EnvOptions& env_options, |
218 | 0 | const ImmutableDBOptions& immutable_ops) const override { |
219 | 0 | return file_system_->OptimizeForCompactionTableWrite( |
220 | 0 | FileOptions(env_options), immutable_ops); |
221 | 0 | } |
222 | | EnvOptions OptimizeForCompactionTableRead( |
223 | | const EnvOptions& env_options, |
224 | 0 | const ImmutableDBOptions& db_options) const override { |
225 | 0 | return file_system_->OptimizeForCompactionTableRead( |
226 | 0 | FileOptions(env_options), db_options); |
227 | 0 | } |
228 | | EnvOptions OptimizeForBlobFileRead( |
229 | | const EnvOptions& env_options, |
230 | 0 | const ImmutableDBOptions& db_options) const override { |
231 | 0 | return file_system_->OptimizeForBlobFileRead(FileOptions(env_options), |
232 | 0 | db_options); |
233 | 0 | } |
234 | | // This seems to clash with a macro on Windows, so #undef it here |
235 | | #ifdef GetFreeSpace |
236 | | #undef GetFreeSpace |
237 | | #endif |
238 | 0 | Status GetFreeSpace(const std::string& path, uint64_t* diskfree) override { |
239 | 0 | IOOptions io_opts; |
240 | 0 | IODebugContext dbg; |
241 | 0 | return file_system_->GetFreeSpace(path, io_opts, diskfree, &dbg); |
242 | 0 | } |
243 | 0 | uint64_t NowMicros() override { return system_clock_->NowMicros(); } |
244 | 4 | uint64_t NowNanos() override { return system_clock_->NowNanos(); } |
245 | | |
246 | 0 | uint64_t NowCPUNanos() override { return system_clock_->CPUNanos(); } |
247 | | |
248 | 0 | void SleepForMicroseconds(int micros) override { |
249 | 0 | system_clock_->SleepForMicroseconds(micros); |
250 | 0 | } |
251 | | |
252 | 4 | Status GetCurrentTime(int64_t* unix_time) override { |
253 | 4 | return system_clock_->GetCurrentTime(unix_time); |
254 | 4 | } |
255 | 0 | std::string TimeToString(uint64_t time) override { |
256 | 0 | return system_clock_->TimeToString(time); |
257 | 0 | } |
258 | | }; |
259 | | |
260 | | // A `CompositeEnvWrapper` is constructed with a target `Env` object, an |
261 | | // optional `FileSystem` object and an optional `SystemClock` object. |
262 | | // `Env::GetFileSystem()` is a fallback file system if no such object is |
263 | | // explicitly provided. Similarly, `Env::GetSystemClock()` is a fallback system |
264 | | // clock. |
265 | | // Besides delegating corresponding functionality to `file_system_` and `clock_` |
266 | | // which is inherited from `CompositeEnv`, it also implements the thread |
267 | | // management APIs by delegating them to the target `Env` object. |
268 | | // |
269 | | // Effectively, this class helps to support using customized file system |
270 | | // implementations such as a remote file system instead of the default file |
271 | | // system provided by the operating system. |
272 | | // |
273 | | // Also see public API `NewCompositeEnv` in rocksdb/include/env.h |
274 | | class CompositeEnvWrapper : public CompositeEnv { |
275 | | public: |
276 | | // Initialize a CompositeEnvWrapper that delegates all thread/time related |
277 | | // calls to env, and all file operations to fs |
278 | | explicit CompositeEnvWrapper(Env* env) |
279 | 0 | : CompositeEnvWrapper(env, env->GetFileSystem(), env->GetSystemClock()) {} |
280 | | explicit CompositeEnvWrapper(Env* env, const std::shared_ptr<FileSystem>& fs) |
281 | 0 | : CompositeEnvWrapper(env, fs, env->GetSystemClock()) {} |
282 | | |
283 | | explicit CompositeEnvWrapper(Env* env, const std::shared_ptr<SystemClock>& sc) |
284 | 0 | : CompositeEnvWrapper(env, env->GetFileSystem(), sc) {} |
285 | | |
286 | | explicit CompositeEnvWrapper(Env* env, const std::shared_ptr<FileSystem>& fs, |
287 | | const std::shared_ptr<SystemClock>& sc); |
288 | | |
289 | | explicit CompositeEnvWrapper(const std::shared_ptr<Env>& env, |
290 | | const std::shared_ptr<FileSystem>& fs) |
291 | 0 | : CompositeEnvWrapper(env, fs, env->GetSystemClock()) {} |
292 | | |
293 | | explicit CompositeEnvWrapper(const std::shared_ptr<Env>& env, |
294 | | const std::shared_ptr<SystemClock>& sc) |
295 | 0 | : CompositeEnvWrapper(env, env->GetFileSystem(), sc) {} |
296 | | |
297 | | explicit CompositeEnvWrapper(const std::shared_ptr<Env>& env, |
298 | | const std::shared_ptr<FileSystem>& fs, |
299 | | const std::shared_ptr<SystemClock>& sc); |
300 | | |
301 | 0 | static const char* kClassName() { return "CompositeEnv"; } |
302 | 0 | const char* Name() const override { return kClassName(); } |
303 | 0 | bool IsInstanceOf(const std::string& name) const override { |
304 | 0 | if (name == kClassName()) { |
305 | 0 | return true; |
306 | 0 | } else { |
307 | 0 | return CompositeEnv::IsInstanceOf(name); |
308 | 0 | } |
309 | 0 | } |
310 | 0 | const Customizable* Inner() const override { return target_.env; } |
311 | | |
312 | | Status PrepareOptions(const ConfigOptions& options) override; |
313 | | std::string SerializeOptions(const ConfigOptions& config_options, |
314 | | const std::string& header) const override; |
315 | | |
316 | | // Return the target to which this Env forwards all calls |
317 | 0 | Env* env_target() const { return target_.env; } |
318 | | |
319 | | #if !defined(OS_WIN) && !defined(ROCKSDB_NO_DYNAMIC_EXTENSION) |
320 | | Status LoadLibrary(const std::string& lib_name, |
321 | | const std::string& search_path, |
322 | 0 | std::shared_ptr<DynamicLibrary>* result) override { |
323 | 0 | return target_.env->LoadLibrary(lib_name, search_path, result); |
324 | 0 | } |
325 | | #endif |
326 | | |
327 | | void Schedule(void (*f)(void* arg), void* a, Priority pri, |
328 | 0 | void* tag = nullptr, void (*u)(void* arg) = nullptr) override { |
329 | 0 | return target_.env->Schedule(f, a, pri, tag, u); |
330 | 0 | } |
331 | | |
332 | 0 | int UnSchedule(void* tag, Priority pri) override { |
333 | 0 | return target_.env->UnSchedule(tag, pri); |
334 | 0 | } |
335 | | |
336 | 0 | void StartThread(void (*f)(void*), void* a) override { |
337 | 0 | return target_.env->StartThread(f, a); |
338 | 0 | } |
339 | 0 | void WaitForJoin() override { return target_.env->WaitForJoin(); } |
340 | 0 | unsigned int GetThreadPoolQueueLen(Priority pri = LOW) const override { |
341 | 0 | return target_.env->GetThreadPoolQueueLen(pri); |
342 | 0 | } |
343 | | |
344 | 0 | int ReserveThreads(int threads_to_be_reserved, Priority pri) override { |
345 | 0 | return target_.env->ReserveThreads(threads_to_be_reserved, pri); |
346 | 0 | } |
347 | | |
348 | 0 | int ReleaseThreads(int threads_to_be_released, Priority pri) override { |
349 | 0 | return target_.env->ReleaseThreads(threads_to_be_released, pri); |
350 | 0 | } |
351 | | |
352 | 0 | Status GetHostName(char* name, uint64_t len) override { |
353 | 0 | return target_.env->GetHostName(name, len); |
354 | 0 | } |
355 | 0 | void SetBackgroundThreads(int num, Priority pri) override { |
356 | 0 | return target_.env->SetBackgroundThreads(num, pri); |
357 | 0 | } |
358 | 0 | int GetBackgroundThreads(Priority pri) override { |
359 | 0 | return target_.env->GetBackgroundThreads(pri); |
360 | 0 | } |
361 | | |
362 | 0 | Status SetAllowNonOwnerAccess(bool allow_non_owner_access) override { |
363 | 0 | return target_.env->SetAllowNonOwnerAccess(allow_non_owner_access); |
364 | 0 | } |
365 | | |
366 | 0 | void IncBackgroundThreadsIfNeeded(int num, Priority pri) override { |
367 | 0 | return target_.env->IncBackgroundThreadsIfNeeded(num, pri); |
368 | 0 | } |
369 | | |
370 | 0 | void LowerThreadPoolIOPriority(Priority pool) override { |
371 | 0 | target_.env->LowerThreadPoolIOPriority(pool); |
372 | 0 | } |
373 | | |
374 | 0 | void LowerThreadPoolCPUPriority(Priority pool) override { |
375 | 0 | target_.env->LowerThreadPoolCPUPriority(pool); |
376 | 0 | } |
377 | | |
378 | 0 | Status LowerThreadPoolCPUPriority(Priority pool, CpuPriority pri) override { |
379 | 0 | return target_.env->LowerThreadPoolCPUPriority(pool, pri); |
380 | 0 | } |
381 | | |
382 | 0 | Status GetThreadList(std::vector<ThreadStatus>* thread_list) override { |
383 | 0 | return target_.env->GetThreadList(thread_list); |
384 | 0 | } |
385 | | |
386 | 0 | ThreadStatusUpdater* GetThreadStatusUpdater() const override { |
387 | 0 | return target_.env->GetThreadStatusUpdater(); |
388 | 0 | } |
389 | | |
390 | 0 | uint64_t GetThreadID() const override { return target_.env->GetThreadID(); } |
391 | | |
392 | 0 | std::string GenerateUniqueId() override { |
393 | 0 | return target_.env->GenerateUniqueId(); |
394 | 0 | } |
395 | | |
396 | | private: |
397 | | EnvWrapper::Target target_; |
398 | | }; |
399 | | } // namespace ROCKSDB_NAMESPACE |