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 // A FileSystem is an interface used by the rocksdb implementation to access
7 // storage functionality like the filesystem etc.  Callers
8 // may wish to provide a custom FileSystem object when opening a database to
9 // get fine gain control; e.g., to rate limit file system operations.
10 //
11 // All FileSystem implementations are safe for concurrent access from
12 // multiple threads without any external synchronization.
13 //
14 // WARNING: Since this is a new interface, it is expected that there will be
15 // some changes as storage systems are ported over.
16 
17 #pragma once
18 
19 #include <stdint.h>
20 #include <chrono>
21 #include <cstdarg>
22 #include <functional>
23 #include <limits>
24 #include <memory>
25 #include <sstream>
26 #include <string>
27 #include <vector>
28 #include "rocksdb/env.h"
29 #include "rocksdb/io_status.h"
30 #include "rocksdb/options.h"
31 #include "rocksdb/thread_status.h"
32 
33 namespace ROCKSDB_NAMESPACE {
34 
35 class FileLock;
36 class FSDirectory;
37 class FSRandomAccessFile;
38 class FSRandomRWFile;
39 class FSSequentialFile;
40 class FSWritableFile;
41 class Logger;
42 class Slice;
43 struct ImmutableDBOptions;
44 struct MutableDBOptions;
45 class RateLimiter;
46 
47 using AccessPattern = RandomAccessFile::AccessPattern;
48 using FileAttributes = Env::FileAttributes;
49 
50 // Priority of an IO request. This is a hint and does not guarantee any
51 // particular QoS.
52 // IO_LOW - Typically background reads/writes such as compaction/flush
53 // IO_HIGH - Typically user reads/synchronous WAL writes
54 enum class IOPriority : uint8_t {
55   kIOLow,
56   kIOHigh,
57   kIOTotal,
58 };
59 
60 // Type of the data begin read/written. It can be passed down as a flag
61 // for the FileSystem implementation to optionally handle different types in
62 // different ways
63 enum class IOType : uint8_t {
64   kData,
65   kFilter,
66   kIndex,
67   kMetadata,
68   kWAL,
69   kManifest,
70   kLog,
71   kUnknown,
72   kInvalid,
73 };
74 
75 // Per-request options that can be passed down to the FileSystem
76 // implementation. These are hints and are not necessarily guaranteed to be
77 // honored. More hints can be added here in the future to indicate things like
78 // storage media (HDD/SSD) to be used, replication level etc.
79 struct IOOptions {
80   // Timeout for the operation in milliseconds
81   std::chrono::milliseconds timeout;
82 
83   // Priority - high or low
84   IOPriority prio;
85 
86   // Type of data being read/written
87   IOType type;
88 };
89 
90 // File scope options that control how a file is opened/created and accessed
91 // while its open. We may add more options here in the future such as
92 // redundancy level, media to use etc.
93 struct FileOptions : EnvOptions {
94   // Embedded IOOptions to control the parameters for any IOs that need
95   // to be issued for the file open/creation
96   IOOptions io_options;
97 
FileOptionsFileOptions98   FileOptions() : EnvOptions() {}
99 
FileOptionsFileOptions100   FileOptions(const DBOptions& opts)
101     : EnvOptions(opts) {}
102 
FileOptionsFileOptions103   FileOptions(const EnvOptions& opts)
104     : EnvOptions(opts) {}
105 };
106 
107 // A structure to pass back some debugging information from the FileSystem
108 // implementation to RocksDB in case of an IO error
109 struct IODebugContext {
110   // file_path to be filled in by RocksDB in case of an error
111   std::string file_path;
112 
113   // A map of counter names to values - set by the FileSystem implementation
114   std::map<std::string, uint64_t> counters;
115 
116   // To be set by the FileSystem implementation
117   std::string msg;
118 
IODebugContextIODebugContext119   IODebugContext() {}
120 
AddCounterIODebugContext121   void AddCounter(std::string& name, uint64_t value) {
122     counters.emplace(name, value);
123   }
124 
ToStringIODebugContext125   std::string ToString() {
126     std::ostringstream ss;
127     ss << file_path << ", ";
128     for (auto counter : counters) {
129       ss << counter.first << " = " << counter.second << ",";
130     }
131     ss << msg;
132     return ss.str();
133   }
134 };
135 
136 // The FileSystem, FSSequentialFile, FSRandomAccessFile, FSWritableFile,
137 // FSRandomRWFileclass, and FSDIrectory classes define the interface between
138 // RocksDB and storage systems, such as Posix filesystems,
139 // remote filesystems etc.
140 // The interface allows for fine grained control of individual IO operations,
141 // such as setting a timeout, prioritization, hints on data placement,
142 // different handling based on type of IO etc.
143 // This is accomplished by passing an instance of IOOptions to every
144 // API call that can potentially perform IO. Additionally, each such API is
145 // passed a pointer to a IODebugContext structure that can be used by the
146 // storage system to include troubleshooting information. The return values
147 // of the APIs is of type IOStatus, which can indicate an error code/sub-code,
148 // as well as metadata about the error such as its scope and whether its
149 // retryable.
150 class FileSystem {
151  public:
152   FileSystem();
153 
154   // No copying allowed
155   FileSystem(const FileSystem&) = delete;
156 
157   virtual ~FileSystem();
158 
159   virtual const char* Name() const = 0;
160 
Type()161   static const char* Type() { return "FileSystem"; }
162 
163   // Loads the FileSystem specified by the input value into the result
164   static Status Load(const std::string& value,
165                      std::shared_ptr<FileSystem>* result);
166 
167   // Return a default fie_system suitable for the current operating
168   // system.  Sophisticated users may wish to provide their own Env
169   // implementation instead of relying on this default file_system
170   //
171   // The result of Default() belongs to rocksdb and must never be deleted.
172   static std::shared_ptr<FileSystem> Default();
173 
174   // Create a brand new sequentially-readable file with the specified name.
175   // On success, stores a pointer to the new file in *result and returns OK.
176   // On failure stores nullptr in *result and returns non-OK.  If the file does
177   // not exist, returns a non-OK status.
178   //
179   // The returned file will only be accessed by one thread at a time.
180   virtual IOStatus NewSequentialFile(const std::string& fname,
181                                      const FileOptions& file_opts,
182                                      std::unique_ptr<FSSequentialFile>* result,
183                                      IODebugContext* dbg) = 0;
184 
185   // Create a brand new random access read-only file with the
186   // specified name.  On success, stores a pointer to the new file in
187   // *result and returns OK.  On failure stores nullptr in *result and
188   // returns non-OK.  If the file does not exist, returns a non-OK
189   // status.
190   //
191   // The returned file may be concurrently accessed by multiple threads.
192   virtual IOStatus NewRandomAccessFile(
193       const std::string& fname, const FileOptions& file_opts,
194       std::unique_ptr<FSRandomAccessFile>* result,
195       IODebugContext* dbg) = 0;
196   // These values match Linux definition
197   // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/fcntl.h#n56
198   enum WriteLifeTimeHint {
199     kWLTHNotSet = 0,  // No hint information set
200     kWLTHNone,        // No hints about write life time
201     kWLTHShort,       // Data written has a short life time
202     kWLTHMedium,      // Data written has a medium life time
203     kWLTHLong,        // Data written has a long life time
204     kWLTHExtreme,     // Data written has an extremely long life time
205   };
206 
207   // Create an object that writes to a new file with the specified
208   // name.  Deletes any existing file with the same name and creates a
209   // new file.  On success, stores a pointer to the new file in
210   // *result and returns OK.  On failure stores nullptr in *result and
211   // returns non-OK.
212   //
213   // The returned file will only be accessed by one thread at a time.
214   virtual IOStatus NewWritableFile(const std::string& fname,
215                                    const FileOptions& file_opts,
216                                    std::unique_ptr<FSWritableFile>* result,
217                                    IODebugContext* dbg) = 0;
218 
219   // Create an object that writes to a new file with the specified
220   // name.  Deletes any existing file with the same name and creates a
221   // new file.  On success, stores a pointer to the new file in
222   // *result and returns OK.  On failure stores nullptr in *result and
223   // returns non-OK.
224   //
225   // The returned file will only be accessed by one thread at a time.
ReopenWritableFile(const std::string &,const FileOptions &,std::unique_ptr<FSWritableFile> *,IODebugContext *)226   virtual IOStatus ReopenWritableFile(
227       const std::string& /*fname*/, const FileOptions& /*options*/,
228       std::unique_ptr<FSWritableFile>* /*result*/, IODebugContext* /*dbg*/) {
229     return IOStatus::NotSupported();
230   }
231 
232   // Reuse an existing file by renaming it and opening it as writable.
233   virtual IOStatus ReuseWritableFile(const std::string& fname,
234                                      const std::string& old_fname,
235                                      const FileOptions& file_opts,
236                                      std::unique_ptr<FSWritableFile>* result,
237                                      IODebugContext* dbg) = 0;
238 
239   // Open `fname` for random read and write, if file doesn't exist the file
240   // will be created.  On success, stores a pointer to the new file in
241   // *result and returns OK.  On failure returns non-OK.
242   //
243   // The returned file will only be accessed by one thread at a time.
NewRandomRWFile(const std::string &,const FileOptions &,std::unique_ptr<FSRandomRWFile> *,IODebugContext *)244   virtual IOStatus NewRandomRWFile(const std::string& /*fname*/,
245                                    const FileOptions& /*options*/,
246                                    std::unique_ptr<FSRandomRWFile>* /*result*/,
247                                    IODebugContext* /*dbg*/) {
248     return IOStatus::NotSupported(
249         "RandomRWFile is not implemented in this FileSystem");
250   }
251 
252   // Opens `fname` as a memory-mapped file for read and write (in-place updates
253   // only, i.e., no appends). On success, stores a raw buffer covering the whole
254   // file in `*result`. The file must exist prior to this call.
NewMemoryMappedFileBuffer(const std::string &,std::unique_ptr<MemoryMappedFileBuffer> *)255   virtual IOStatus NewMemoryMappedFileBuffer(
256       const std::string& /*fname*/,
257       std::unique_ptr<MemoryMappedFileBuffer>* /*result*/) {
258     return IOStatus::NotSupported(
259         "MemoryMappedFileBuffer is not implemented in this FileSystem");
260   }
261 
262   // Create an object that represents a directory. Will fail if directory
263   // doesn't exist. If the directory exists, it will open the directory
264   // and create a new Directory object.
265   //
266   // On success, stores a pointer to the new Directory in
267   // *result and returns OK. On failure stores nullptr in *result and
268   // returns non-OK.
269   virtual IOStatus NewDirectory(const std::string& name,
270                                 const IOOptions& io_opts,
271                                 std::unique_ptr<FSDirectory>* result,
272                                 IODebugContext* dbg) = 0;
273 
274   // Returns OK if the named file exists.
275   //         NotFound if the named file does not exist,
276   //                  the calling process does not have permission to determine
277   //                  whether this file exists, or if the path is invalid.
278   //         IOError if an IO Error was encountered
279   virtual IOStatus FileExists(const std::string& fname,
280                               const IOOptions& options,
281                               IODebugContext* dbg) = 0;
282 
283   // Store in *result the names of the children of the specified directory.
284   // The names are relative to "dir".
285   // Original contents of *results are dropped.
286   // Returns OK if "dir" exists and "*result" contains its children.
287   //         NotFound if "dir" does not exist, the calling process does not have
288   //                  permission to access "dir", or if "dir" is invalid.
289   //         IOError if an IO Error was encountered
290   virtual IOStatus GetChildren(const std::string& dir, const IOOptions& options,
291                                std::vector<std::string>* result,
292                                IODebugContext* dbg) = 0;
293 
294   // Store in *result the attributes of the children of the specified directory.
295   // In case the implementation lists the directory prior to iterating the files
296   // and files are concurrently deleted, the deleted files will be omitted from
297   // result.
298   // The name attributes are relative to "dir".
299   // Original contents of *results are dropped.
300   // Returns OK if "dir" exists and "*result" contains its children.
301   //         NotFound if "dir" does not exist, the calling process does not have
302   //                  permission to access "dir", or if "dir" is invalid.
303   //         IOError if an IO Error was encountered
GetChildrenFileAttributes(const std::string & dir,const IOOptions & options,std::vector<FileAttributes> * result,IODebugContext * dbg)304   virtual IOStatus GetChildrenFileAttributes(
305       const std::string& dir, const IOOptions& options,
306       std::vector<FileAttributes>* result, IODebugContext* dbg) {
307     assert(result != nullptr);
308     std::vector<std::string> child_fnames;
309     IOStatus s = GetChildren(dir, options, &child_fnames, dbg);
310     if (!s.ok()) {
311       return s;
312     }
313     result->resize(child_fnames.size());
314     size_t result_size = 0;
315     for (size_t i = 0; i < child_fnames.size(); ++i) {
316       const std::string path = dir + "/" + child_fnames[i];
317       if (!(s = GetFileSize(path, options, &(*result)[result_size].size_bytes,
318                             dbg))
319                .ok()) {
320         if (FileExists(path, options, dbg).IsNotFound()) {
321           // The file may have been deleted since we listed the directory
322           continue;
323         }
324         return s;
325       }
326       (*result)[result_size].name = std::move(child_fnames[i]);
327       result_size++;
328     }
329     result->resize(result_size);
330     return IOStatus::OK();
331   }
332 
333   // Delete the named file.
334   virtual IOStatus DeleteFile(const std::string& fname,
335                               const IOOptions& options,
336                               IODebugContext* dbg) = 0;
337 
338   // Truncate the named file to the specified size.
Truncate(const std::string &,size_t,const IOOptions &,IODebugContext *)339   virtual IOStatus Truncate(const std::string& /*fname*/, size_t /*size*/,
340                             const IOOptions& /*options*/,
341                             IODebugContext* /*dbg*/) {
342     return IOStatus::NotSupported("Truncate is not supported for this FileSystem");
343   }
344 
345   // Create the specified directory. Returns error if directory exists.
346   virtual IOStatus CreateDir(const std::string& dirname,
347                              const IOOptions& options, IODebugContext* dbg) = 0;
348 
349   // Creates directory if missing. Return Ok if it exists, or successful in
350   // Creating.
351   virtual IOStatus CreateDirIfMissing(const std::string& dirname,
352                                       const IOOptions& options,
353                                       IODebugContext* dbg) = 0;
354 
355   // Delete the specified directory.
356   virtual IOStatus DeleteDir(const std::string& dirname,
357                              const IOOptions& options, IODebugContext* dbg) = 0;
358 
359   // Store the size of fname in *file_size.
360   virtual IOStatus GetFileSize(const std::string& fname,
361                                const IOOptions& options, uint64_t* file_size,
362                                IODebugContext* dbg) = 0;
363 
364   // Store the last modification time of fname in *file_mtime.
365   virtual IOStatus GetFileModificationTime(const std::string& fname,
366                                            const IOOptions& options,
367                                            uint64_t* file_mtime,
368                                            IODebugContext* dbg) = 0;
369   // Rename file src to target.
370   virtual IOStatus RenameFile(const std::string& src, const std::string& target,
371                               const IOOptions& options,
372                               IODebugContext* dbg) = 0;
373 
374   // Hard Link file src to target.
LinkFile(const std::string &,const std::string &,const IOOptions &,IODebugContext *)375   virtual IOStatus LinkFile(const std::string& /*src*/,
376                             const std::string& /*target*/,
377                             const IOOptions& /*options*/,
378                             IODebugContext* /*dbg*/) {
379     return IOStatus::NotSupported("LinkFile is not supported for this FileSystem");
380   }
381 
NumFileLinks(const std::string &,const IOOptions &,uint64_t *,IODebugContext *)382   virtual IOStatus NumFileLinks(const std::string& /*fname*/,
383                                 const IOOptions& /*options*/,
384                                 uint64_t* /*count*/, IODebugContext* /*dbg*/) {
385     return IOStatus::NotSupported(
386         "Getting number of file links is not supported for this FileSystem");
387   }
388 
AreFilesSame(const std::string &,const std::string &,const IOOptions &,bool *,IODebugContext *)389   virtual IOStatus AreFilesSame(const std::string& /*first*/,
390                                 const std::string& /*second*/,
391                                 const IOOptions& /*options*/, bool* /*res*/,
392                                 IODebugContext* /*dbg*/) {
393     return IOStatus::NotSupported("AreFilesSame is not supported for this FileSystem");
394   }
395 
396   // Lock the specified file.  Used to prevent concurrent access to
397   // the same db by multiple processes.  On failure, stores nullptr in
398   // *lock and returns non-OK.
399   //
400   // On success, stores a pointer to the object that represents the
401   // acquired lock in *lock and returns OK.  The caller should call
402   // UnlockFile(*lock) to release the lock.  If the process exits,
403   // the lock will be automatically released.
404   //
405   // If somebody else already holds the lock, finishes immediately
406   // with a failure.  I.e., this call does not wait for existing locks
407   // to go away.
408   //
409   // May create the named file if it does not already exist.
410   virtual IOStatus LockFile(const std::string& fname, const IOOptions& options,
411                             FileLock** lock, IODebugContext* dbg) = 0;
412 
413   // Release the lock acquired by a previous successful call to LockFile.
414   // REQUIRES: lock was returned by a successful LockFile() call
415   // REQUIRES: lock has not already been unlocked.
416   virtual IOStatus UnlockFile(FileLock* lock, const IOOptions& options,
417                               IODebugContext* dbg) = 0;
418 
419   // *path is set to a temporary directory that can be used for testing. It may
420   // or many not have just been created. The directory may or may not differ
421   // between runs of the same process, but subsequent calls will return the
422   // same directory.
423   virtual IOStatus GetTestDirectory(const IOOptions& options, std::string* path,
424                                     IODebugContext* dbg) = 0;
425 
426   // Create and returns a default logger (an instance of EnvLogger) for storing
427   // informational messages. Derived classes can overide to provide custom
428   // logger.
429   virtual IOStatus NewLogger(const std::string& fname, const IOOptions& io_opts,
430                              std::shared_ptr<Logger>* result,
431                              IODebugContext* dbg) = 0;
432 
433   // Get full directory name for this db.
434   virtual IOStatus GetAbsolutePath(const std::string& db_path,
435                                    const IOOptions& options,
436                                    std::string* output_path,
437                                    IODebugContext* dbg) = 0;
438 
439   // OptimizeForLogRead will create a new FileOptions object that is a copy of
440   // the FileOptions in the parameters, but is optimized for reading log files.
441   virtual FileOptions OptimizeForLogRead(const FileOptions& file_options) const;
442 
443   // OptimizeForManifestRead will create a new FileOptions object that is a copy
444   // of the FileOptions in the parameters, but is optimized for reading manifest
445   // files.
446   virtual FileOptions OptimizeForManifestRead(
447       const FileOptions& file_options) const;
448 
449   // OptimizeForLogWrite will create a new FileOptions object that is a copy of
450   // the FileOptions in the parameters, but is optimized for writing log files.
451   // Default implementation returns the copy of the same object.
452   virtual FileOptions OptimizeForLogWrite(const FileOptions& file_options,
453                                          const DBOptions& db_options) const;
454 
455   // OptimizeForManifestWrite will create a new FileOptions object that is a
456   // copy of the FileOptions in the parameters, but is optimized for writing
457   // manifest files. Default implementation returns the copy of the same
458   // object.
459   virtual FileOptions OptimizeForManifestWrite(
460       const FileOptions& file_options) const;
461 
462   // OptimizeForCompactionTableWrite will create a new FileOptions object that
463   // is a copy of the FileOptions in the parameters, but is optimized for
464   // writing table files.
465   virtual FileOptions OptimizeForCompactionTableWrite(
466       const FileOptions& file_options,
467       const ImmutableDBOptions& immutable_ops) const;
468 
469   // OptimizeForCompactionTableRead will create a new FileOptions object that
470   // is a copy of the FileOptions in the parameters, but is optimized for
471   // reading table files.
472   virtual FileOptions OptimizeForCompactionTableRead(
473       const FileOptions& file_options,
474       const ImmutableDBOptions& db_options) const;
475 
476 // This seems to clash with a macro on Windows, so #undef it here
477 #ifdef GetFreeSpace
478 #undef GetFreeSpace
479 #endif
480 
481   // Get the amount of free disk space
GetFreeSpace(const std::string &,const IOOptions &,uint64_t *,IODebugContext *)482   virtual IOStatus GetFreeSpace(const std::string& /*path*/,
483                                 const IOOptions& /*options*/,
484                                 uint64_t* /*diskfree*/,
485                                 IODebugContext* /*dbg*/) {
486     return IOStatus::NotSupported();
487   }
488 
489   // If you're adding methods here, remember to add them to EnvWrapper too.
490 
491  private:
492   void operator=(const FileSystem&);
493 };
494 
495 // A file abstraction for reading sequentially through a file
496 class FSSequentialFile {
497  public:
FSSequentialFile()498   FSSequentialFile() {}
499 
~FSSequentialFile()500   virtual ~FSSequentialFile() {}
501 
502   // Read up to "n" bytes from the file.  "scratch[0..n-1]" may be
503   // written by this routine.  Sets "*result" to the data that was
504   // read (including if fewer than "n" bytes were successfully read).
505   // May set "*result" to point at data in "scratch[0..n-1]", so
506   // "scratch[0..n-1]" must be live when "*result" is used.
507   // If an error was encountered, returns a non-OK status.
508   //
509   // REQUIRES: External synchronization
510   virtual IOStatus Read(size_t n, const IOOptions& options, Slice* result,
511                         char* scratch, IODebugContext* dbg) = 0;
512 
513   // Skip "n" bytes from the file. This is guaranteed to be no
514   // slower that reading the same data, but may be faster.
515   //
516   // If end of file is reached, skipping will stop at the end of the
517   // file, and Skip will return OK.
518   //
519   // REQUIRES: External synchronization
520   virtual IOStatus Skip(uint64_t n) = 0;
521 
522   // Indicates the upper layers if the current SequentialFile implementation
523   // uses direct IO.
use_direct_io()524   virtual bool use_direct_io() const { return false; }
525 
526   // Use the returned alignment value to allocate
527   // aligned buffer for Direct I/O
GetRequiredBufferAlignment()528   virtual size_t GetRequiredBufferAlignment() const { return kDefaultPageSize; }
529 
530   // Remove any kind of caching of data from the offset to offset+length
531   // of this file. If the length is 0, then it refers to the end of file.
532   // If the system is not caching the file contents, then this is a noop.
InvalidateCache(size_t,size_t)533   virtual IOStatus InvalidateCache(size_t /*offset*/, size_t /*length*/) {
534     return IOStatus::NotSupported("InvalidateCache not supported.");
535   }
536 
537   // Positioned Read for direct I/O
538   // If Direct I/O enabled, offset, n, and scratch should be properly aligned
PositionedRead(uint64_t,size_t,const IOOptions &,Slice *,char *,IODebugContext *)539   virtual IOStatus PositionedRead(uint64_t /*offset*/, size_t /*n*/,
540                                   const IOOptions& /*options*/,
541                                   Slice* /*result*/, char* /*scratch*/,
542                                   IODebugContext* /*dbg*/) {
543     return IOStatus::NotSupported();
544   }
545 
546   // If you're adding methods here, remember to add them to
547   // SequentialFileWrapper too.
548 };
549 
550 // A read IO request structure for use in MultiRead
551 struct FSReadRequest {
552   // File offset in bytes
553   uint64_t offset;
554 
555   // Length to read in bytes
556   size_t len;
557 
558   // A buffer that MultiRead()  can optionally place data in. It can
559   // ignore this and allocate its own buffer
560   char* scratch;
561 
562   // Output parameter set by MultiRead() to point to the data buffer, and
563   // the number of valid bytes
564   Slice result;
565 
566   // Status of read
567   IOStatus status;
568 };
569 
570 // A file abstraction for randomly reading the contents of a file.
571 class FSRandomAccessFile {
572  public:
FSRandomAccessFile()573   FSRandomAccessFile() {}
574 
~FSRandomAccessFile()575   virtual ~FSRandomAccessFile() {}
576 
577   // Read up to "n" bytes from the file starting at "offset".
578   // "scratch[0..n-1]" may be written by this routine.  Sets "*result"
579   // to the data that was read (including if fewer than "n" bytes were
580   // successfully read).  May set "*result" to point at data in
581   // "scratch[0..n-1]", so "scratch[0..n-1]" must be live when
582   // "*result" is used.  If an error was encountered, returns a non-OK
583   // status.
584   //
585   // Safe for concurrent use by multiple threads.
586   // If Direct I/O enabled, offset, n, and scratch should be aligned properly.
587   virtual IOStatus Read(uint64_t offset, size_t n, const IOOptions& options,
588                         Slice* result, char* scratch,
589                         IODebugContext* dbg) const = 0;
590 
591   // Readahead the file starting from offset by n bytes for caching.
Prefetch(uint64_t,size_t,const IOOptions &,IODebugContext *)592   virtual IOStatus Prefetch(uint64_t /*offset*/, size_t /*n*/,
593                             const IOOptions& /*options*/,
594                             IODebugContext* /*dbg*/) {
595     return IOStatus::OK();
596   }
597 
598   // Read a bunch of blocks as described by reqs. The blocks can
599   // optionally be read in parallel. This is a synchronous call, i.e it
600   // should return after all reads have completed. The reads will be
601   // non-overlapping. If the function return Status is not ok, status of
602   // individual requests will be ignored and return status will be assumed
603   // for all read requests. The function return status is only meant for any
604   // any errors that occur before even processing specific read requests
MultiRead(FSReadRequest * reqs,size_t num_reqs,const IOOptions & options,IODebugContext * dbg)605   virtual IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs,
606                              const IOOptions& options, IODebugContext* dbg) {
607     assert(reqs != nullptr);
608     for (size_t i = 0; i < num_reqs; ++i) {
609       FSReadRequest& req = reqs[i];
610       req.status =
611           Read(req.offset, req.len, options, &req.result, req.scratch, dbg);
612     }
613     return IOStatus::OK();
614   }
615 
616   // Tries to get an unique ID for this file that will be the same each time
617   // the file is opened (and will stay the same while the file is open).
618   // Furthermore, it tries to make this ID at most "max_size" bytes. If such an
619   // ID can be created this function returns the length of the ID and places it
620   // in "id"; otherwise, this function returns 0, in which case "id"
621   // may not have been modified.
622   //
623   // This function guarantees, for IDs from a given environment, two unique ids
624   // cannot be made equal to each other by adding arbitrary bytes to one of
625   // them. That is, no unique ID is the prefix of another.
626   //
627   // This function guarantees that the returned ID will not be interpretable as
628   // a single varint.
629   //
630   // Note: these IDs are only valid for the duration of the process.
GetUniqueId(char *,size_t)631   virtual size_t GetUniqueId(char* /*id*/, size_t /*max_size*/) const {
632     return 0;  // Default implementation to prevent issues with backwards
633                // compatibility.
634   };
635 
636   enum AccessPattern { kNormal, kRandom, kSequential, kWillNeed, kWontNeed };
637 
Hint(AccessPattern)638   virtual void Hint(AccessPattern /*pattern*/) {}
639 
640   // Indicates the upper layers if the current RandomAccessFile implementation
641   // uses direct IO.
use_direct_io()642   virtual bool use_direct_io() const { return false; }
643 
644   // Use the returned alignment value to allocate
645   // aligned buffer for Direct I/O
GetRequiredBufferAlignment()646   virtual size_t GetRequiredBufferAlignment() const { return kDefaultPageSize; }
647 
648   // Remove any kind of caching of data from the offset to offset+length
649   // of this file. If the length is 0, then it refers to the end of file.
650   // If the system is not caching the file contents, then this is a noop.
InvalidateCache(size_t,size_t)651   virtual IOStatus InvalidateCache(size_t /*offset*/, size_t /*length*/) {
652     return IOStatus::NotSupported("InvalidateCache not supported.");
653   }
654 
655   // If you're adding methods here, remember to add them to
656   // RandomAccessFileWrapper too.
657 };
658 
659 // A file abstraction for sequential writing.  The implementation
660 // must provide buffering since callers may append small fragments
661 // at a time to the file.
662 class FSWritableFile {
663  public:
FSWritableFile()664   FSWritableFile()
665       : last_preallocated_block_(0),
666         preallocation_block_size_(0),
667         io_priority_(Env::IO_TOTAL),
668         write_hint_(Env::WLTH_NOT_SET),
669         strict_bytes_per_sync_(false) {}
670 
FSWritableFile(const FileOptions & options)671   explicit FSWritableFile(const FileOptions& options)
672       : last_preallocated_block_(0),
673         preallocation_block_size_(0),
674         io_priority_(Env::IO_TOTAL),
675         write_hint_(Env::WLTH_NOT_SET),
676         strict_bytes_per_sync_(options.strict_bytes_per_sync) {}
677 
~FSWritableFile()678   virtual ~FSWritableFile() {}
679 
680   // Append data to the end of the file
681   // Note: A WriteabelFile object must support either Append or
682   // PositionedAppend, so the users cannot mix the two.
683   virtual IOStatus Append(const Slice& data, const IOOptions& options,
684                           IODebugContext* dbg) = 0;
685 
686   // PositionedAppend data to the specified offset. The new EOF after append
687   // must be larger than the previous EOF. This is to be used when writes are
688   // not backed by OS buffers and hence has to always start from the start of
689   // the sector. The implementation thus needs to also rewrite the last
690   // partial sector.
691   // Note: PositionAppend does not guarantee moving the file offset after the
692   // write. A WritableFile object must support either Append or
693   // PositionedAppend, so the users cannot mix the two.
694   //
695   // PositionedAppend() can only happen on the page/sector boundaries. For that
696   // reason, if the last write was an incomplete sector we still need to rewind
697   // back to the nearest sector/page and rewrite the portion of it with whatever
698   // we need to add. We need to keep where we stop writing.
699   //
700   // PositionedAppend() can only write whole sectors. For that reason we have to
701   // pad with zeros for the last write and trim the file when closing according
702   // to the position we keep in the previous step.
703   //
704   // PositionedAppend() requires aligned buffer to be passed in. The alignment
705   // required is queried via GetRequiredBufferAlignment()
PositionedAppend(const Slice &,uint64_t,const IOOptions &,IODebugContext *)706   virtual IOStatus PositionedAppend(const Slice& /* data */,
707                                     uint64_t /* offset */,
708                                     const IOOptions& /*options*/,
709                                     IODebugContext* /*dbg*/) {
710     return IOStatus::NotSupported();
711   }
712 
713   // Truncate is necessary to trim the file to the correct size
714   // before closing. It is not always possible to keep track of the file
715   // size due to whole pages writes. The behavior is undefined if called
716   // with other writes to follow.
Truncate(uint64_t,const IOOptions &,IODebugContext *)717   virtual IOStatus Truncate(uint64_t /*size*/, const IOOptions& /*options*/,
718                             IODebugContext* /*dbg*/) {
719     return IOStatus::OK();
720   }
721   virtual IOStatus Close(const IOOptions& options, IODebugContext* dbg) = 0;
722   virtual IOStatus Flush(const IOOptions& options, IODebugContext* dbg) = 0;
723   virtual IOStatus Sync(const IOOptions& options,
724                         IODebugContext* dbg) = 0;  // sync data
725 
726   /*
727    * Sync data and/or metadata as well.
728    * By default, sync only data.
729    * Override this method for environments where we need to sync
730    * metadata as well.
731    */
Fsync(const IOOptions & options,IODebugContext * dbg)732   virtual IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) {
733     return Sync(options, dbg);
734   }
735 
736   // true if Sync() and Fsync() are safe to call concurrently with Append()
737   // and Flush().
IsSyncThreadSafe()738   virtual bool IsSyncThreadSafe() const { return false; }
739 
740   // Indicates the upper layers if the current WritableFile implementation
741   // uses direct IO.
use_direct_io()742   virtual bool use_direct_io() const { return false; }
743 
744   // Use the returned alignment value to allocate
745   // aligned buffer for Direct I/O
GetRequiredBufferAlignment()746   virtual size_t GetRequiredBufferAlignment() const { return kDefaultPageSize; }
747 
SetWriteLifeTimeHint(Env::WriteLifeTimeHint hint)748   virtual void SetWriteLifeTimeHint(Env::WriteLifeTimeHint hint) {
749     write_hint_ = hint;
750   }
751 
SetIOPriority(Env::IOPriority pri)752   virtual void SetIOPriority(Env::IOPriority pri) { io_priority_ = pri; }
753 
GetIOPriority()754   virtual Env::IOPriority GetIOPriority() { return io_priority_; }
755 
GetWriteLifeTimeHint()756   virtual Env::WriteLifeTimeHint GetWriteLifeTimeHint() { return write_hint_; }
757   /*
758    * Get the size of valid data in the file.
759    */
GetFileSize(const IOOptions &,IODebugContext *)760   virtual uint64_t GetFileSize(const IOOptions& /*options*/,
761                                IODebugContext* /*dbg*/) {
762     return 0;
763   }
764 
765   /*
766    * Get and set the default pre-allocation block size for writes to
767    * this file.  If non-zero, then Allocate will be used to extend the
768    * underlying storage of a file (generally via fallocate) if the Env
769    * instance supports it.
770    */
SetPreallocationBlockSize(size_t size)771   virtual void SetPreallocationBlockSize(size_t size) {
772     preallocation_block_size_ = size;
773   }
774 
GetPreallocationStatus(size_t * block_size,size_t * last_allocated_block)775   virtual void GetPreallocationStatus(size_t* block_size,
776                                       size_t* last_allocated_block) {
777     *last_allocated_block = last_preallocated_block_;
778     *block_size = preallocation_block_size_;
779   }
780 
781   // For documentation, refer to RandomAccessFile::GetUniqueId()
GetUniqueId(char *,size_t)782   virtual size_t GetUniqueId(char* /*id*/, size_t /*max_size*/) const {
783     return 0;  // Default implementation to prevent issues with backwards
784   }
785 
786   // Remove any kind of caching of data from the offset to offset+length
787   // of this file. If the length is 0, then it refers to the end of file.
788   // If the system is not caching the file contents, then this is a noop.
789   // This call has no effect on dirty pages in the cache.
InvalidateCache(size_t,size_t)790   virtual IOStatus InvalidateCache(size_t /*offset*/, size_t /*length*/) {
791     return IOStatus::NotSupported("InvalidateCache not supported.");
792   }
793 
794   // Sync a file range with disk.
795   // offset is the starting byte of the file range to be synchronized.
796   // nbytes specifies the length of the range to be synchronized.
797   // This asks the OS to initiate flushing the cached data to disk,
798   // without waiting for completion.
799   // Default implementation does nothing.
RangeSync(uint64_t,uint64_t,const IOOptions & options,IODebugContext * dbg)800   virtual IOStatus RangeSync(uint64_t /*offset*/, uint64_t /*nbytes*/,
801                              const IOOptions& options, IODebugContext* dbg) {
802     if (strict_bytes_per_sync_) {
803       return Sync(options, dbg);
804     }
805     return IOStatus::OK();
806   }
807 
808   // PrepareWrite performs any necessary preparation for a write
809   // before the write actually occurs.  This allows for pre-allocation
810   // of space on devices where it can result in less file
811   // fragmentation and/or less waste from over-zealous filesystem
812   // pre-allocation.
PrepareWrite(size_t offset,size_t len,const IOOptions & options,IODebugContext * dbg)813   virtual void PrepareWrite(size_t offset, size_t len, const IOOptions& options,
814                             IODebugContext* dbg) {
815     if (preallocation_block_size_ == 0) {
816       return;
817     }
818     // If this write would cross one or more preallocation blocks,
819     // determine what the last preallocation block necessary to
820     // cover this write would be and Allocate to that point.
821     const auto block_size = preallocation_block_size_;
822     size_t new_last_preallocated_block =
823         (offset + len + block_size - 1) / block_size;
824     if (new_last_preallocated_block > last_preallocated_block_) {
825       size_t num_spanned_blocks =
826           new_last_preallocated_block - last_preallocated_block_;
827       Allocate(block_size * last_preallocated_block_,
828                block_size * num_spanned_blocks, options, dbg);
829       last_preallocated_block_ = new_last_preallocated_block;
830     }
831   }
832 
833   // Pre-allocates space for a file.
Allocate(uint64_t,uint64_t,const IOOptions &,IODebugContext *)834   virtual IOStatus Allocate(uint64_t /*offset*/, uint64_t /*len*/,
835                             const IOOptions& /*options*/,
836                             IODebugContext* /*dbg*/) {
837     return IOStatus::OK();
838   }
839 
840   // If you're adding methods here, remember to add them to
841   // WritableFileWrapper too.
842 
843  protected:
preallocation_block_size()844   size_t preallocation_block_size() { return preallocation_block_size_; }
845 
846  private:
847   size_t last_preallocated_block_;
848   size_t preallocation_block_size_;
849   // No copying allowed
850   FSWritableFile(const FSWritableFile&);
851   void operator=(const FSWritableFile&);
852 
853  protected:
854   Env::IOPriority io_priority_;
855   Env::WriteLifeTimeHint write_hint_;
856   const bool strict_bytes_per_sync_;
857 };
858 
859 // A file abstraction for random reading and writing.
860 class FSRandomRWFile {
861  public:
FSRandomRWFile()862   FSRandomRWFile() {}
863 
~FSRandomRWFile()864   virtual ~FSRandomRWFile() {}
865 
866   // Indicates if the class makes use of direct I/O
867   // If false you must pass aligned buffer to Write()
use_direct_io()868   virtual bool use_direct_io() const { return false; }
869 
870   // Use the returned alignment value to allocate
871   // aligned buffer for Direct I/O
GetRequiredBufferAlignment()872   virtual size_t GetRequiredBufferAlignment() const { return kDefaultPageSize; }
873 
874   // Write bytes in `data` at  offset `offset`, Returns Status::OK() on success.
875   // Pass aligned buffer when use_direct_io() returns true.
876   virtual IOStatus Write(uint64_t offset, const Slice& data,
877                          const IOOptions& options, IODebugContext* dbg) = 0;
878 
879   // Read up to `n` bytes starting from offset `offset` and store them in
880   // result, provided `scratch` size should be at least `n`.
881   // Returns Status::OK() on success.
882   virtual IOStatus Read(uint64_t offset, size_t n, const IOOptions& options,
883                         Slice* result, char* scratch,
884                         IODebugContext* dbg) const = 0;
885 
886   virtual IOStatus Flush(const IOOptions& options, IODebugContext* dbg) = 0;
887 
888   virtual IOStatus Sync(const IOOptions& options, IODebugContext* dbg) = 0;
889 
Fsync(const IOOptions & options,IODebugContext * dbg)890   virtual IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) {
891     return Sync(options, dbg);
892   }
893 
894   virtual IOStatus Close(const IOOptions& options, IODebugContext* dbg) = 0;
895 
896   // If you're adding methods here, remember to add them to
897   // RandomRWFileWrapper too.
898 
899   // No copying allowed
900   FSRandomRWFile(const RandomRWFile&) = delete;
901   FSRandomRWFile& operator=(const RandomRWFile&) = delete;
902 };
903 
904 // MemoryMappedFileBuffer object represents a memory-mapped file's raw buffer.
905 // Subclasses should release the mapping upon destruction.
906 class FSMemoryMappedFileBuffer {
907  public:
FSMemoryMappedFileBuffer(void * _base,size_t _length)908   FSMemoryMappedFileBuffer(void* _base, size_t _length)
909       : base_(_base), length_(_length) {}
910 
911   virtual ~FSMemoryMappedFileBuffer() = 0;
912 
913   // We do not want to unmap this twice. We can make this class
914   // movable if desired, however, since
915   FSMemoryMappedFileBuffer(const FSMemoryMappedFileBuffer&) = delete;
916   FSMemoryMappedFileBuffer& operator=(const FSMemoryMappedFileBuffer&) = delete;
917 
GetBase()918   void* GetBase() const { return base_; }
GetLen()919   size_t GetLen() const { return length_; }
920 
921  protected:
922   void* base_;
923   const size_t length_;
924 };
925 
926 // Directory object represents collection of files and implements
927 // filesystem operations that can be executed on directories.
928 class FSDirectory {
929  public:
~FSDirectory()930   virtual ~FSDirectory() {}
931   // Fsync directory. Can be called concurrently from multiple threads.
932   virtual IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) = 0;
933 
GetUniqueId(char *,size_t)934   virtual size_t GetUniqueId(char* /*id*/, size_t /*max_size*/) const {
935     return 0;
936   }
937 
938   // If you're adding methods here, remember to add them to
939   // DirectoryWrapper too.
940 };
941 
942 // Below are helpers for wrapping most of the classes in this file.
943 // They forward all calls to another instance of the class.
944 // Useful when wrapping the default implementations.
945 // Typical usage is to inherit your wrapper from *Wrapper, e.g.:
946 //
947 // class MySequentialFileWrapper : public
948 // ROCKSDB_NAMESPACE::FSSequentialFileWrapper {
949 //  public:
950 //   MySequentialFileWrapper(ROCKSDB_NAMESPACE::FSSequentialFile* target):
951 //     ROCKSDB_NAMESPACE::FSSequentialFileWrapper(target) {}
952 //   Status Read(size_t n, FileSystem::IOOptions& options, Slice* result,
953 //               char* scratch, FileSystem::IODebugContext* dbg) override {
954 //     cout << "Doing a read of size " << n << "!" << endl;
955 //     return ROCKSDB_NAMESPACE::FSSequentialFileWrapper::Read(n, options,
956 //     result,
957 //                                                 scratch, dbg);
958 //   }
959 //   // All other methods are forwarded to target_ automatically.
960 // };
961 //
962 // This is often more convenient than inheriting the class directly because
963 // (a) Don't have to override and forward all methods - the Wrapper will
964 //     forward everything you're not explicitly overriding.
965 // (b) Don't need to update the wrapper when more methods are added to the
966 //     rocksdb class. Unless you actually want to override the behavior.
967 //     (And unless rocksdb people forgot to update the *Wrapper class.)
968 
969 // An implementation of Env that forwards all calls to another Env.
970 // May be useful to clients who wish to override just part of the
971 // functionality of another Env.
972 class FileSystemWrapper : public FileSystem {
973  public:
974   // Initialize an EnvWrapper that delegates all calls to *t
FileSystemWrapper(FileSystem * t)975   explicit FileSystemWrapper(FileSystem* t) : target_(t) {}
~FileSystemWrapper()976   ~FileSystemWrapper() override {}
977 
978   // Return the target to which this Env forwards all calls
target()979   FileSystem* target() const { return target_; }
980 
981   // The following text is boilerplate that forwards all methods to target()
NewSequentialFile(const std::string & f,const FileOptions & file_opts,std::unique_ptr<FSSequentialFile> * r,IODebugContext * dbg)982   IOStatus NewSequentialFile(const std::string& f,
983                              const FileOptions& file_opts,
984                              std::unique_ptr<FSSequentialFile>* r,
985                              IODebugContext* dbg) override {
986     return target_->NewSequentialFile(f, file_opts, r, dbg);
987   }
NewRandomAccessFile(const std::string & f,const FileOptions & file_opts,std::unique_ptr<FSRandomAccessFile> * r,IODebugContext * dbg)988   IOStatus NewRandomAccessFile(const std::string& f,
989                                const FileOptions& file_opts,
990                                std::unique_ptr<FSRandomAccessFile>* r,
991                                IODebugContext* dbg) override {
992     return target_->NewRandomAccessFile(f, file_opts, r, dbg);
993   }
NewWritableFile(const std::string & f,const FileOptions & file_opts,std::unique_ptr<FSWritableFile> * r,IODebugContext * dbg)994   IOStatus NewWritableFile(const std::string& f, const FileOptions& file_opts,
995                            std::unique_ptr<FSWritableFile>* r,
996                            IODebugContext* dbg) override {
997     return target_->NewWritableFile(f, file_opts, r, dbg);
998   }
ReopenWritableFile(const std::string & fname,const FileOptions & file_opts,std::unique_ptr<FSWritableFile> * result,IODebugContext * dbg)999   IOStatus ReopenWritableFile(const std::string& fname,
1000                               const FileOptions& file_opts,
1001                               std::unique_ptr<FSWritableFile>* result,
1002                               IODebugContext* dbg) override {
1003     return target_->ReopenWritableFile(fname, file_opts, result, dbg);
1004   }
ReuseWritableFile(const std::string & fname,const std::string & old_fname,const FileOptions & file_opts,std::unique_ptr<FSWritableFile> * r,IODebugContext * dbg)1005   IOStatus ReuseWritableFile(const std::string& fname,
1006                              const std::string& old_fname,
1007                              const FileOptions& file_opts,
1008                              std::unique_ptr<FSWritableFile>* r,
1009                              IODebugContext* dbg) override {
1010     return target_->ReuseWritableFile(fname, old_fname, file_opts, r,
1011                                       dbg);
1012   }
NewRandomRWFile(const std::string & fname,const FileOptions & file_opts,std::unique_ptr<FSRandomRWFile> * result,IODebugContext * dbg)1013   IOStatus NewRandomRWFile(const std::string& fname,
1014                            const FileOptions& file_opts,
1015                            std::unique_ptr<FSRandomRWFile>* result,
1016                            IODebugContext* dbg) override {
1017     return target_->NewRandomRWFile(fname, file_opts, result, dbg);
1018   }
NewMemoryMappedFileBuffer(const std::string & fname,std::unique_ptr<MemoryMappedFileBuffer> * result)1019   IOStatus NewMemoryMappedFileBuffer(
1020       const std::string& fname,
1021       std::unique_ptr<MemoryMappedFileBuffer>* result) override {
1022     return target_->NewMemoryMappedFileBuffer(fname, result);
1023   }
NewDirectory(const std::string & name,const IOOptions & io_opts,std::unique_ptr<FSDirectory> * result,IODebugContext * dbg)1024   IOStatus NewDirectory(const std::string& name, const IOOptions& io_opts,
1025                         std::unique_ptr<FSDirectory>* result,
1026                         IODebugContext* dbg) override {
1027     return target_->NewDirectory(name, io_opts, result, dbg);
1028   }
FileExists(const std::string & f,const IOOptions & io_opts,IODebugContext * dbg)1029   IOStatus FileExists(const std::string& f, const IOOptions& io_opts,
1030                       IODebugContext* dbg) override {
1031     return target_->FileExists(f, io_opts, dbg);
1032   }
GetChildren(const std::string & dir,const IOOptions & io_opts,std::vector<std::string> * r,IODebugContext * dbg)1033   IOStatus GetChildren(const std::string& dir, const IOOptions& io_opts,
1034                        std::vector<std::string>* r,
1035                        IODebugContext* dbg) override {
1036     return target_->GetChildren(dir, io_opts, r, dbg);
1037   }
GetChildrenFileAttributes(const std::string & dir,const IOOptions & options,std::vector<FileAttributes> * result,IODebugContext * dbg)1038   IOStatus GetChildrenFileAttributes(const std::string& dir,
1039                                      const IOOptions& options,
1040                                      std::vector<FileAttributes>* result,
1041                                      IODebugContext* dbg) override {
1042     return target_->GetChildrenFileAttributes(dir, options, result, dbg);
1043   }
DeleteFile(const std::string & f,const IOOptions & options,IODebugContext * dbg)1044   IOStatus DeleteFile(const std::string& f, const IOOptions& options,
1045                       IODebugContext* dbg) override {
1046     return target_->DeleteFile(f, options, dbg);
1047   }
Truncate(const std::string & fname,size_t size,const IOOptions & options,IODebugContext * dbg)1048   IOStatus Truncate(const std::string& fname, size_t size,
1049                     const IOOptions& options, IODebugContext* dbg) override {
1050     return target_->Truncate(fname, size, options, dbg);
1051   }
CreateDir(const std::string & d,const IOOptions & options,IODebugContext * dbg)1052   IOStatus CreateDir(const std::string& d, const IOOptions& options,
1053                      IODebugContext* dbg) override {
1054     return target_->CreateDir(d, options, dbg);
1055   }
CreateDirIfMissing(const std::string & d,const IOOptions & options,IODebugContext * dbg)1056   IOStatus CreateDirIfMissing(const std::string& d, const IOOptions& options,
1057                               IODebugContext* dbg) override {
1058     return target_->CreateDirIfMissing(d, options, dbg);
1059   }
DeleteDir(const std::string & d,const IOOptions & options,IODebugContext * dbg)1060   IOStatus DeleteDir(const std::string& d, const IOOptions& options,
1061                      IODebugContext* dbg) override {
1062     return target_->DeleteDir(d, options, dbg);
1063   }
GetFileSize(const std::string & f,const IOOptions & options,uint64_t * s,IODebugContext * dbg)1064   IOStatus GetFileSize(const std::string& f, const IOOptions& options,
1065                        uint64_t* s, IODebugContext* dbg) override {
1066     return target_->GetFileSize(f, options, s, dbg);
1067   }
1068 
GetFileModificationTime(const std::string & fname,const IOOptions & options,uint64_t * file_mtime,IODebugContext * dbg)1069   IOStatus GetFileModificationTime(const std::string& fname,
1070                                    const IOOptions& options,
1071                                    uint64_t* file_mtime,
1072                                    IODebugContext* dbg) override {
1073     return target_->GetFileModificationTime(fname, options, file_mtime, dbg);
1074   }
1075 
GetAbsolutePath(const std::string & db_path,const IOOptions & options,std::string * output_path,IODebugContext * dbg)1076   IOStatus GetAbsolutePath(const std::string& db_path, const IOOptions& options,
1077                            std::string* output_path,
1078                            IODebugContext* dbg) override {
1079     return target_->GetAbsolutePath(db_path, options, output_path, dbg);
1080   }
1081 
RenameFile(const std::string & s,const std::string & t,const IOOptions & options,IODebugContext * dbg)1082   IOStatus RenameFile(const std::string& s, const std::string& t,
1083                       const IOOptions& options, IODebugContext* dbg) override {
1084     return target_->RenameFile(s, t, options, dbg);
1085   }
1086 
LinkFile(const std::string & s,const std::string & t,const IOOptions & options,IODebugContext * dbg)1087   IOStatus LinkFile(const std::string& s, const std::string& t,
1088                     const IOOptions& options, IODebugContext* dbg) override {
1089     return target_->LinkFile(s, t, options, dbg);
1090   }
1091 
NumFileLinks(const std::string & fname,const IOOptions & options,uint64_t * count,IODebugContext * dbg)1092   IOStatus NumFileLinks(const std::string& fname, const IOOptions& options,
1093                         uint64_t* count, IODebugContext* dbg) override {
1094     return target_->NumFileLinks(fname, options, count, dbg);
1095   }
1096 
AreFilesSame(const std::string & first,const std::string & second,const IOOptions & options,bool * res,IODebugContext * dbg)1097   IOStatus AreFilesSame(const std::string& first, const std::string& second,
1098                         const IOOptions& options, bool* res,
1099                         IODebugContext* dbg) override {
1100     return target_->AreFilesSame(first, second, options, res, dbg);
1101   }
1102 
LockFile(const std::string & f,const IOOptions & options,FileLock ** l,IODebugContext * dbg)1103   IOStatus LockFile(const std::string& f, const IOOptions& options,
1104                     FileLock** l, IODebugContext* dbg) override {
1105     return target_->LockFile(f, options, l, dbg);
1106   }
1107 
UnlockFile(FileLock * l,const IOOptions & options,IODebugContext * dbg)1108   IOStatus UnlockFile(FileLock* l, const IOOptions& options,
1109                       IODebugContext* dbg) override {
1110     return target_->UnlockFile(l, options, dbg);
1111   }
1112 
GetTestDirectory(const IOOptions & options,std::string * path,IODebugContext * dbg)1113   IOStatus GetTestDirectory(const IOOptions& options, std::string* path,
1114                             IODebugContext* dbg) override {
1115     return target_->GetTestDirectory(options, path, dbg);
1116   }
NewLogger(const std::string & fname,const IOOptions & options,std::shared_ptr<Logger> * result,IODebugContext * dbg)1117   IOStatus NewLogger(const std::string& fname, const IOOptions& options,
1118                      std::shared_ptr<Logger>* result,
1119                      IODebugContext* dbg) override {
1120     return target_->NewLogger(fname, options, result, dbg);
1121   }
1122 
OptimizeForLogRead(const FileOptions & file_options)1123   FileOptions OptimizeForLogRead(
1124                   const FileOptions& file_options) const override {
1125     return target_->OptimizeForLogRead(file_options);
1126   }
OptimizeForManifestRead(const FileOptions & file_options)1127   FileOptions OptimizeForManifestRead(
1128       const FileOptions& file_options) const override {
1129     return target_->OptimizeForManifestRead(file_options);
1130   }
OptimizeForLogWrite(const FileOptions & file_options,const DBOptions & db_options)1131   FileOptions OptimizeForLogWrite(const FileOptions& file_options,
1132                                  const DBOptions& db_options) const override {
1133     return target_->OptimizeForLogWrite(file_options, db_options);
1134   }
OptimizeForManifestWrite(const FileOptions & file_options)1135   FileOptions OptimizeForManifestWrite(
1136       const FileOptions& file_options) const override {
1137     return target_->OptimizeForManifestWrite(file_options);
1138   }
OptimizeForCompactionTableWrite(const FileOptions & file_options,const ImmutableDBOptions & immutable_ops)1139   FileOptions OptimizeForCompactionTableWrite(
1140       const FileOptions& file_options,
1141       const ImmutableDBOptions& immutable_ops) const override {
1142     return target_->OptimizeForCompactionTableWrite(file_options,
1143                                                     immutable_ops);
1144   }
OptimizeForCompactionTableRead(const FileOptions & file_options,const ImmutableDBOptions & db_options)1145   FileOptions OptimizeForCompactionTableRead(
1146       const FileOptions& file_options,
1147       const ImmutableDBOptions& db_options) const override {
1148     return target_->OptimizeForCompactionTableRead(file_options, db_options);
1149   }
GetFreeSpace(const std::string & path,const IOOptions & options,uint64_t * diskfree,IODebugContext * dbg)1150   IOStatus GetFreeSpace(const std::string& path, const IOOptions& options,
1151                         uint64_t* diskfree, IODebugContext* dbg) override {
1152     return target_->GetFreeSpace(path, options, diskfree, dbg);
1153   }
1154 
1155  private:
1156   FileSystem* target_;
1157 };
1158 
1159 class FSSequentialFileWrapper : public FSSequentialFile {
1160  public:
FSSequentialFileWrapper(FSSequentialFile * target)1161   explicit FSSequentialFileWrapper(FSSequentialFile* target)
1162       : target_(target) {}
1163 
Read(size_t n,const IOOptions & options,Slice * result,char * scratch,IODebugContext * dbg)1164   IOStatus Read(size_t n, const IOOptions& options, Slice* result,
1165                 char* scratch, IODebugContext* dbg) override {
1166     return target_->Read(n, options, result, scratch, dbg);
1167   }
Skip(uint64_t n)1168   IOStatus Skip(uint64_t n) override { return target_->Skip(n); }
use_direct_io()1169   bool use_direct_io() const override { return target_->use_direct_io(); }
GetRequiredBufferAlignment()1170   size_t GetRequiredBufferAlignment() const override {
1171     return target_->GetRequiredBufferAlignment();
1172   }
InvalidateCache(size_t offset,size_t length)1173   IOStatus InvalidateCache(size_t offset, size_t length) override {
1174     return target_->InvalidateCache(offset, length);
1175   }
PositionedRead(uint64_t offset,size_t n,const IOOptions & options,Slice * result,char * scratch,IODebugContext * dbg)1176   IOStatus PositionedRead(uint64_t offset, size_t n, const IOOptions& options,
1177                           Slice* result, char* scratch,
1178                           IODebugContext* dbg) override {
1179     return target_->PositionedRead(offset, n, options, result, scratch, dbg);
1180   }
1181 
1182  private:
1183   FSSequentialFile* target_;
1184 };
1185 
1186 class FSRandomAccessFileWrapper : public FSRandomAccessFile {
1187  public:
FSRandomAccessFileWrapper(FSRandomAccessFile * target)1188   explicit FSRandomAccessFileWrapper(FSRandomAccessFile* target)
1189       : target_(target) {}
1190 
Read(uint64_t offset,size_t n,const IOOptions & options,Slice * result,char * scratch,IODebugContext * dbg)1191   IOStatus Read(uint64_t offset, size_t n, const IOOptions& options,
1192                 Slice* result, char* scratch,
1193                 IODebugContext* dbg) const override {
1194     return target_->Read(offset, n, options, result, scratch, dbg);
1195   }
MultiRead(FSReadRequest * reqs,size_t num_reqs,const IOOptions & options,IODebugContext * dbg)1196   IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs,
1197                      const IOOptions& options, IODebugContext* dbg) override {
1198     return target_->MultiRead(reqs, num_reqs, options, dbg);
1199   }
Prefetch(uint64_t offset,size_t n,const IOOptions & options,IODebugContext * dbg)1200   IOStatus Prefetch(uint64_t offset, size_t n, const IOOptions& options,
1201                     IODebugContext* dbg) override {
1202     return target_->Prefetch(offset, n, options, dbg);
1203   }
GetUniqueId(char * id,size_t max_size)1204   size_t GetUniqueId(char* id, size_t max_size) const override {
1205     return target_->GetUniqueId(id, max_size);
1206   };
Hint(AccessPattern pattern)1207   void Hint(AccessPattern pattern) override { target_->Hint(pattern); }
use_direct_io()1208   bool use_direct_io() const override { return target_->use_direct_io(); }
GetRequiredBufferAlignment()1209   size_t GetRequiredBufferAlignment() const override {
1210     return target_->GetRequiredBufferAlignment();
1211   }
InvalidateCache(size_t offset,size_t length)1212   IOStatus InvalidateCache(size_t offset, size_t length) override {
1213     return target_->InvalidateCache(offset, length);
1214   }
1215 
1216  private:
1217   FSRandomAccessFile* target_;
1218 };
1219 
1220 class FSWritableFileWrapper : public FSWritableFile {
1221  public:
FSWritableFileWrapper(FSWritableFile * t)1222   explicit FSWritableFileWrapper(FSWritableFile* t) : target_(t) {}
1223 
Append(const Slice & data,const IOOptions & options,IODebugContext * dbg)1224   IOStatus Append(const Slice& data, const IOOptions& options,
1225                   IODebugContext* dbg) override {
1226     return target_->Append(data, options, dbg);
1227   }
PositionedAppend(const Slice & data,uint64_t offset,const IOOptions & options,IODebugContext * dbg)1228   IOStatus PositionedAppend(const Slice& data, uint64_t offset,
1229                             const IOOptions& options,
1230                             IODebugContext* dbg) override {
1231     return target_->PositionedAppend(data, offset, options, dbg);
1232   }
Truncate(uint64_t size,const IOOptions & options,IODebugContext * dbg)1233   IOStatus Truncate(uint64_t size, const IOOptions& options,
1234                     IODebugContext* dbg) override {
1235     return target_->Truncate(size, options, dbg);
1236   }
Close(const IOOptions & options,IODebugContext * dbg)1237   IOStatus Close(const IOOptions& options, IODebugContext* dbg) override {
1238     return target_->Close(options, dbg);
1239   }
Flush(const IOOptions & options,IODebugContext * dbg)1240   IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override {
1241     return target_->Flush(options, dbg);
1242   }
Sync(const IOOptions & options,IODebugContext * dbg)1243   IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override {
1244     return target_->Sync(options, dbg);
1245   }
Fsync(const IOOptions & options,IODebugContext * dbg)1246   IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override {
1247     return target_->Fsync(options, dbg);
1248   }
IsSyncThreadSafe()1249   bool IsSyncThreadSafe() const override { return target_->IsSyncThreadSafe(); }
1250 
use_direct_io()1251   bool use_direct_io() const override { return target_->use_direct_io(); }
1252 
GetRequiredBufferAlignment()1253   size_t GetRequiredBufferAlignment() const override {
1254     return target_->GetRequiredBufferAlignment();
1255   }
1256 
SetWriteLifeTimeHint(Env::WriteLifeTimeHint hint)1257   void SetWriteLifeTimeHint(Env::WriteLifeTimeHint hint) override {
1258     target_->SetWriteLifeTimeHint(hint);
1259   }
1260 
GetWriteLifeTimeHint()1261   Env::WriteLifeTimeHint GetWriteLifeTimeHint() override {
1262     return target_->GetWriteLifeTimeHint();
1263   }
1264 
GetFileSize(const IOOptions & options,IODebugContext * dbg)1265   uint64_t GetFileSize(const IOOptions& options, IODebugContext* dbg) override {
1266     return target_->GetFileSize(options, dbg);
1267   }
1268 
SetPreallocationBlockSize(size_t size)1269   void SetPreallocationBlockSize(size_t size) override {
1270     target_->SetPreallocationBlockSize(size);
1271   }
1272 
GetPreallocationStatus(size_t * block_size,size_t * last_allocated_block)1273   void GetPreallocationStatus(size_t* block_size,
1274                               size_t* last_allocated_block) override {
1275     target_->GetPreallocationStatus(block_size, last_allocated_block);
1276   }
1277 
GetUniqueId(char * id,size_t max_size)1278   size_t GetUniqueId(char* id, size_t max_size) const override {
1279     return target_->GetUniqueId(id, max_size);
1280   }
1281 
InvalidateCache(size_t offset,size_t length)1282   IOStatus InvalidateCache(size_t offset, size_t length) override {
1283     return target_->InvalidateCache(offset, length);
1284   }
1285 
RangeSync(uint64_t offset,uint64_t nbytes,const IOOptions & options,IODebugContext * dbg)1286   IOStatus RangeSync(uint64_t offset, uint64_t nbytes, const IOOptions& options,
1287                      IODebugContext* dbg) override {
1288     return target_->RangeSync(offset, nbytes, options, dbg);
1289   }
1290 
PrepareWrite(size_t offset,size_t len,const IOOptions & options,IODebugContext * dbg)1291   void PrepareWrite(size_t offset, size_t len, const IOOptions& options,
1292                     IODebugContext* dbg) override {
1293     target_->PrepareWrite(offset, len, options, dbg);
1294   }
1295 
Allocate(uint64_t offset,uint64_t len,const IOOptions & options,IODebugContext * dbg)1296   IOStatus Allocate(uint64_t offset, uint64_t len, const IOOptions& options,
1297                     IODebugContext* dbg) override {
1298     return target_->Allocate(offset, len, options, dbg);
1299   }
1300 
1301  private:
1302   FSWritableFile* target_;
1303 };
1304 
1305 class FSRandomRWFileWrapper : public FSRandomRWFile {
1306  public:
FSRandomRWFileWrapper(FSRandomRWFile * target)1307   explicit FSRandomRWFileWrapper(FSRandomRWFile* target) : target_(target) {}
1308 
use_direct_io()1309   bool use_direct_io() const override { return target_->use_direct_io(); }
GetRequiredBufferAlignment()1310   size_t GetRequiredBufferAlignment() const override {
1311     return target_->GetRequiredBufferAlignment();
1312   }
Write(uint64_t offset,const Slice & data,const IOOptions & options,IODebugContext * dbg)1313   IOStatus Write(uint64_t offset, const Slice& data, const IOOptions& options,
1314                  IODebugContext* dbg) override {
1315     return target_->Write(offset, data, options, dbg);
1316   }
Read(uint64_t offset,size_t n,const IOOptions & options,Slice * result,char * scratch,IODebugContext * dbg)1317   IOStatus Read(uint64_t offset, size_t n, const IOOptions& options,
1318                 Slice* result, char* scratch,
1319                 IODebugContext* dbg) const override {
1320     return target_->Read(offset, n, options, result, scratch, dbg);
1321   }
Flush(const IOOptions & options,IODebugContext * dbg)1322   IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override {
1323     return target_->Flush(options, dbg);
1324   }
Sync(const IOOptions & options,IODebugContext * dbg)1325   IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override {
1326     return target_->Sync(options, dbg);
1327   }
Fsync(const IOOptions & options,IODebugContext * dbg)1328   IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override {
1329     return target_->Fsync(options, dbg);
1330   }
Close(const IOOptions & options,IODebugContext * dbg)1331   IOStatus Close(const IOOptions& options, IODebugContext* dbg) override {
1332     return target_->Close(options, dbg);
1333   }
1334 
1335  private:
1336   FSRandomRWFile* target_;
1337 };
1338 
1339 class FSDirectoryWrapper : public FSDirectory {
1340  public:
FSDirectoryWrapper(FSDirectory * target)1341   explicit FSDirectoryWrapper(FSDirectory* target) : target_(target) {}
1342 
Fsync(const IOOptions & options,IODebugContext * dbg)1343   IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override {
1344     return target_->Fsync(options, dbg);
1345   }
GetUniqueId(char * id,size_t max_size)1346   size_t GetUniqueId(char* id, size_t max_size) const override {
1347     return target_->GetUniqueId(id, max_size);
1348   }
1349 
1350  private:
1351   FSDirectory* target_;
1352 };
1353 
1354 // A utility routine: read contents of named file into *data
1355 extern Status ReadFileToString(FileSystem* fs, const std::string& fname,
1356                                std::string* data);
1357 
1358 }  // namespace ROCKSDB_NAMESPACE
1359