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