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