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