/Users/deen/code/yugabyte-db/src/yb/rocksdb/env.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under the BSD-style license found in the |
3 | | // LICENSE file in the root directory of this source tree. An additional grant |
4 | | // of patent rights can be found in the PATENTS file in the same directory. |
5 | | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
6 | | // Use of this source code is governed by a BSD-style license that can be |
7 | | // found in the LICENSE file. See the AUTHORS file for names of contributors. |
8 | | // |
9 | | // The following only applies to changes made to this file as part of YugaByte development. |
10 | | // |
11 | | // Portions Copyright (c) YugaByte, Inc. |
12 | | // |
13 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
14 | | // in compliance with the License. You may obtain a copy of the License at |
15 | | // |
16 | | // http://www.apache.org/licenses/LICENSE-2.0 |
17 | | // |
18 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
19 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
20 | | // or implied. See the License for the specific language governing permissions and limitations |
21 | | // under the License. |
22 | | // |
23 | | // An Env is an interface used by the rocksdb implementation to access |
24 | | // operating system functionality like the filesystem etc. Callers |
25 | | // may wish to provide a custom Env object when opening a database to |
26 | | // get fine gain control; e.g., to rate limit file system operations. |
27 | | // |
28 | | // All Env implementations are safe for concurrent access from |
29 | | // multiple threads without any external synchronization. |
30 | | |
31 | | #ifndef YB_ROCKSDB_ENV_H |
32 | | #define YB_ROCKSDB_ENV_H |
33 | | |
34 | | #include <stdint.h> |
35 | | |
36 | | #include <limits> |
37 | | #include <memory> |
38 | | #include <string> |
39 | | #include <vector> |
40 | | |
41 | | #include "yb/util/status_fwd.h" |
42 | | #include "yb/util/file_system.h" |
43 | | #include "yb/util/slice.h" |
44 | | |
45 | | #ifdef _WIN32 |
46 | | // Windows API macro interference |
47 | | #undef DeleteFile |
48 | | #undef GetCurrentTime |
49 | | #endif |
50 | | |
51 | 5.67M | #define RLOG(...) LogWithContext(__FILE__, __LINE__, ##__VA_ARGS__) |
52 | 1.13M | #define RHEADER(...) HeaderWithContext(__FILE__, __LINE__, ##__VA_ARGS__) |
53 | 114k | #define RDEBUG(...) DebugWithContext(__FILE__, __LINE__, ##__VA_ARGS__) |
54 | 2.97k | #define RINFO(...) InfoWithContext(__FILE__, __LINE__, ##__VA_ARGS__) |
55 | 444 | #define RWARN(...) WarnWithContext(__FILE__, __LINE__, ##__VA_ARGS__) |
56 | 6 | #define RERROR(...) ErrorWithContext(__FILE__, __LINE__, ##__VA_ARGS__) |
57 | 6 | #define RFATAL(...) FatalWithContext(__FILE__, __LINE__, ##__VA_ARGS__) |
58 | | |
59 | | #ifdef NDEBUG |
60 | | // TODO: it should also fail in release under tests: https://yugabyte.atlassian.net/browse/ENG-1453. |
61 | | // Idea is to fail in both release and debug builds under tests, but don't fail in production. |
62 | | // This is useful when some secondary functionality is broken and we don't want to fail the whole |
63 | | // server, we can just turn that functionality off. But under tests and in debug mode we need to |
64 | | // fail to be able to catch bugs quickly. One of examples of such functionality is bloom filters. |
65 | | #define FAIL_IF_NOT_PRODUCTION() do {} while (false) |
66 | | #else |
67 | 363 | #define FAIL_IF_NOT_PRODUCTION() assert(false) |
68 | | #endif |
69 | | |
70 | | |
71 | | namespace rocksdb { |
72 | | |
73 | | class FileLock; |
74 | | class Logger; |
75 | | class WritableFile; |
76 | | class Directory; |
77 | | struct DBOptions; |
78 | | class RateLimiter; |
79 | | |
80 | | typedef yb::SequentialFile SequentialFile; |
81 | | typedef yb::RandomAccessFile RandomAccessFile; |
82 | | |
83 | | using std::unique_ptr; |
84 | | using std::shared_ptr; |
85 | | |
86 | | using Status = yb::Status; |
87 | | |
88 | | // Options while opening a file to read/write |
89 | | struct EnvOptions : public yb::FileSystemOptions { |
90 | | |
91 | | // construct with default Options |
92 | | EnvOptions(); |
93 | | |
94 | | // construct from Options |
95 | | explicit EnvOptions(const DBOptions& options); |
96 | | |
97 | | // If true, then use mmap to write data |
98 | | bool use_mmap_writes = true; |
99 | | |
100 | | // If false, fallocate() calls are bypassed |
101 | | bool allow_fallocate = true; |
102 | | |
103 | | // If true, set the FD_CLOEXEC on open fd. |
104 | | bool set_fd_cloexec = true; |
105 | | |
106 | | // Allows OS to incrementally sync files to disk while they are being |
107 | | // written, in the background. Issue one request for every bytes_per_sync |
108 | | // written. 0 turns it off. |
109 | | // Default: 0 |
110 | | uint64_t bytes_per_sync = 0; |
111 | | |
112 | | // If true, we will preallocate the file with FALLOC_FL_KEEP_SIZE flag, which |
113 | | // means that file size won't change as part of preallocation. |
114 | | // If false, preallocation will also change the file size. This option will |
115 | | // improve the performance in workloads where you sync the data on every |
116 | | // write. By default, we set it to true for MANIFEST writes and false for |
117 | | // WAL writes |
118 | | bool fallocate_with_keep_size = true; |
119 | | |
120 | | // See DBOPtions doc |
121 | | size_t compaction_readahead_size; |
122 | | |
123 | | // See DBOPtions doc |
124 | | size_t random_access_max_buffer_size; |
125 | | |
126 | | // See DBOptions doc |
127 | | size_t writable_file_max_buffer_size = 1024 * 1024; |
128 | | |
129 | | // If not nullptr, write rate limiting is enabled for flush and compaction |
130 | | RateLimiter* rate_limiter = nullptr; |
131 | | }; |
132 | | |
133 | | // RocksDBFileFactory is the implementation of all NewxxxFile Env methods as well as any methods |
134 | | // that are used to create new files. This class is created to allow easy definition of how we |
135 | | // create new files without inheriting the whole env. |
136 | | class RocksDBFileFactory { |
137 | | public: |
138 | 1.39k | virtual ~RocksDBFileFactory() {} |
139 | | virtual CHECKED_STATUS NewSequentialFile(const std::string& f, unique_ptr<SequentialFile>* r, |
140 | | const EnvOptions& options) = 0; |
141 | | virtual CHECKED_STATUS NewRandomAccessFile(const std::string& f, |
142 | | unique_ptr<RandomAccessFile>* r, |
143 | | const EnvOptions& options) = 0; |
144 | | virtual CHECKED_STATUS NewWritableFile(const std::string& f, unique_ptr<WritableFile>* r, |
145 | | const EnvOptions& options) = 0; |
146 | | virtual CHECKED_STATUS ReuseWritableFile(const std::string& fname, |
147 | | const std::string& old_fname, |
148 | | unique_ptr<WritableFile>* result, |
149 | | const EnvOptions& options) = 0; |
150 | | virtual CHECKED_STATUS GetFileSize(const std::string& fname, uint64_t* size) = 0; |
151 | | |
152 | | // Does the file factory produce plaintext files. |
153 | | virtual bool IsPlainText() const = 0; |
154 | | }; |
155 | | |
156 | | class RocksDBFileFactoryWrapper : public rocksdb::RocksDBFileFactory { |
157 | | public: |
158 | 6.11k | explicit RocksDBFileFactoryWrapper(rocksdb::RocksDBFileFactory* t) : target_(t) {} |
159 | | |
160 | 121 | virtual ~RocksDBFileFactoryWrapper() {} |
161 | | |
162 | | // The following text is boilerplate that forwards all methods to target() |
163 | | Status NewSequentialFile(const std::string& f, unique_ptr<SequentialFile>* r, |
164 | | const rocksdb::EnvOptions& options) override; |
165 | | Status NewRandomAccessFile(const std::string& f, |
166 | | unique_ptr <rocksdb::RandomAccessFile>* r, |
167 | | const EnvOptions& options) override; |
168 | | Status NewWritableFile(const std::string& f, unique_ptr <rocksdb::WritableFile>* r, |
169 | | const EnvOptions& options) override; |
170 | | |
171 | | Status ReuseWritableFile(const std::string& fname, |
172 | | const std::string& old_fname, |
173 | | unique_ptr<WritableFile>* result, |
174 | | const EnvOptions& options) override; |
175 | | |
176 | | Status GetFileSize(const std::string& fname, uint64_t* size) override; |
177 | | |
178 | 0 | bool IsPlainText() const override { |
179 | 0 | return target_->IsPlainText(); |
180 | 0 | } |
181 | | |
182 | | private: |
183 | | rocksdb::RocksDBFileFactory* target_; |
184 | | }; |
185 | | |
186 | | class Env { |
187 | | public: |
188 | | struct FileAttributes { |
189 | | // File name |
190 | | std::string name; |
191 | | |
192 | | // Size of file in bytes |
193 | | uint64_t size_bytes; |
194 | | }; |
195 | | |
196 | 18.7k | Env() {} |
197 | | |
198 | | virtual ~Env(); |
199 | | |
200 | | // Return a default environment suitable for the current operating |
201 | | // system. Sophisticated users may wish to provide their own Env |
202 | | // implementation instead of relying on this default environment. |
203 | | // |
204 | | // The result of Default() belongs to rocksdb and must never be deleted. |
205 | | static Env* Default(); |
206 | | |
207 | | static RocksDBFileFactory* DefaultFileFactory(); |
208 | | |
209 | | static std::unique_ptr<Env> NewRocksDBDefaultEnv( |
210 | | std::unique_ptr<RocksDBFileFactory> file_factory); |
211 | | |
212 | | // Create a brand new sequentially-readable file with the specified name. |
213 | | // On success, stores a pointer to the new file in *result and returns OK. |
214 | | // On failure stores nullptr in *result and returns non-OK. If the file does |
215 | | // not exist, returns a non-OK status. |
216 | | // |
217 | | // The returned file will only be accessed by one thread at a time. |
218 | | virtual Status NewSequentialFile(const std::string& fname, |
219 | | std::unique_ptr<SequentialFile>* result, |
220 | | const EnvOptions& options) |
221 | | = 0; |
222 | | |
223 | | // Create a brand new random access read-only file with the |
224 | | // specified name. On success, stores a pointer to the new file in |
225 | | // *result and returns OK. On failure stores nullptr in *result and |
226 | | // returns non-OK. If the file does not exist, returns a non-OK |
227 | | // status. |
228 | | // |
229 | | // The returned file may be concurrently accessed by multiple threads. |
230 | | virtual Status NewRandomAccessFile(const std::string& fname, |
231 | | std::unique_ptr<RandomAccessFile>* result, |
232 | | const EnvOptions& options) |
233 | | = 0; |
234 | | |
235 | | // Create an object that writes to a new file with the specified |
236 | | // name. Deletes any existing file with the same name and creates a |
237 | | // new file. On success, stores a pointer to the new file in |
238 | | // *result and returns OK. On failure stores nullptr in *result and |
239 | | // returns non-OK. |
240 | | // |
241 | | // The returned file will only be accessed by one thread at a time. |
242 | | virtual Status NewWritableFile(const std::string& fname, |
243 | | unique_ptr<WritableFile>* result, |
244 | | const EnvOptions& options) = 0; |
245 | | |
246 | | // Reuse an existing file by renaming it and opening it as writable. |
247 | | virtual Status ReuseWritableFile(const std::string& fname, |
248 | | const std::string& old_fname, |
249 | | unique_ptr<WritableFile>* result, |
250 | | const EnvOptions& options); |
251 | | |
252 | | // Create an object that represents a directory. Will fail if directory |
253 | | // doesn't exist. If the directory exists, it will open the directory |
254 | | // and create a new Directory object. |
255 | | // |
256 | | // On success, stores a pointer to the new Directory in |
257 | | // *result and returns OK. On failure stores nullptr in *result and |
258 | | // returns non-OK. |
259 | | virtual Status NewDirectory(const std::string& name, |
260 | | unique_ptr<Directory>* result) = 0; |
261 | | |
262 | | // Returns OK if the named file exists. |
263 | | // NotFound if the named file does not exist, |
264 | | // the calling process does not have permission to determine |
265 | | // whether this file exists, or if the path is invalid. |
266 | | // IOError if an IO Error was encountered |
267 | | virtual Status FileExists(const std::string& fname) = 0; |
268 | | |
269 | 0 | virtual bool DirExists(const std::string& fname) { return false; } |
270 | | |
271 | | // Store in *result the names of the children of the specified directory. |
272 | | // The names are relative to "dir". |
273 | | // Original contents of *results are dropped. |
274 | | virtual Status GetChildren(const std::string& dir, |
275 | | std::vector<std::string>* result) = 0; |
276 | | |
277 | | void GetChildrenWarnNotOk(const std::string& dir, |
278 | | std::vector<std::string>* result); |
279 | | |
280 | | // Store in *result the attributes of the children of the specified directory. |
281 | | // In case the implementation lists the directory prior to iterating the files |
282 | | // and files are concurrently deleted, the deleted files will be omitted from |
283 | | // result. |
284 | | // The name attributes are relative to "dir". |
285 | | // Original contents of *results are dropped. |
286 | | virtual Status GetChildrenFileAttributes(const std::string& dir, |
287 | | std::vector<FileAttributes>* result); |
288 | | |
289 | | // Delete the named file. |
290 | | virtual Status DeleteFile(const std::string& fname) = 0; |
291 | | |
292 | | // Delete file, print warning on failure. |
293 | | void CleanupFile(const std::string& fname); |
294 | | |
295 | | // Create the specified directory. Returns error if directory exists. |
296 | | virtual Status CreateDir(const std::string& dirname) = 0; |
297 | | |
298 | | // Creates directory if missing. Return Ok if it exists, or successful in |
299 | | // Creating. |
300 | | virtual Status CreateDirIfMissing(const std::string& dirname) = 0; |
301 | | |
302 | | // Delete the specified directory. |
303 | | virtual Status DeleteDir(const std::string& dirname) = 0; |
304 | | |
305 | | // Store the size of fname in *file_size. |
306 | | virtual Status GetFileSize(const std::string& fname, uint64_t* file_size) = 0; |
307 | | |
308 | | yb::Result<uint64_t> GetFileSize(const std::string& fname); |
309 | | |
310 | | // Store the last modification time of fname in *file_mtime. |
311 | | virtual Status GetFileModificationTime(const std::string& fname, |
312 | | uint64_t* file_mtime) = 0; |
313 | | // Rename file src to target. |
314 | | virtual Status RenameFile(const std::string& src, |
315 | | const std::string& target) = 0; |
316 | | |
317 | | // Hard Link file src to target. |
318 | | virtual Status LinkFile(const std::string& src, const std::string& target); |
319 | | |
320 | | // Lock the specified file. Used to prevent concurrent access to |
321 | | // the same db by multiple processes. On failure, stores nullptr in |
322 | | // *lock and returns non-OK. |
323 | | // |
324 | | // On success, stores a pointer to the object that represents the |
325 | | // acquired lock in *lock and returns OK. The caller should call |
326 | | // UnlockFile(*lock) to release the lock. If the process exits, |
327 | | // the lock will be automatically released. |
328 | | // |
329 | | // If somebody else already holds the lock, finishes immediately |
330 | | // with a failure. I.e., this call does not wait for existing locks |
331 | | // to go away. |
332 | | // |
333 | | // May create the named file if it does not already exist. |
334 | | virtual Status LockFile(const std::string& fname, FileLock** lock) = 0; |
335 | | |
336 | | // Release the lock acquired by a previous successful call to LockFile. |
337 | | // REQUIRES: lock was returned by a successful LockFile() call |
338 | | // REQUIRES: lock has not already been unlocked. |
339 | | virtual Status UnlockFile(FileLock* lock) = 0; |
340 | | |
341 | | // Priority for scheduling job in thread pool |
342 | | enum Priority { LOW, HIGH, TOTAL }; |
343 | | |
344 | | // Priority for requesting bytes in rate limiter scheduler |
345 | | enum IOPriority { |
346 | | IO_LOW = 0, |
347 | | IO_HIGH = 1, |
348 | | IO_TOTAL = 2 |
349 | | }; |
350 | | |
351 | | // Arrange to run "(*function)(arg)" once in a background thread, in |
352 | | // the thread pool specified by pri. By default, jobs go to the 'LOW' |
353 | | // priority thread pool. |
354 | | |
355 | | // "function" may run in an unspecified thread. Multiple functions |
356 | | // added to the same Env may run concurrently in different threads. |
357 | | // I.e., the caller may not assume that background work items are |
358 | | // serialized. |
359 | | // When the UnSchedule function is called, the unschedFunction |
360 | | // registered at the time of Schedule is invoked with arg as a parameter. |
361 | | virtual void Schedule(void (*function)(void* arg), void* arg, |
362 | | Priority pri = LOW, void* tag = nullptr, |
363 | | void (*unschedFunction)(void* arg) = 0) = 0; |
364 | | |
365 | | // Arrange to remove jobs for given arg from the queue_ if they are not |
366 | | // already scheduled. Caller is expected to have exclusive lock on arg. |
367 | 0 | virtual int UnSchedule(void* arg, Priority pri) { return 0; } |
368 | | |
369 | | // Start a new thread, invoking "function(arg)" within the new thread. |
370 | | // When "function(arg)" returns, the thread will be destroyed. |
371 | | virtual void StartThread(void (*function)(void* arg), void* arg) = 0; |
372 | | |
373 | | // Wait for all threads started by StartThread to terminate. |
374 | 0 | virtual void WaitForJoin() {} |
375 | | |
376 | | // Get thread pool queue length for specific thrad pool. |
377 | 0 | virtual unsigned int GetThreadPoolQueueLen(Priority pri = LOW) const { |
378 | 0 | return 0; |
379 | 0 | } |
380 | | |
381 | | // *path is set to a temporary directory that can be used for testing. It may |
382 | | // or many not have just been created. The directory may or may not differ |
383 | | // between runs of the same process, but subsequent calls will return the |
384 | | // same directory. |
385 | | virtual Status GetTestDirectory(std::string* path) = 0; |
386 | | |
387 | | // Create and return a log file for storing informational messages. |
388 | | virtual Status NewLogger(const std::string& fname, |
389 | | shared_ptr<Logger>* result) = 0; |
390 | | |
391 | | // Returns the number of micro-seconds since some fixed point in time. Only |
392 | | // useful for computing deltas of time. |
393 | | // However, it is often used as system time such as in GenericRateLimiter |
394 | | // and other places so a port needs to return system time in order to work. |
395 | | virtual uint64_t NowMicros() = 0; |
396 | | |
397 | | // Returns the number of nano-seconds since some fixed point in time. Only |
398 | | // useful for computing deltas of time in one run. |
399 | | // Default implementation simply relies on NowMicros |
400 | 86 | virtual uint64_t NowNanos() { |
401 | 86 | return NowMicros() * 1000; |
402 | 86 | } |
403 | | |
404 | | // Sleep/delay the thread for the perscribed number of micro-seconds. |
405 | | virtual void SleepForMicroseconds(int micros) = 0; |
406 | | |
407 | | // Get the current host name. |
408 | | virtual Status GetHostName(char* name, uint64_t len) = 0; |
409 | | |
410 | | // Get the number of seconds since the Epoch, 1970-01-01 00:00:00 (UTC). |
411 | | virtual Status GetCurrentTime(int64_t* unix_time) = 0; |
412 | | |
413 | | // Get full directory name for this db. |
414 | | virtual Status GetAbsolutePath(const std::string& db_path, |
415 | | std::string* output_path) = 0; |
416 | | |
417 | | // The number of background worker threads of a specific thread pool |
418 | | // for this environment. 'LOW' is the default pool. |
419 | | // default number: 1 |
420 | | virtual void SetBackgroundThreads(int number, Priority pri = LOW) = 0; |
421 | | |
422 | | // Enlarge number of background worker threads of a specific thread pool |
423 | | // for this environment if it is smaller than specified. 'LOW' is the default |
424 | | // pool. |
425 | | virtual void IncBackgroundThreadsIfNeeded(int number, Priority pri) = 0; |
426 | | |
427 | | // Lower IO priority for threads from the specified pool. |
428 | 0 | virtual void LowerThreadPoolIOPriority(Priority pool = LOW) {} |
429 | | |
430 | | // Converts seconds-since-Jan-01-1970 to a printable string |
431 | | virtual std::string TimeToString(uint64_t time) = 0; |
432 | | |
433 | | // Generates a unique id that can be used to identify a db |
434 | | virtual std::string GenerateUniqueId(); |
435 | | |
436 | | // OptimizeForLogWrite will create a new EnvOptions object that is a copy of |
437 | | // the EnvOptions in the parameters, but is optimized for writing log files. |
438 | | // Default implementation returns the copy of the same object. |
439 | | virtual EnvOptions OptimizeForLogWrite(const EnvOptions& env_options, |
440 | | const DBOptions& db_options) const; |
441 | | // OptimizeForManifestWrite will create a new EnvOptions object that is a copy |
442 | | // of the EnvOptions in the parameters, but is optimized for writing manifest |
443 | | // files. Default implementation returns the copy of the same object. |
444 | | virtual EnvOptions OptimizeForManifestWrite(const EnvOptions& env_options) |
445 | | const; |
446 | | |
447 | 0 | virtual bool IsPlainText() const { |
448 | 0 | return true; |
449 | 0 | } |
450 | | |
451 | | // Returns the ID of the current thread. |
452 | | virtual uint64_t GetThreadID() const; |
453 | | |
454 | | private: |
455 | | // No copying allowed |
456 | | Env(const Env&); |
457 | | void operator=(const Env&); |
458 | | }; |
459 | | |
460 | | // A file abstraction for sequential writing. The implementation |
461 | | // must provide buffering since callers may append small fragments |
462 | | // at a time to the file. |
463 | | class WritableFile : public yb::FileWithUniqueId { |
464 | | public: |
465 | | WritableFile() |
466 | | : last_preallocated_block_(0), |
467 | | preallocation_block_size_(0), |
468 | 3.16M | io_priority_(Env::IO_TOTAL) { |
469 | 3.16M | } |
470 | | virtual ~WritableFile(); |
471 | | |
472 | | // Indicates if the class makes use of unbuffered I/O |
473 | 1.09M | virtual bool UseOSBuffer() const { |
474 | 1.09M | return true; |
475 | 1.09M | } |
476 | | |
477 | | const size_t c_DefaultPageSize = 4 * 1024; |
478 | | |
479 | | // This is needed when you want to allocate |
480 | | // AlignedBuffer for use with file I/O classes |
481 | | // Used for unbuffered file I/O when UseOSBuffer() returns false |
482 | 1.09M | virtual size_t GetRequiredBufferAlignment() const { |
483 | 1.09M | return c_DefaultPageSize; |
484 | 1.09M | } |
485 | | |
486 | | virtual Status Append(const Slice& data) = 0; |
487 | | |
488 | | // Positioned write for unbuffered access default forward |
489 | | // to simple append as most of the tests are buffered by default |
490 | | virtual Status PositionedAppend(const Slice& /* data */, uint64_t /* offset */); |
491 | | |
492 | | // Truncate is necessary to trim the file to the correct size |
493 | | // before closing. It is not always possible to keep track of the file |
494 | | // size due to whole pages writes. The behavior is undefined if called |
495 | | // with other writes to follow. |
496 | | virtual Status Truncate(uint64_t size); |
497 | | virtual Status Close() = 0; |
498 | | virtual Status Flush() = 0; |
499 | | virtual Status Sync() = 0; // sync data |
500 | | |
501 | | /* |
502 | | * Sync data and/or metadata as well. |
503 | | * By default, sync only data. |
504 | | * Override this method for environments where we need to sync |
505 | | * metadata as well. |
506 | | */ |
507 | | virtual Status Fsync(); |
508 | | |
509 | | // true if Sync() and Fsync() are safe to call concurrently with Append() |
510 | | // and Flush(). |
511 | 0 | virtual bool IsSyncThreadSafe() const { |
512 | 0 | return false; |
513 | 0 | } |
514 | | |
515 | | // Indicates the upper layers if the current WritableFile implementation |
516 | | // uses direct IO. |
517 | 1.09M | virtual bool UseDirectIO() const { return false; } |
518 | | |
519 | | /* |
520 | | * Change the priority in rate limiter if rate limiting is enabled. |
521 | | * If rate limiting is not enabled, this call has no effect. |
522 | | */ |
523 | 98.6k | virtual void SetIOPriority(Env::IOPriority pri) { |
524 | 98.6k | io_priority_ = pri; |
525 | 98.6k | } |
526 | | |
527 | 1.66M | virtual Env::IOPriority GetIOPriority() { return io_priority_; } |
528 | | |
529 | | /* |
530 | | * Get the size of valid data in the file. |
531 | | */ |
532 | 0 | virtual uint64_t GetFileSize() { |
533 | 0 | return 0; |
534 | 0 | } |
535 | | |
536 | | /* |
537 | | * Get and set the default pre-allocation block size for writes to |
538 | | * this file. If non-zero, then Allocate will be used to extend the |
539 | | * underlying storage of a file (generally via fallocate) if the Env |
540 | | * instance supports it. |
541 | | */ |
542 | 972k | void SetPreallocationBlockSize(size_t size) { |
543 | 972k | preallocation_block_size_ = size; |
544 | 972k | } |
545 | | |
546 | | virtual void GetPreallocationStatus(size_t* block_size, |
547 | 2.98M | size_t* last_allocated_block) { |
548 | 2.98M | *last_allocated_block = last_preallocated_block_; |
549 | 2.98M | *block_size = preallocation_block_size_; |
550 | 2.98M | } |
551 | | |
552 | | // For documentation, refer to File::GetUniqueId() |
553 | 1.46k | virtual size_t GetUniqueId(char* id) const override { |
554 | 1.46k | return 0; // Default implementation to prevent issues with backwards |
555 | 1.46k | } |
556 | | |
557 | | // Remove any kind of caching of data from the offset to offset+length |
558 | | // of this file. If the length is 0, then it refers to the end of file. |
559 | | // If the system is not caching the file contents, then this is a noop. |
560 | | // This call has no effect on dirty pages in the cache. |
561 | | virtual Status InvalidateCache(size_t offset, size_t length); |
562 | | |
563 | | // Sync a file range with disk. |
564 | | // offset is the starting byte of the file range to be synchronized. |
565 | | // nbytes specifies the length of the range to be synchronized. |
566 | | // This asks the OS to initiate flushing the cached data to disk, |
567 | | // without waiting for completion. |
568 | | // Default implementation does nothing. |
569 | | virtual Status RangeSync(uint64_t offset, uint64_t nbytes); |
570 | | |
571 | | // PrepareWrite performs any necessary preparation for a write |
572 | | // before the write actually occurs. This allows for pre-allocation |
573 | | // of space on devices where it can result in less file |
574 | | // fragmentation and/or less waste from over-zealous filesystem |
575 | | // pre-allocation. |
576 | | void PrepareWrite(size_t offset, size_t len); |
577 | | |
578 | | protected: |
579 | | /* |
580 | | * Pre-allocate space for a file. |
581 | | */ |
582 | | virtual Status Allocate(uint64_t offset, uint64_t len); |
583 | | |
584 | 96.9k | size_t preallocation_block_size() { return preallocation_block_size_; } |
585 | | |
586 | | private: |
587 | | size_t last_preallocated_block_; |
588 | | size_t preallocation_block_size_; |
589 | | // No copying allowed |
590 | | WritableFile(const WritableFile&); |
591 | | void operator=(const WritableFile&); |
592 | | |
593 | | protected: |
594 | | friend class WritableFileWrapper; |
595 | | friend class WritableFileMirror; |
596 | | |
597 | | Env::IOPriority io_priority_; |
598 | | }; |
599 | | |
600 | | // Directory object represents collection of files and implements |
601 | | // filesystem operations that can be executed on directories. |
602 | | class Directory { |
603 | | public: |
604 | 325k | virtual ~Directory() {} |
605 | | // Fsync directory. Can be called concurrently from multiple threads. |
606 | | virtual Status Fsync() = 0; |
607 | | }; |
608 | | |
609 | | enum InfoLogLevel : unsigned char { |
610 | | DEBUG_LEVEL = 0, |
611 | | INFO_LEVEL, |
612 | | WARN_LEVEL, |
613 | | ERROR_LEVEL, |
614 | | FATAL_LEVEL, |
615 | | HEADER_LEVEL, |
616 | | NUM_INFO_LOG_LEVELS, |
617 | | }; |
618 | | |
619 | | // An interface for writing log messages. |
620 | | class Logger { |
621 | | public: |
622 | | size_t kDoNotSupportGetLogFileSize = std::numeric_limits<size_t>::max(); |
623 | | |
624 | | explicit Logger(const InfoLogLevel log_level = InfoLogLevel::INFO_LEVEL) |
625 | 559k | : log_level_(log_level) { |
626 | | |
627 | 559k | } |
628 | | virtual ~Logger(); |
629 | | |
630 | | // Write a header to the log file with the specified format |
631 | | // It is recommended that you log all header information at the start of the |
632 | | // application. But it is not enforced. |
633 | | virtual void LogHeaderWithContext(const char* file, const int line, |
634 | 1.13M | const char *format, va_list ap) { |
635 | | // Default implementation does a simple INFO level log write. |
636 | | // Please override as per the logger class requirement. |
637 | 1.13M | LogvWithContext(file, line, InfoLogLevel::HEADER_LEVEL, format, ap); |
638 | 1.13M | } |
639 | | |
640 | | // Write an entry to the log file with the specified format. |
641 | | virtual void Logv(const char* format, va_list ap) = 0; |
642 | | |
643 | | // Write an entry to the log file with the specified log level |
644 | | // and format. Any log with level under the internal log level |
645 | | // of *this (see @SetInfoLogLevel and @GetInfoLogLevel) will not be |
646 | | // printed. |
647 | | virtual void Logv(const rocksdb::InfoLogLevel log_level, const char* format, va_list ap); |
648 | | |
649 | | // A version of the Logv function that takes the file and line number of the caller. |
650 | | // Accomplished by the RLOG() macro with the __FILE__ and __LINE__ attributes. |
651 | | virtual void LogvWithContext(const char* file, |
652 | | const int line, |
653 | | const InfoLogLevel log_level, |
654 | | const char* format, |
655 | | va_list ap); |
656 | | |
657 | 0 | virtual size_t GetLogFileSize() const { return kDoNotSupportGetLogFileSize; } |
658 | | // Flush to the OS buffers |
659 | 2.44M | virtual void Flush() {} |
660 | 1.46M | virtual InfoLogLevel GetInfoLogLevel() const { return log_level_; } |
661 | 21.0k | virtual void SetInfoLogLevel(const InfoLogLevel log_level) { |
662 | 21.0k | log_level_ = log_level; |
663 | 21.0k | } |
664 | | |
665 | 14.2k | virtual const std::string& Prefix() const { |
666 | 14.2k | static const std::string kEmptyString; |
667 | 14.2k | return kEmptyString; |
668 | 14.2k | } |
669 | | |
670 | | private: |
671 | | // No copying allowed |
672 | | Logger(const Logger&); |
673 | | void operator=(const Logger&); |
674 | | InfoLogLevel log_level_; |
675 | | }; |
676 | | |
677 | | |
678 | | // Identifies a locked file. |
679 | | class FileLock { |
680 | | public: |
681 | 687k | FileLock() { } |
682 | | virtual ~FileLock(); |
683 | | private: |
684 | | // No copying allowed |
685 | | FileLock(const FileLock&); |
686 | | void operator=(const FileLock&); |
687 | | }; |
688 | | |
689 | | extern void LogFlush(const shared_ptr<Logger>& info_log); |
690 | | |
691 | | extern void LogWithContext(const char* file, |
692 | | const int line, |
693 | | const InfoLogLevel log_level, |
694 | | const shared_ptr<Logger>& info_log, |
695 | | const char* format, |
696 | | ...); |
697 | | |
698 | | // a set of log functions with different log levels. |
699 | | extern void HeaderWithContext( |
700 | | const char* file, |
701 | | const int line, |
702 | | const shared_ptr<Logger> &info_log, |
703 | | const char *format, ...); |
704 | | extern void DebugWithContext( |
705 | | const char* file, |
706 | | const int line, |
707 | | const shared_ptr<Logger> &info_log, |
708 | | const char *format, ...); |
709 | | extern void InfoWithContext( |
710 | | const char* file, |
711 | | const int line, |
712 | | const shared_ptr<Logger> &info_log, |
713 | | const char *format, ...); |
714 | | extern void WarnWithContext( |
715 | | const char* file, |
716 | | const int line, |
717 | | const shared_ptr<Logger> &info_log, |
718 | | const char *format, ...); |
719 | | extern void ErrorWithContext( |
720 | | const char* file, |
721 | | const int line, |
722 | | const shared_ptr<Logger> &info_log, |
723 | | const char *format, ...); |
724 | | extern void FatalWithContext( |
725 | | const char* file, |
726 | | const int line, |
727 | | const shared_ptr<Logger> &info_log, |
728 | | const char *format, ...); |
729 | | |
730 | | // Log the specified data to *info_log if info_log is non-nullptr. |
731 | | // The default info log level is InfoLogLevel::ERROR. |
732 | | extern void LogWithContext(const char* file, |
733 | | const int line, |
734 | | const shared_ptr<Logger>& info_log, |
735 | | const char* format, |
736 | | ...) |
737 | | # if defined(__GNUC__) || defined(__clang__) |
738 | | __attribute__((__format__ (__printf__, 4, 5))) |
739 | | # endif |
740 | | ; // NOLINT(whitespace/semicolon) |
741 | | |
742 | | extern void LogFlush(Logger *info_log); |
743 | | |
744 | | extern void LogWithContext(const char* file, |
745 | | const int line, |
746 | | const InfoLogLevel log_level, |
747 | | Logger* info_log, |
748 | | const char* format, |
749 | | ...); |
750 | | |
751 | | // The default info log level is InfoLogLevel::ERROR. |
752 | | extern void LogWithContext(const char* file, |
753 | | const int line, |
754 | | Logger* info_log, |
755 | | const char* format, |
756 | | ...) |
757 | | # if defined(__GNUC__) || defined(__clang__) |
758 | | __attribute__((__format__ (__printf__, 4, 5))) |
759 | | # endif |
760 | | ; // NOLINT(whitespace/semicolon) |
761 | | |
762 | | // a set of log functions with different log levels. |
763 | | extern void HeaderWithContext(const char* file, const int line, |
764 | | Logger *info_log, const char *format, ...); |
765 | | extern void DebugWithContext(const char* file, const int line, |
766 | | Logger *info_log, const char *format, ...); |
767 | | extern void InfoWithContext(const char* file, const int line, |
768 | | Logger *info_log, const char *format, ...); |
769 | | extern void WarnWithContext(const char* file, const int line, |
770 | | Logger *info_log, const char *format, ...); |
771 | | extern void ErrorWithContext(const char* file, const int line, |
772 | | Logger *info_log, const char *format, ...); |
773 | | extern void FatalWithContext(const char* file, const int line, |
774 | | Logger *info_log, const char *format, ...); |
775 | | |
776 | | // A utility routine: write "data" to the named file. |
777 | | extern Status WriteStringToFile(Env* env, const Slice& data, |
778 | | const std::string& fname, |
779 | | bool should_sync = false); |
780 | | |
781 | | // A utility routine: read contents of named file into *data |
782 | | extern Status ReadFileToString(Env* env, const std::string& fname, |
783 | | std::string* data); |
784 | | |
785 | | // An implementation of Env that forwards all calls to another Env. |
786 | | // May be useful to clients who wish to override just part of the |
787 | | // functionality of another Env. |
788 | | class EnvWrapper : public Env { |
789 | | public: |
790 | | // Initialize an EnvWrapper that delegates all calls to *t |
791 | 672 | explicit EnvWrapper(Env* t) : target_(t) { } |
792 | | virtual ~EnvWrapper(); |
793 | | |
794 | | // Return the target to which this Env forwards all calls |
795 | 3.14M | Env* target() const { return target_; } |
796 | | |
797 | | // The following text is boilerplate that forwards all methods to target() |
798 | | Status NewSequentialFile(const std::string& f, std::unique_ptr<SequentialFile>* r, |
799 | | const EnvOptions& options) override; |
800 | | Status NewRandomAccessFile(const std::string& f, |
801 | | unique_ptr<RandomAccessFile>* r, |
802 | | const EnvOptions& options) override; |
803 | | Status NewWritableFile(const std::string& f, unique_ptr<WritableFile>* r, |
804 | | const EnvOptions& options) override; |
805 | | Status ReuseWritableFile(const std::string& fname, |
806 | | const std::string& old_fname, |
807 | | unique_ptr<WritableFile>* r, |
808 | | const EnvOptions& options) override; |
809 | | virtual Status NewDirectory(const std::string& name, |
810 | | unique_ptr<Directory>* result) override; |
811 | | Status FileExists(const std::string& f) override; |
812 | | |
813 | 15.9k | bool DirExists(const std::string& f) override { |
814 | 15.9k | return target_->DirExists(f); |
815 | 15.9k | } |
816 | | |
817 | | Status GetChildren(const std::string& dir, |
818 | | std::vector<std::string>* r) override; |
819 | | Status GetChildrenFileAttributes( |
820 | | const std::string& dir, std::vector<FileAttributes>* result) override; |
821 | | Status DeleteFile(const std::string& f) override; |
822 | | Status CreateDir(const std::string& d) override; |
823 | | Status CreateDirIfMissing(const std::string& d) override; |
824 | | Status DeleteDir(const std::string& d) override; |
825 | | Status GetFileSize(const std::string& f, uint64_t* s) override; |
826 | | |
827 | | Status GetFileModificationTime(const std::string& fname, |
828 | | uint64_t* file_mtime) override; |
829 | | |
830 | | Status RenameFile(const std::string& s, const std::string& t) override; |
831 | | |
832 | | Status LinkFile(const std::string& s, const std::string& t) override; |
833 | | |
834 | | Status LockFile(const std::string& f, FileLock** l) override; |
835 | | |
836 | | Status UnlockFile(FileLock* l) override; |
837 | | |
838 | | void Schedule(void (*f)(void* arg), void* a, Priority pri, |
839 | 110k | void* tag = nullptr, void (*u)(void* arg) = 0) override { |
840 | 110k | return target_->Schedule(f, a, pri, tag, u); |
841 | 110k | } |
842 | | |
843 | 18.2k | int UnSchedule(void* tag, Priority pri) override { |
844 | 18.2k | return target_->UnSchedule(tag, pri); |
845 | 18.2k | } |
846 | | |
847 | 412 | void StartThread(void (*f)(void*), void* a) override { |
848 | 412 | return target_->StartThread(f, a); |
849 | 412 | } |
850 | 0 | void WaitForJoin() override { return target_->WaitForJoin(); } |
851 | | virtual unsigned int GetThreadPoolQueueLen( |
852 | 9 | Priority pri = LOW) const override { |
853 | 9 | return target_->GetThreadPoolQueueLen(pri); |
854 | 9 | } |
855 | | virtual Status GetTestDirectory(std::string* path) override; |
856 | | virtual Status NewLogger(const std::string& fname, |
857 | | shared_ptr<Logger>* result) override; |
858 | 20.3k | uint64_t NowMicros() override { return target_->NowMicros(); } |
859 | 37 | void SleepForMicroseconds(int micros) override { |
860 | 37 | target_->SleepForMicroseconds(micros); |
861 | 37 | } |
862 | | Status GetHostName(char* name, uint64_t len) override; |
863 | | Status GetCurrentTime(int64_t* unix_time) override; |
864 | | Status GetAbsolutePath(const std::string& db_path, |
865 | | std::string* output_path) override; |
866 | 1.14k | void SetBackgroundThreads(int num, Priority pri) override { |
867 | 1.14k | return target_->SetBackgroundThreads(num, pri); |
868 | 1.14k | } |
869 | | |
870 | 25.0k | void IncBackgroundThreadsIfNeeded(int num, Priority pri) override { |
871 | 25.0k | return target_->IncBackgroundThreadsIfNeeded(num, pri); |
872 | 25.0k | } |
873 | | |
874 | 0 | void LowerThreadPoolIOPriority(Priority pool = LOW) override { |
875 | 0 | target_->LowerThreadPoolIOPriority(pool); |
876 | 0 | } |
877 | | |
878 | 0 | std::string TimeToString(uint64_t time) override { |
879 | 0 | return target_->TimeToString(time); |
880 | 0 | } |
881 | | |
882 | 201 | uint64_t GetThreadID() const override { |
883 | 201 | return target_->GetThreadID(); |
884 | 201 | } |
885 | | |
886 | 5.51k | bool IsPlainText() const override { |
887 | 5.51k | return target_->IsPlainText(); |
888 | 5.51k | } |
889 | | |
890 | | private: |
891 | | Env* target_; |
892 | | }; |
893 | | |
894 | | // An implementation of WritableFile that forwards all calls to another |
895 | | // WritableFile. May be useful to clients who wish to override just part of the |
896 | | // functionality of another WritableFile. |
897 | | // It's declared as friend of WritableFile to allow forwarding calls to |
898 | | // protected virtual methods. |
899 | | class WritableFileWrapper : public WritableFile { |
900 | | public: |
901 | 39 | explicit WritableFileWrapper(std::unique_ptr<WritableFile> t) : target_(std::move(t)) { } |
902 | | |
903 | | Status Append(const Slice& data) override; |
904 | | Status PositionedAppend(const Slice& data, uint64_t offset) override; |
905 | | Status Truncate(uint64_t size) override; |
906 | | Status Close() override; |
907 | | Status Flush() override; |
908 | | Status Sync() override; |
909 | | Status Fsync() override; |
910 | 0 | bool IsSyncThreadSafe() const override { return target_->IsSyncThreadSafe(); } |
911 | 5 | void SetIOPriority(Env::IOPriority pri) override { |
912 | 5 | target_->SetIOPriority(pri); |
913 | 5 | } |
914 | 0 | Env::IOPriority GetIOPriority() override { return target_->GetIOPriority(); } |
915 | 99.5k | uint64_t GetFileSize() override { return target_->GetFileSize(); } |
916 | | void GetPreallocationStatus(size_t* block_size, |
917 | 1 | size_t* last_allocated_block) override { |
918 | 1 | target_->GetPreallocationStatus(block_size, last_allocated_block); |
919 | 1 | } |
920 | 1 | size_t GetUniqueId(char* id) const override { |
921 | 1 | return target_->GetUniqueId(id); |
922 | 1 | } |
923 | | Status InvalidateCache(size_t offset, size_t length) override; |
924 | | |
925 | | protected: |
926 | | Status Allocate(uint64_t offset, uint64_t len) override; |
927 | | Status RangeSync(uint64_t offset, uint64_t nbytes) override; |
928 | | |
929 | | private: |
930 | | std::unique_ptr<WritableFile> target_; |
931 | | }; |
932 | | |
933 | | // Returns a new environment that stores its data in memory and delegates |
934 | | // all non-file-storage tasks to base_env. The caller must delete the result |
935 | | // when it is no longer needed. |
936 | | // *base_env must remain live while the result is in use. |
937 | | Env* NewMemEnv(Env* base_env); |
938 | | |
939 | | // Returns a new environment that is used for HDFS environment. |
940 | | // This is a factory method for HdfsEnv declared in hdfs/env_hdfs.h |
941 | | Status NewHdfsEnv(Env** hdfs_env, const std::string& fsname); |
942 | | |
943 | | } // namespace rocksdb |
944 | | |
945 | | #endif // YB_ROCKSDB_ENV_H |