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