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