From eb8d27e5c14dc0bc39c27e9b2ea23789372c8416 Mon Sep 17 00:00:00 2001 From: mrambacher Date: Thu, 9 Feb 2023 10:15:49 -0500 Subject: [PATCH] Add Injection and NoSyncFS (#380) Use a NoSyncFileSystem to skip Sync/FSync to reduce test times --- CMakeLists.txt | 2 + TARGETS | 4 + db/db_compaction_test.cc | 2 +- db/db_with_timestamp_test_util.h | 2 +- env/env_test.cc | 32 +++ include/rocksdb/file_system.h | 2 +- src.mk | 2 + table/table_test.cc | 5 + test_util/testutil.cc | 8 + utilities/counted_fs.cc | 276 +-------------------- utilities/counted_fs.h | 213 +++++++++++++++- utilities/fault_injection_fs.cc | 233 +++++++++--------- utilities/fault_injection_fs.h | 115 ++++----- utilities/injection_fs.cc | 89 +++++++ utilities/injection_fs.h | 403 +++++++++++++++++++++++++++++++ utilities/nosync_fs.cc | 36 +++ utilities/nosync_fs.h | 125 ++++++++++ 17 files changed, 1081 insertions(+), 468 deletions(-) create mode 100644 utilities/injection_fs.cc create mode 100644 utilities/injection_fs.h create mode 100644 utilities/nosync_fs.cc create mode 100644 utilities/nosync_fs.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ee24208d9..6563df44e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -945,6 +945,7 @@ set(SOURCES utilities/fault_injection_env.cc utilities/fault_injection_fs.cc utilities/fault_injection_secondary_cache.cc + utilities/injection_fs.cc utilities/leveldb_options/leveldb_options.cc utilities/memory/memory_util.cc utilities/merge_operators.cc @@ -955,6 +956,7 @@ set(SOURCES utilities/merge_operators/string_append/stringappend.cc utilities/merge_operators/string_append/stringappend2.cc utilities/merge_operators/uint64add.cc + utilities/nosync_fs.cc utilities/object_registry.cc utilities/option_change_migration/option_change_migration.cc utilities/options/options_util.cc diff --git a/TARGETS b/TARGETS index 2514e09a7c..9ceb2ee424 100644 --- a/TARGETS +++ b/TARGETS @@ -289,6 +289,7 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[ "utilities/fault_injection_env.cc", "utilities/fault_injection_fs.cc", "utilities/fault_injection_secondary_cache.cc", + "utilities/injection_fs.cc", "utilities/leveldb_options/leveldb_options.cc", "utilities/memory/memory_util.cc", "utilities/merge_operators.cc", @@ -299,6 +300,7 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[ "utilities/merge_operators/string_append/stringappend.cc", "utilities/merge_operators/string_append/stringappend2.cc", "utilities/merge_operators/uint64add.cc", + "utilities/nosync_fs.cc", "utilities/object_registry.cc", "utilities/option_change_migration/option_change_migration.cc", "utilities/options/options_util.cc", @@ -635,6 +637,7 @@ cpp_library_wrapper(name="rocksdb_whole_archive_lib", srcs=[ "utilities/fault_injection_env.cc", "utilities/fault_injection_fs.cc", "utilities/fault_injection_secondary_cache.cc", + "utilities/injection_fs.cc", "utilities/leveldb_options/leveldb_options.cc", "utilities/memory/memory_util.cc", "utilities/merge_operators.cc", @@ -645,6 +648,7 @@ cpp_library_wrapper(name="rocksdb_whole_archive_lib", srcs=[ "utilities/merge_operators/string_append/stringappend.cc", "utilities/merge_operators/string_append/stringappend2.cc", "utilities/merge_operators/uint64add.cc", + "utilities/nosync_fs.cc", "utilities/object_registry.cc", "utilities/option_change_migration/option_change_migration.cc", "utilities/options/options_util.cc", diff --git a/db/db_compaction_test.cc b/db/db_compaction_test.cc index 33729d73ea..ae1af66651 100644 --- a/db/db_compaction_test.cc +++ b/db/db_compaction_test.cc @@ -76,7 +76,7 @@ class CompactionStatsCollector : public EventListener { class DBCompactionTest : public DBTestBase { public: DBCompactionTest() - : DBTestBase("db_compaction_test", /*env_do_fsync=*/true) {} + : DBTestBase("db_compaction_test", /*env_do_fsync=*/false) {} protected: /* diff --git a/db/db_with_timestamp_test_util.h b/db/db_with_timestamp_test_util.h index 8a0d8e4e31..679e8f9668 100644 --- a/db/db_with_timestamp_test_util.h +++ b/db/db_with_timestamp_test_util.h @@ -17,7 +17,7 @@ namespace ROCKSDB_NAMESPACE { class DBBasicTestWithTimestampBase : public DBTestBase { public: explicit DBBasicTestWithTimestampBase(const std::string& dbname) - : DBTestBase(dbname, /*env_do_fsync=*/true) {} + : DBTestBase(dbname, /*env_do_fsync=*/false) {} protected: static std::string Key1(uint64_t k); diff --git a/env/env_test.cc b/env/env_test.cc index 2f748846b8..abdd38151c 100644 --- a/env/env_test.cc +++ b/env/env_test.cc @@ -67,6 +67,7 @@ #include "utilities/env_timed.h" #include "utilities/fault_injection_env.h" #include "utilities/fault_injection_fs.h" +#include "utilities/nosync_fs.h" namespace ROCKSDB_NAMESPACE { @@ -3339,6 +3340,37 @@ TEST_F(CreateEnvTest, CreateCompositeEnv) { ASSERT_OK(ValidateOptions(db_opts, cf_opts)); } +TEST_F(CreateEnvTest, CreateNoSyncFileSystem) { + std::shared_ptr fs, copy; + auto lib = config_options_.registry->AddLibrary("test"); + test::RegisterTestObjects(*(lib.get()), ""); + ASSERT_OK(FileSystem::CreateFromString(config_options_, + NoSyncFileSystem::kClassName(), &fs)); + ASSERT_NE(fs, nullptr); + ASSERT_STREQ(fs->Name(), NoSyncFileSystem::kClassName()); + ASSERT_EQ(fs->Inner(), FileSystem::Default().get()); + + std::string opts_str = fs->ToString(config_options_); + std::string mismatch; + + ASSERT_OK(FileSystem::CreateFromString(config_options_, opts_str, ©)); + ASSERT_TRUE(fs->AreEquivalent(config_options_, copy.get(), &mismatch)); + + ASSERT_OK(FileSystem::CreateFromString( + config_options_, + std::string("id=") + NoSyncFileSystem::kClassName() + + "; target=" + TimedFileSystem::kClassName(), + &fs)); + ASSERT_NE(fs, nullptr); + opts_str = fs->ToString(config_options_); + ASSERT_STREQ(fs->Name(), NoSyncFileSystem::kClassName()); + ASSERT_NE(fs->Inner(), nullptr); + ASSERT_STREQ(fs->Inner()->Name(), TimedFileSystem::kClassName()); + ASSERT_EQ(fs->Inner()->Inner(), FileSystem::Default().get()); + ASSERT_OK(FileSystem::CreateFromString(config_options_, opts_str, ©)); + ASSERT_TRUE(fs->AreEquivalent(config_options_, copy.get(), &mismatch)); +} + // Forward declaration class ReadAsyncFS; diff --git a/include/rocksdb/file_system.h b/include/rocksdb/file_system.h index 97b21e286e..f725c87a4f 100644 --- a/include/rocksdb/file_system.h +++ b/include/rocksdb/file_system.h @@ -1830,7 +1830,7 @@ class FSDirectoryWrapper : public FSDirectory { return target_->GetUniqueId(id, max_size); } - private: + protected: std::unique_ptr guard_; FSDirectory* target_; }; diff --git a/src.mk b/src.mk index 9cbfc5d45a..93d4cd9d8e 100644 --- a/src.mk +++ b/src.mk @@ -275,6 +275,7 @@ LIB_SOURCES = \ utilities/fault_injection_env.cc \ utilities/fault_injection_fs.cc \ utilities/fault_injection_secondary_cache.cc \ + utilities/injection_fs.cc \ utilities/leveldb_options/leveldb_options.cc \ utilities/memory/memory_util.cc \ utilities/merge_operators.cc \ @@ -285,6 +286,7 @@ LIB_SOURCES = \ utilities/merge_operators/string_append/stringappend2.cc \ utilities/merge_operators/uint64add.cc \ utilities/merge_operators/bytesxor.cc \ + utilities/nosync_fs.cc \ utilities/object_registry.cc \ utilities/option_change_migration/option_change_migration.cc \ utilities/options/options_util.cc \ diff --git a/table/table_test.cc b/table/table_test.cc index df9e508f5e..ccd7067e4e 100644 --- a/table/table_test.cc +++ b/table/table_test.cc @@ -75,6 +75,7 @@ #include "util/string_util.h" #include "utilities/memory_allocators.h" #include "utilities/merge_operators.h" +#include "utilities/nosync_fs.h" namespace ROCKSDB_NAMESPACE { @@ -571,6 +572,8 @@ class DBConstructor : public Constructor { explicit DBConstructor(const Comparator* cmp) : Constructor(cmp), comparator_(cmp) { db_ = nullptr; + std::shared_ptr fs(new NoSyncFileSystem(FileSystem::Default())); + env_ = NewCompositeEnv(fs); NewDB(); } ~DBConstructor() override { delete db_; } @@ -604,6 +607,7 @@ class DBConstructor : public Constructor { Options options; options.comparator = comparator_; + options.env = env_.get(); Status status = DestroyDB(name, options); ASSERT_TRUE(status.ok()) << status.ToString(); @@ -616,6 +620,7 @@ class DBConstructor : public Constructor { const Comparator* comparator_; DB* db_; + std::unique_ptr env_; }; enum TestType { diff --git a/test_util/testutil.cc b/test_util/testutil.cc index 031104a7b5..22cedf7faf 100644 --- a/test_util/testutil.cc +++ b/test_util/testutil.cc @@ -29,6 +29,7 @@ #include "test_util/mock_time_env.h" #include "test_util/sync_point.h" #include "util/random.h" +#include "utilities/nosync_fs.h" #ifndef ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS void RegisterCustomObjects(int /*argc*/, char** /*argv*/) {} @@ -707,6 +708,13 @@ int RegisterTestObjects(ObjectLibrary& library, const std::string& arg) { guard->reset(new MockSystemClock(SystemClock::Default())); return guard->get(); }); + library.AddFactory( + NoSyncFileSystem::kClassName(), + [](const std::string& /*uri*/, std::unique_ptr* guard, + std::string* /* errmsg */) { + guard->reset(new NoSyncFileSystem(FileSystem::Default())); + return guard->get(); + }); return static_cast(library.GetFactoryCount(&num_types)); } diff --git a/utilities/counted_fs.cc b/utilities/counted_fs.cc index e43f3a1912..a45e44a1ac 100644 --- a/utilities/counted_fs.cc +++ b/utilities/counted_fs.cc @@ -11,249 +11,6 @@ #include "rocksdb/utilities/options_type.h" namespace ROCKSDB_NAMESPACE { -namespace { -class CountedSequentialFile : public FSSequentialFileOwnerWrapper { - private: - CountedFileSystem* fs_; - - public: - CountedSequentialFile(std::unique_ptr&& f, - CountedFileSystem* fs) - : FSSequentialFileOwnerWrapper(std::move(f)), fs_(fs) {} - - ~CountedSequentialFile() override { fs_->counters()->closes++; } - - IOStatus Read(size_t n, const IOOptions& options, Slice* result, - char* scratch, IODebugContext* dbg) override { - IOStatus rv = target()->Read(n, options, result, scratch, dbg); - fs_->counters()->reads.RecordOp(rv, result->size()); - return rv; - } - - IOStatus PositionedRead(uint64_t offset, size_t n, const IOOptions& options, - Slice* result, char* scratch, - IODebugContext* dbg) override { - IOStatus rv = - target()->PositionedRead(offset, n, options, result, scratch, dbg); - fs_->counters()->reads.RecordOp(rv, result->size()); - return rv; - } -}; - -class CountedRandomAccessFile : public FSRandomAccessFileOwnerWrapper { - private: - CountedFileSystem* fs_; - - public: - CountedRandomAccessFile(std::unique_ptr&& f, - CountedFileSystem* fs) - : FSRandomAccessFileOwnerWrapper(std::move(f)), fs_(fs) {} - - ~CountedRandomAccessFile() override { fs_->counters()->closes++; } - - IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, - Slice* result, char* scratch, - IODebugContext* dbg) const override { - IOStatus rv = target()->Read(offset, n, options, result, scratch, dbg); - fs_->counters()->reads.RecordOp(rv, result->size()); - return rv; - } - - IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs, - const IOOptions& options, IODebugContext* dbg) override { - IOStatus rv = target()->MultiRead(reqs, num_reqs, options, dbg); - for (size_t r = 0; r < num_reqs; r++) { - fs_->counters()->reads.RecordOp(reqs[r].status, reqs[r].result.size()); - } - return rv; - } -}; - -class CountedWritableFile : public FSWritableFileOwnerWrapper { - private: - CountedFileSystem* fs_; - - public: - CountedWritableFile(std::unique_ptr&& f, - CountedFileSystem* fs) - : FSWritableFileOwnerWrapper(std::move(f)), fs_(fs) {} - - IOStatus Append(const Slice& data, const IOOptions& options, - IODebugContext* dbg) override { - IOStatus rv = target()->Append(data, options, dbg); - fs_->counters()->writes.RecordOp(rv, data.size()); - return rv; - } - - IOStatus Append(const Slice& data, const IOOptions& options, - const DataVerificationInfo& info, - IODebugContext* dbg) override { - IOStatus rv = target()->Append(data, options, info, dbg); - fs_->counters()->writes.RecordOp(rv, data.size()); - return rv; - } - - IOStatus PositionedAppend(const Slice& data, uint64_t offset, - const IOOptions& options, - IODebugContext* dbg) override { - IOStatus rv = target()->PositionedAppend(data, offset, options, dbg); - fs_->counters()->writes.RecordOp(rv, data.size()); - return rv; - } - - IOStatus PositionedAppend(const Slice& data, uint64_t offset, - const IOOptions& options, - const DataVerificationInfo& info, - IODebugContext* dbg) override { - IOStatus rv = target()->PositionedAppend(data, offset, options, info, dbg); - fs_->counters()->writes.RecordOp(rv, data.size()); - return rv; - } - - IOStatus Close(const IOOptions& options, IODebugContext* dbg) override { - IOStatus rv = target()->Close(options, dbg); - if (rv.ok()) { - fs_->counters()->closes++; - } - return rv; - } - - IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override { - IOStatus rv = target()->Flush(options, dbg); - if (rv.ok()) { - fs_->counters()->flushes++; - } - return rv; - } - - IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override { - IOStatus rv = target()->Sync(options, dbg); - if (rv.ok()) { - fs_->counters()->syncs++; - } - return rv; - } - - IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override { - IOStatus rv = target()->Fsync(options, dbg); - if (rv.ok()) { - fs_->counters()->fsyncs++; - } - return rv; - } - - IOStatus RangeSync(uint64_t offset, uint64_t nbytes, const IOOptions& options, - IODebugContext* dbg) override { - IOStatus rv = target()->RangeSync(offset, nbytes, options, dbg); - if (rv.ok()) { - fs_->counters()->syncs++; - } - return rv; - } -}; - -class CountedRandomRWFile : public FSRandomRWFileOwnerWrapper { - private: - mutable CountedFileSystem* fs_; - - public: - CountedRandomRWFile(std::unique_ptr&& f, - CountedFileSystem* fs) - : FSRandomRWFileOwnerWrapper(std::move(f)), fs_(fs) {} - IOStatus Write(uint64_t offset, const Slice& data, const IOOptions& options, - IODebugContext* dbg) override { - IOStatus rv = target()->Write(offset, data, options, dbg); - fs_->counters()->writes.RecordOp(rv, data.size()); - return rv; - } - - IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, - Slice* result, char* scratch, - IODebugContext* dbg) const override { - IOStatus rv = target()->Read(offset, n, options, result, scratch, dbg); - fs_->counters()->reads.RecordOp(rv, result->size()); - return rv; - } - - IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override { - IOStatus rv = target()->Flush(options, dbg); - if (rv.ok()) { - fs_->counters()->flushes++; - } - return rv; - } - - IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override { - IOStatus rv = target()->Sync(options, dbg); - if (rv.ok()) { - fs_->counters()->syncs++; - } - return rv; - } - - IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override { - IOStatus rv = target()->Fsync(options, dbg); - if (rv.ok()) { - fs_->counters()->fsyncs++; - } - return rv; - } - - IOStatus Close(const IOOptions& options, IODebugContext* dbg) override { - IOStatus rv = target()->Close(options, dbg); - if (rv.ok()) { - fs_->counters()->closes++; - } - return rv; - } -}; - -class CountedDirectory : public FSDirectoryWrapper { - private: - mutable CountedFileSystem* fs_; - bool closed_ = false; - - public: - CountedDirectory(std::unique_ptr&& f, CountedFileSystem* fs) - : FSDirectoryWrapper(std::move(f)), fs_(fs) {} - - IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override { - IOStatus rv = FSDirectoryWrapper::Fsync(options, dbg); - if (rv.ok()) { - fs_->counters()->dsyncs++; - } - return rv; - } - - IOStatus Close(const IOOptions& options, IODebugContext* dbg) override { - IOStatus rv = FSDirectoryWrapper::Close(options, dbg); - if (rv.ok()) { - fs_->counters()->closes++; - fs_->counters()->dir_closes++; - closed_ = true; - } - return rv; - } - - IOStatus FsyncWithDirOptions(const IOOptions& options, IODebugContext* dbg, - const DirFsyncOptions& dir_options) override { - IOStatus rv = - FSDirectoryWrapper::FsyncWithDirOptions(options, dbg, dir_options); - if (rv.ok()) { - fs_->counters()->dsyncs++; - } - return rv; - } - - ~CountedDirectory() { - if (!closed_) { - // TODO: fix DB+CF code to use explicit Close, not rely on destructor - fs_->counters()->closes++; - fs_->counters()->dir_closes++; - } - } -}; -} // anonymous namespace std::string FileOpCounters::PrintCounters() const { std::stringstream ss; @@ -285,16 +42,14 @@ std::string FileOpCounters::PrintCounters() const { } CountedFileSystem::CountedFileSystem(const std::shared_ptr& base) - : FileSystemWrapper(base) {} + : InjectionFileSystem(base) {} IOStatus CountedFileSystem::NewSequentialFile( const std::string& f, const FileOptions& options, std::unique_ptr* r, IODebugContext* dbg) { - std::unique_ptr base; - IOStatus s = target()->NewSequentialFile(f, options, &base, dbg); + IOStatus s = InjectionFileSystem::NewSequentialFile(f, options, r, dbg); if (s.ok()) { counters_.opens++; - r->reset(new CountedSequentialFile(std::move(base), this)); } return s; } @@ -302,11 +57,9 @@ IOStatus CountedFileSystem::NewSequentialFile( IOStatus CountedFileSystem::NewRandomAccessFile( const std::string& f, const FileOptions& options, std::unique_ptr* r, IODebugContext* dbg) { - std::unique_ptr base; - IOStatus s = target()->NewRandomAccessFile(f, options, &base, dbg); + IOStatus s = InjectionFileSystem::NewRandomAccessFile(f, options, r, dbg); if (s.ok()) { counters_.opens++; - r->reset(new CountedRandomAccessFile(std::move(base), this)); } return s; } @@ -315,11 +68,9 @@ IOStatus CountedFileSystem::NewWritableFile(const std::string& f, const FileOptions& options, std::unique_ptr* r, IODebugContext* dbg) { - std::unique_ptr base; - IOStatus s = target()->NewWritableFile(f, options, &base, dbg); + IOStatus s = InjectionFileSystem::NewWritableFile(f, options, r, dbg); if (s.ok()) { counters_.opens++; - r->reset(new CountedWritableFile(std::move(base), this)); } return s; } @@ -327,11 +78,10 @@ IOStatus CountedFileSystem::NewWritableFile(const std::string& f, IOStatus CountedFileSystem::ReopenWritableFile( const std::string& fname, const FileOptions& options, std::unique_ptr* result, IODebugContext* dbg) { - std::unique_ptr base; - IOStatus s = target()->ReopenWritableFile(fname, options, &base, dbg); + IOStatus s = + InjectionFileSystem::ReopenWritableFile(fname, options, result, dbg); if (s.ok()) { counters_.opens++; - result->reset(new CountedWritableFile(std::move(base), this)); } return s; } @@ -340,12 +90,10 @@ IOStatus CountedFileSystem::ReuseWritableFile( const std::string& fname, const std::string& old_fname, const FileOptions& options, std::unique_ptr* result, IODebugContext* dbg) { - std::unique_ptr base; - IOStatus s = - target()->ReuseWritableFile(fname, old_fname, options, &base, dbg); + IOStatus s = InjectionFileSystem::ReuseWritableFile(fname, old_fname, options, + result, dbg); if (s.ok()) { counters_.opens++; - result->reset(new CountedWritableFile(std::move(base), this)); } return s; } @@ -353,11 +101,9 @@ IOStatus CountedFileSystem::ReuseWritableFile( IOStatus CountedFileSystem::NewRandomRWFile( const std::string& name, const FileOptions& options, std::unique_ptr* result, IODebugContext* dbg) { - std::unique_ptr base; - IOStatus s = target()->NewRandomRWFile(name, options, &base, dbg); + IOStatus s = InjectionFileSystem::NewRandomRWFile(name, options, result, dbg); if (s.ok()) { counters_.opens++; - result->reset(new CountedRandomRWFile(std::move(base), this)); } return s; } @@ -366,12 +112,10 @@ IOStatus CountedFileSystem::NewDirectory(const std::string& name, const IOOptions& options, std::unique_ptr* result, IODebugContext* dbg) { - std::unique_ptr base; - IOStatus s = target()->NewDirectory(name, options, &base, dbg); + IOStatus s = InjectionFileSystem::NewDirectory(name, options, result, dbg); if (s.ok()) { counters_.opens++; counters_.dir_opens++; - result->reset(new CountedDirectory(std::move(base), this)); } return s; } diff --git a/utilities/counted_fs.h b/utilities/counted_fs.h index cb8a8968fb..5cad37c834 100644 --- a/utilities/counted_fs.h +++ b/utilities/counted_fs.h @@ -11,6 +11,7 @@ #include "rocksdb/file_system.h" #include "rocksdb/io_status.h" #include "rocksdb/rocksdb_namespace.h" +#include "utilities/injection_fs.h" namespace ROCKSDB_NAMESPACE { class Logger; @@ -81,7 +82,7 @@ struct FileOpCounters { }; // A FileSystem class that counts operations (reads, writes, opens, closes, etc) -class CountedFileSystem : public FileSystemWrapper { +class CountedFileSystem : public InjectionFileSystem { public: private: FileOpCounters counters_; @@ -154,5 +155,215 @@ class CountedFileSystem : public FileSystemWrapper { // Prints the counters to a string std::string PrintCounters() const { return counters_.PrintCounters(); } void ResetCounters() { counters_.Reset(); } + + protected: + IOStatus DoRead(FSSequentialFile* file, size_t n, const IOOptions& options, + Slice* result, char* scratch, IODebugContext* dbg) override { + auto rv = + InjectionFileSystem::DoRead(file, n, options, result, scratch, dbg); + counters_.reads.RecordOp(rv, result->size()); + return rv; + } + + IOStatus DoPositionedRead(FSSequentialFile* file, uint64_t offset, size_t n, + const IOOptions& options, Slice* result, + char* scratch, IODebugContext* dbg) override { + auto rv = InjectionFileSystem::DoPositionedRead(file, offset, n, options, + result, scratch, dbg); + counters_.reads.RecordOp(rv, result->size()); + return rv; + } + void DoClose(FSSequentialFile* file) override { + InjectionFileSystem::DoClose(file); + counters_.closes++; + } + + IOStatus DoRead(FSRandomAccessFile* file, uint64_t offset, size_t n, + const IOOptions& options, Slice* result, char* scratch, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoRead(file, offset, n, options, result, + scratch, dbg); + counters_.reads.RecordOp(rv, result->size()); + return rv; + } + + IOStatus DoMultiRead(FSRandomAccessFile* file, FSReadRequest* reqs, + size_t num_reqs, const IOOptions& options, + IODebugContext* dbg) override { + IOStatus rv = + InjectionFileSystem::DoMultiRead(file, reqs, num_reqs, options, dbg); + for (size_t r = 0; r < num_reqs; r++) { + counters_.reads.RecordOp(reqs[r].status, reqs[r].result.size()); + } + return rv; + } + + void DoClose(FSRandomAccessFile* file) override { + InjectionFileSystem::DoClose(file); + counters_.closes++; + } + + IOStatus DoAppend(FSWritableFile* file, const Slice& data, + const IOOptions& options, IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoAppend(file, data, options, dbg); + counters_.writes.RecordOp(rv, data.size()); + return rv; + } + + IOStatus DoAppend(FSWritableFile* file, const Slice& data, + const IOOptions& options, const DataVerificationInfo& info, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoAppend(file, data, options, info, dbg); + counters_.writes.RecordOp(rv, data.size()); + return rv; + } + + IOStatus DoPositionedAppend(FSWritableFile* file, const Slice& data, + uint64_t offset, const IOOptions& options, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoPositionedAppend(file, data, offset, + options, dbg); + counters_.writes.RecordOp(rv, data.size()); + return rv; + } + + IOStatus DoPositionedAppend(FSWritableFile* file, const Slice& data, + uint64_t offset, const IOOptions& options, + const DataVerificationInfo& info, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoPositionedAppend(file, data, offset, + options, info, dbg); + counters_.writes.RecordOp(rv, data.size()); + return rv; + } + + IOStatus DoClose(FSWritableFile* file, const IOOptions& options, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoClose(file, options, dbg); + if (rv.ok()) { + counters_.closes++; + } + return rv; + } + + IOStatus DoFlush(FSWritableFile* file, const IOOptions& options, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoFlush(file, options, dbg); + if (rv.ok()) { + counters_.flushes++; + } + return rv; + } + + IOStatus DoSync(FSWritableFile* file, const IOOptions& options, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoSync(file, options, dbg); + if (rv.ok()) { + counters_.syncs++; + } + return rv; + } + + IOStatus DoFsync(FSWritableFile* file, const IOOptions& options, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoFsync(file, options, dbg); + if (rv.ok()) { + counters_.fsyncs++; + } + return rv; + } + + IOStatus DoRangeSync(FSWritableFile* file, uint64_t offset, uint64_t nbytes, + const IOOptions& options, IODebugContext* dbg) override { + IOStatus rv = + InjectionFileSystem::DoRangeSync(file, offset, nbytes, options, dbg); + if (rv.ok()) { + counters_.syncs++; + } + return rv; + } + + IOStatus DoWrite(FSRandomRWFile* file, uint64_t offset, const Slice& data, + const IOOptions& options, IODebugContext* dbg) override { + IOStatus rv = + InjectionFileSystem::DoWrite(file, offset, data, options, dbg); + counters_.writes.RecordOp(rv, data.size()); + return rv; + } + + IOStatus DoRead(FSRandomRWFile* file, uint64_t offset, size_t n, + const IOOptions& options, Slice* result, char* scratch, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoRead(file, offset, n, options, result, + scratch, dbg); + counters_.reads.RecordOp(rv, result->size()); + return rv; + } + + IOStatus DoFlush(FSRandomRWFile* file, const IOOptions& options, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoFlush(file, options, dbg); + if (rv.ok()) { + counters_.flushes++; + } + return rv; + } + + IOStatus DoSync(FSRandomRWFile* file, const IOOptions& options, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoSync(file, options, dbg); + if (rv.ok()) { + counters_.syncs++; + } + return rv; + } + + IOStatus DoFsync(FSRandomRWFile* file, const IOOptions& options, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoFsync(file, options, dbg); + if (rv.ok()) { + counters_.fsyncs++; + } + return rv; + } + + IOStatus DoClose(FSRandomRWFile* file, const IOOptions& options, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoClose(file, options, dbg); + if (rv.ok()) { + counters_.closes++; + } + return rv; + } + + IOStatus DoFsync(FSDirectory* dir, const IOOptions& options, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoFsync(dir, options, dbg); + if (rv.ok()) { + counters_.dsyncs++; + } + return rv; + } + + IOStatus DoFsyncWithDirOptions(FSDirectory* dir, const IOOptions& options, + IODebugContext* dbg, + const DirFsyncOptions& dir_options) override { + IOStatus rv = InjectionFileSystem::DoFsyncWithDirOptions(dir, options, dbg, + dir_options); + if (rv.ok()) { + counters_.dsyncs++; + } + return rv; + } + + IOStatus DoClose(FSDirectory* dir, const IOOptions& options, + IODebugContext* dbg) override { + IOStatus rv = InjectionFileSystem::DoClose(dir, options, dbg); + if (rv.ok()) { + counters_.closes++; + counters_.dir_closes++; + } + return rv; + } }; } // namespace ROCKSDB_NAMESPACE diff --git a/utilities/fault_injection_fs.cc b/utilities/fault_injection_fs.cc index 5523530926..2bd2384060 100644 --- a/utilities/fault_injection_fs.cc +++ b/utilities/fault_injection_fs.cc @@ -83,11 +83,9 @@ IOStatus FSFileState::DropUnsyncedData() { } IOStatus FSFileState::DropRandomUnsyncedData(Random* rand) { - const int range = static_cast(buffer_.size()); - if (range > 0) { - size_t truncated_size = static_cast(rand->Uniform(range)); - buffer_.resize(truncated_size); - } + int range = static_cast(buffer_.size()); + size_t truncated_size = static_cast(rand->Uniform(range)); + buffer_.resize(truncated_size); return IOStatus::OK(); } @@ -103,7 +101,7 @@ IOStatus TestFSDirectory::Fsync(const IOOptions& options, IODebugContext* dbg) { } fs_->SyncDir(dirname_); IOStatus s = dir_->Fsync(options, dbg); - { + if (s.ok()) { IOStatus in_s = fs_->InjectMetadataWriteError(); if (!in_s.ok()) { return in_s; @@ -134,7 +132,7 @@ IOStatus TestFSDirectory::FsyncWithDirOptions( } fs_->SyncDir(dirname_); IOStatus s = dir_->FsyncWithDirOptions(options, dbg, dir_fsync_options); - { + if (s.ok()) { IOStatus in_s = fs_->InjectMetadataWriteError(); if (!in_s.ok()) { return in_s; @@ -305,6 +303,17 @@ IOStatus TestFSWritableFile::Sync(const IOOptions& options, return io_s; } +IOStatus FaultInjectionTestFS::DoWrite(FSRandomRWFile* file, uint64_t offset, + const Slice& data, + const IOOptions& options, + IODebugContext* dbg) { + if (!IsFilesystemActive()) { + return GetError(); + } else { + return file->Write(offset, data, options, dbg); + } +} + IOStatus TestFSWritableFile::RangeSync(uint64_t offset, uint64_t nbytes, const IOOptions& options, IODebugContext* dbg) { @@ -333,108 +342,86 @@ IOStatus TestFSWritableFile::RangeSync(uint64_t offset, uint64_t nbytes, return io_s; } -TestFSRandomRWFile::TestFSRandomRWFile(const std::string& /*fname*/, - std::unique_ptr&& f, - FaultInjectionTestFS* fs) - : target_(std::move(f)), file_opened_(true), fs_(fs) { - assert(target_ != nullptr); -} - -TestFSRandomRWFile::~TestFSRandomRWFile() { - if (file_opened_) { - Close(IOOptions(), nullptr).PermitUncheckedError(); - } -} - -IOStatus TestFSRandomRWFile::Write(uint64_t offset, const Slice& data, - const IOOptions& options, - IODebugContext* dbg) { - if (!fs_->IsFilesystemActive()) { - return fs_->GetError(); - } - return target_->Write(offset, data, options, dbg); -} - -IOStatus TestFSRandomRWFile::Read(uint64_t offset, size_t n, - const IOOptions& options, Slice* result, - char* scratch, IODebugContext* dbg) const { - if (!fs_->IsFilesystemActive()) { - return fs_->GetError(); +IOStatus FaultInjectionTestFS::DoRead(FSRandomRWFile* file, uint64_t offset, + size_t n, const IOOptions& options, + Slice* result, char* scratch, + IODebugContext* dbg) { + if (!IsFilesystemActive()) { + return GetError(); + } else { + return file->Read(offset, n, options, result, scratch, dbg); } - return target_->Read(offset, n, options, result, scratch, dbg); } -IOStatus TestFSRandomRWFile::Close(const IOOptions& options, - IODebugContext* dbg) { - if (!fs_->IsFilesystemActive()) { - return fs_->GetError(); +IOStatus FaultInjectionTestFS::DoClose(FSRandomRWFile* file, + const IOOptions& options, + IODebugContext* dbg) { + if (!IsFilesystemActive()) { + return GetError(); + } else { + return file->Close(options, dbg); } - file_opened_ = false; - return target_->Close(options, dbg); } - -IOStatus TestFSRandomRWFile::Flush(const IOOptions& options, - IODebugContext* dbg) { - if (!fs_->IsFilesystemActive()) { - return fs_->GetError(); +IOStatus FaultInjectionTestFS::DoFlush(FSRandomRWFile* file, + const IOOptions& options, + IODebugContext* dbg) { + if (!IsFilesystemActive()) { + return GetError(); + } else { + return file->Flush(options, dbg); } - return target_->Flush(options, dbg); } -IOStatus TestFSRandomRWFile::Sync(const IOOptions& options, - IODebugContext* dbg) { - if (!fs_->IsFilesystemActive()) { - return fs_->GetError(); +IOStatus FaultInjectionTestFS::DoSync(FSRandomRWFile* file, + const IOOptions& options, + IODebugContext* dbg) { + if (!IsFilesystemActive()) { + return GetError(); + } else { + return file->Sync(options, dbg); } - return target_->Sync(options, dbg); } -TestFSRandomAccessFile::TestFSRandomAccessFile( - const std::string& /*fname*/, std::unique_ptr&& f, - FaultInjectionTestFS* fs) - : target_(std::move(f)), fs_(fs) { - assert(target_ != nullptr); -} - -IOStatus TestFSRandomAccessFile::Read(uint64_t offset, size_t n, - const IOOptions& options, Slice* result, - char* scratch, - IODebugContext* dbg) const { - if (!fs_->IsFilesystemActive()) { - return fs_->GetError(); +IOStatus FaultInjectionTestFS::DoRead(FSRandomAccessFile* file, uint64_t offset, + size_t n, const IOOptions& options, + Slice* result, char* scratch, + IODebugContext* dbg) { + if (!IsFilesystemActive()) { + return GetError(); } - IOStatus s = target_->Read(offset, n, options, result, scratch, dbg); + IOStatus s = file->Read(offset, n, options, result, scratch, dbg); if (s.ok()) { - s = fs_->InjectThreadSpecificReadError( - FaultInjectionTestFS::ErrorOperation::kRead, result, use_direct_io(), - scratch, /*need_count_increase=*/true, /*fault_injected=*/nullptr); + s = InjectThreadSpecificReadError( + FaultInjectionTestFS::ErrorOperation::kRead, result, + file->use_direct_io(), scratch, /*need_count_increase=*/true, + /*fault_injected=*/nullptr); } - if (s.ok() && fs_->ShouldInjectRandomReadError()) { + if (s.ok() && ShouldInjectRandomReadError()) { return IOStatus::IOError("Injected read error"); } return s; } -IOStatus TestFSRandomAccessFile::ReadAsync( - FSReadRequest& req, const IOOptions& opts, +IOStatus FaultInjectionTestFS::DoReadAsync( + FSRandomAccessFile* file, FSReadRequest& req, const IOOptions& opts, std::function cb, void* cb_arg, - void** io_handle, IOHandleDeleter* del_fn, IODebugContext* /*dbg*/) { + void** io_handle, IOHandleDeleter* del_fn, IODebugContext* dbg) { IOStatus ret; IOStatus s; FSReadRequest res; - if (!fs_->IsFilesystemActive()) { - ret = fs_->GetError(); + if (!IsFilesystemActive()) { + ret = GetError(); } else { - ret = fs_->InjectThreadSpecificReadError( + ret = InjectThreadSpecificReadError( FaultInjectionTestFS::ErrorOperation::kRead, &res.result, - use_direct_io(), req.scratch, /*need_count_increase=*/true, + file->use_direct_io(), req.scratch, /*need_count_increase=*/true, /*fault_injected=*/nullptr); } if (ret.ok()) { - if (fs_->ShouldInjectRandomReadError()) { + if (ShouldInjectRandomReadError()) { ret = IOStatus::IOError("Injected read error"); } else { - s = target_->ReadAsync(req, opts, cb, cb_arg, io_handle, del_fn, nullptr); + s = file->ReadAsync(req, opts, cb, cb_arg, io_handle, del_fn, dbg); } } if (!ret.ok()) { @@ -444,13 +431,14 @@ IOStatus TestFSRandomAccessFile::ReadAsync( return s; } -IOStatus TestFSRandomAccessFile::MultiRead(FSReadRequest* reqs, size_t num_reqs, +IOStatus FaultInjectionTestFS::DoMultiRead(FSRandomAccessFile* file, + FSReadRequest* reqs, size_t num_reqs, const IOOptions& options, IODebugContext* dbg) { - if (!fs_->IsFilesystemActive()) { - return fs_->GetError(); + if (!IsFilesystemActive()) { + return GetError(); } - IOStatus s = target_->MultiRead(reqs, num_reqs, options, dbg); + IOStatus s = file->MultiRead(reqs, num_reqs, options, dbg); bool injected_error = false; for (size_t i = 0; i < num_reqs; i++) { if (!reqs[i].status.ok()) { @@ -458,49 +446,51 @@ IOStatus TestFSRandomAccessFile::MultiRead(FSReadRequest* reqs, size_t num_reqs, break; } bool this_injected_error; - reqs[i].status = fs_->InjectThreadSpecificReadError( + reqs[i].status = InjectThreadSpecificReadError( FaultInjectionTestFS::ErrorOperation::kMultiReadSingleReq, - &(reqs[i].result), use_direct_io(), reqs[i].scratch, + &(reqs[i].result), file->use_direct_io(), reqs[i].scratch, /*need_count_increase=*/true, /*fault_injected=*/&this_injected_error); injected_error |= this_injected_error; } if (s.ok()) { - s = fs_->InjectThreadSpecificReadError( + s = InjectThreadSpecificReadError( FaultInjectionTestFS::ErrorOperation::kMultiRead, nullptr, - use_direct_io(), nullptr, /*need_count_increase=*/!injected_error, + file->use_direct_io(), nullptr, /*need_count_increase=*/!injected_error, /*fault_injected=*/nullptr); } - if (s.ok() && fs_->ShouldInjectRandomReadError()) { + if (s.ok() && ShouldInjectRandomReadError()) { return IOStatus::IOError("Injected read error"); } return s; } -size_t TestFSRandomAccessFile::GetUniqueId(char* id, size_t max_size) const { - if (fs_->ShouldFailGetUniqueId()) { +size_t FaultInjectionTestFS::DoGetUniqueId(FSRandomAccessFile* file, char* id, + size_t max_size) { + if (ShouldFailGetUniqueId()) { return 0; } else { - return target_->GetUniqueId(id, max_size); + return file->GetUniqueId(id, max_size); } } -IOStatus TestFSSequentialFile::Read(size_t n, const IOOptions& options, - Slice* result, char* scratch, - IODebugContext* dbg) { - IOStatus s = target()->Read(n, options, result, scratch, dbg); - if (s.ok() && fs_->ShouldInjectRandomReadError()) { + +IOStatus FaultInjectionTestFS::DoRead(FSSequentialFile* file, size_t n, + const IOOptions& options, Slice* result, + char* scratch, IODebugContext* dbg) { + IOStatus s = file->Read(n, options, result, scratch, dbg); + if (s.ok() && ShouldInjectRandomReadError()) { return IOStatus::IOError("Injected seq read error"); } return s; } -IOStatus TestFSSequentialFile::PositionedRead(uint64_t offset, size_t n, - const IOOptions& options, - Slice* result, char* scratch, - IODebugContext* dbg) { - IOStatus s = - target()->PositionedRead(offset, n, options, result, scratch, dbg); - if (s.ok() && fs_->ShouldInjectRandomReadError()) { +IOStatus FaultInjectionTestFS::DoPositionedRead(FSSequentialFile* file, + uint64_t offset, size_t n, + const IOOptions& options, + Slice* result, char* scratch, + IODebugContext* dbg) { + IOStatus s = file->PositionedRead(offset, n, options, result, scratch, dbg); + if (s.ok() && ShouldInjectRandomReadError()) { return IOStatus::IOError("Injected seq positioned read error"); } return s; @@ -532,7 +522,7 @@ IOStatus FaultInjectionTestFS::NewWritableFile( } } - if (ShouldUseDiretWritable(fname)) { + if (ShouldUseDirectWritable(fname)) { return target()->NewWritableFile(fname, file_opts, result, dbg); } @@ -569,7 +559,7 @@ IOStatus FaultInjectionTestFS::ReopenWritableFile( if (!IsFilesystemActive()) { return GetError(); } - if (ShouldUseDiretWritable(fname)) { + if (ShouldUseDirectWritable(fname)) { return target()->ReopenWritableFile(fname, file_opts, result, dbg); } { @@ -639,18 +629,17 @@ IOStatus FaultInjectionTestFS::NewRandomRWFile( if (!IsFilesystemActive()) { return GetError(); } - if (ShouldUseDiretWritable(fname)) { + if (ShouldUseDirectWritable(fname)) { return target()->NewRandomRWFile(fname, file_opts, result, dbg); - } - { + } else { IOStatus in_s = InjectMetadataWriteError(); if (!in_s.ok()) { return in_s; } } - IOStatus io_s = target()->NewRandomRWFile(fname, file_opts, result, dbg); + IOStatus io_s = + InjectionFileSystem::NewRandomRWFile(fname, file_opts, result, dbg); if (io_s.ok()) { - result->reset(new TestFSRandomRWFile(fname, std::move(*result), this)); // WritableFileWriter* file is opened // again then it will be truncated - so forget our saved state. UntrackFile(fname); @@ -687,10 +676,8 @@ IOStatus FaultInjectionTestFS::NewRandomAccessFile( /*need_count_increase=*/true, /*fault_injected=*/nullptr); if (io_s.ok()) { - io_s = target()->NewRandomAccessFile(fname, file_opts, result, dbg); - } - if (io_s.ok()) { - result->reset(new TestFSRandomAccessFile(fname, std::move(*result), this)); + io_s = + InjectionFileSystem::NewRandomAccessFile(fname, file_opts, result, dbg); } return io_s; } @@ -700,16 +687,12 @@ IOStatus FaultInjectionTestFS::NewSequentialFile( std::unique_ptr* result, IODebugContext* dbg) { if (!IsFilesystemActive()) { return GetError(); - } - - if (ShouldInjectRandomReadError()) { + } else if (ShouldInjectRandomReadError()) { return IOStatus::IOError("Injected read error when creating seq file"); + } else { + return InjectionFileSystem::NewSequentialFile(fname, file_opts, result, + dbg); } - IOStatus io_s = target()->NewSequentialFile(fname, file_opts, result, dbg); - if (io_s.ok()) { - result->reset(new TestFSSequentialFile(std::move(*result), this)); - } - return io_s; } IOStatus FaultInjectionTestFS::DeleteFile(const std::string& f, @@ -724,7 +707,7 @@ IOStatus FaultInjectionTestFS::DeleteFile(const std::string& f, return in_s; } } - IOStatus io_s = FileSystemWrapper::DeleteFile(f, options, dbg); + IOStatus io_s = InjectionFileSystem::DeleteFile(f, options, dbg); if (io_s.ok()) { UntrackFile(f); { @@ -763,7 +746,7 @@ IOStatus FaultInjectionTestFS::RenameFile(const std::string& s, ReadFileToString(target(), t, &previous_contents).PermitUncheckedError(); } } - IOStatus io_s = FileSystemWrapper::RenameFile(s, t, options, dbg); + IOStatus io_s = InjectionFileSystem::RenameFile(s, t, options, dbg); if (io_s.ok()) { { @@ -808,7 +791,7 @@ IOStatus FaultInjectionTestFS::LinkFile(const std::string& s, // may be a more reasonable choice. std::string previous_contents = kNewFileNoOverwrite; - IOStatus io_s = FileSystemWrapper::LinkFile(s, t, options, dbg); + IOStatus io_s = InjectionFileSystem::LinkFile(s, t, options, dbg); if (io_s.ok()) { { diff --git a/utilities/fault_injection_fs.h b/utilities/fault_injection_fs.h index cab0051bd1..df5091e861 100644 --- a/utilities/fault_injection_fs.h +++ b/utilities/fault_injection_fs.h @@ -26,6 +26,7 @@ #include "util/mutexlock.h" #include "util/random.h" #include "util/thread_local.h" +#include "utilities/injection_fs.h" namespace ROCKSDB_NAMESPACE { @@ -105,75 +106,6 @@ class TestFSWritableFile : public FSWritableFile { port::Mutex mutex_; }; -// A wrapper around WritableFileWriter* file -// is written to or sync'ed. -class TestFSRandomRWFile : public FSRandomRWFile { - public: - explicit TestFSRandomRWFile(const std::string& fname, - std::unique_ptr&& f, - FaultInjectionTestFS* fs); - virtual ~TestFSRandomRWFile(); - IOStatus Write(uint64_t offset, const Slice& data, const IOOptions& options, - IODebugContext* dbg) override; - IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, - Slice* result, char* scratch, - IODebugContext* dbg) const override; - IOStatus Close(const IOOptions& options, IODebugContext* dbg) override; - IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override; - IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override; - size_t GetRequiredBufferAlignment() const override { - return target_->GetRequiredBufferAlignment(); - } - bool use_direct_io() const override { return target_->use_direct_io(); }; - - private: - std::unique_ptr target_; - bool file_opened_; - FaultInjectionTestFS* fs_; -}; - -class TestFSRandomAccessFile : public FSRandomAccessFile { - public: - explicit TestFSRandomAccessFile(const std::string& fname, - std::unique_ptr&& f, - FaultInjectionTestFS* fs); - ~TestFSRandomAccessFile() override {} - IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, - Slice* result, char* scratch, - IODebugContext* dbg) const override; - IOStatus ReadAsync(FSReadRequest& req, const IOOptions& opts, - std::function cb, - void* cb_arg, void** io_handle, IOHandleDeleter* del_fn, - IODebugContext* dbg) override; - IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs, - const IOOptions& options, IODebugContext* dbg) override; - size_t GetRequiredBufferAlignment() const override { - return target_->GetRequiredBufferAlignment(); - } - bool use_direct_io() const override { return target_->use_direct_io(); } - - size_t GetUniqueId(char* id, size_t max_size) const override; - - private: - std::unique_ptr target_; - FaultInjectionTestFS* fs_; -}; - -class TestFSSequentialFile : public FSSequentialFileOwnerWrapper { - public: - explicit TestFSSequentialFile(std::unique_ptr&& f, - FaultInjectionTestFS* fs) - : FSSequentialFileOwnerWrapper(std::move(f)), fs_(fs) {} - IOStatus Read(size_t n, const IOOptions& options, Slice* result, - char* scratch, IODebugContext* dbg) override; - IOStatus PositionedRead(uint64_t offset, size_t n, const IOOptions& options, - Slice* result, char* scratch, - IODebugContext* dbg) override; - - private: - FaultInjectionTestFS* fs_; -}; - class TestFSDirectory : public FSDirectory { public: explicit TestFSDirectory(FaultInjectionTestFS* fs, std::string dirname, @@ -197,10 +129,10 @@ class TestFSDirectory : public FSDirectory { std::unique_ptr dir_; }; -class FaultInjectionTestFS : public FileSystemWrapper { +class FaultInjectionTestFS : public InjectionFileSystem { public: explicit FaultInjectionTestFS(const std::shared_ptr& base) - : FileSystemWrapper(base), + : InjectionFileSystem(base), filesystem_active_(true), filesystem_writable_(false), thread_local_error_(new ThreadLocalPtr(DeleteThreadLocalErrorContext)), @@ -313,7 +245,7 @@ class FaultInjectionTestFS : public FileSystemWrapper { MutexLock l(&mutex_); return filesystem_writable_; } - bool ShouldUseDiretWritable(const std::string& file_name) { + bool ShouldUseDirectWritable(const std::string& file_name) { MutexLock l(&mutex_); if (filesystem_writable_) { return true; @@ -525,12 +457,49 @@ class FaultInjectionTestFS : public FileSystemWrapper { // saved callstack void PrintFaultBacktrace(); + protected: + IOStatus DoRead(FSSequentialFile* file, size_t n, const IOOptions& options, + Slice* result, char* scratch, IODebugContext* dbg) override; + + IOStatus DoPositionedRead(FSSequentialFile* file, uint64_t offset, size_t n, + const IOOptions& options, Slice* result, + char* scratch, IODebugContext* dbg) override; + + IOStatus DoRead(FSRandomAccessFile* file, uint64_t offset, size_t n, + const IOOptions& options, Slice* result, char* scratch, + IODebugContext* dbg) override; + IOStatus DoReadAsync(FSRandomAccessFile* file, FSReadRequest& req, + const IOOptions& opts, + std::function cb, + void* cb_arg, void** io_handle, IOHandleDeleter* del_fn, + IODebugContext* dbg) override; + IOStatus DoMultiRead(FSRandomAccessFile* file, FSReadRequest* reqs, + size_t num_reqs, const IOOptions& options, + IODebugContext* dbg) override; + using InjectionFileSystem::DoGetUniqueId; + size_t DoGetUniqueId(FSRandomAccessFile* file, char* id, + size_t max_size) override; + IOStatus DoWrite(FSRandomRWFile* file, uint64_t offset, const Slice& data, + const IOOptions& options, IODebugContext* dbg) override; + IOStatus DoRead(FSRandomRWFile* file, uint64_t offset, size_t n, + const IOOptions& options, Slice* result, char* scratch, + IODebugContext* dbg) override; + using InjectionFileSystem::DoClose; + IOStatus DoClose(FSRandomRWFile* file, const IOOptions& options, + IODebugContext* dbg) override; + using InjectionFileSystem::DoFlush; + IOStatus DoFlush(FSRandomRWFile* file, const IOOptions& options, + IODebugContext* dbg) override; + using InjectionFileSystem::DoSync; + IOStatus DoSync(FSRandomRWFile* file, const IOOptions& options, + IODebugContext* dbg) override; + private: port::Mutex mutex_; std::map db_file_state_; std::set open_managed_files_; // directory -> (file name -> file contents to recover) - // When data is recovered from unsyned parent directory, the files with + // When data is recovered from unsynced parent directory, the files with // empty file contents to recover is deleted. Those with non-empty ones // will be recovered to content accordingly. std::unordered_map> diff --git a/utilities/injection_fs.cc b/utilities/injection_fs.cc new file mode 100644 index 0000000000..80476be3f2 --- /dev/null +++ b/utilities/injection_fs.cc @@ -0,0 +1,89 @@ +// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + +#include "utilities/injection_fs.h" + +namespace ROCKSDB_NAMESPACE { +IOStatus InjectionFileSystem::NewSequentialFile( + const std::string& f, const FileOptions& options, + std::unique_ptr* r, IODebugContext* dbg) { + std::unique_ptr base; + auto rv = FileSystemWrapper::NewSequentialFile(f, options, &base, dbg); + if (rv.ok()) { + r->reset(new InjectionSequentialFile(std::move(base), this)); + } + return rv; +} + +IOStatus InjectionFileSystem::NewRandomAccessFile( + const std::string& f, const FileOptions& file_opts, + std::unique_ptr* r, IODebugContext* dbg) { + std::unique_ptr base; + auto rv = FileSystemWrapper::NewRandomAccessFile(f, file_opts, &base, dbg); + if (rv.ok()) { + r->reset(new InjectionRandomAccessFile(std::move(base), this)); + } + return rv; +} + +IOStatus InjectionFileSystem::NewWritableFile( + const std::string& f, const FileOptions& options, + std::unique_ptr* r, IODebugContext* dbg) { + std::unique_ptr base; + auto rv = FileSystemWrapper::NewWritableFile(f, options, &base, dbg); + if (rv.ok()) { + r->reset(new InjectionWritableFile(std::move(base), this)); + } + return rv; +} + +IOStatus InjectionFileSystem::ReopenWritableFile( + const std::string& fname, const FileOptions& options, + std::unique_ptr* result, IODebugContext* dbg) { + std::unique_ptr base; + auto rv = FileSystemWrapper::ReopenWritableFile(fname, options, &base, dbg); + if (rv.ok()) { + result->reset(new InjectionWritableFile(std::move(base), this)); + } + return rv; +} + +IOStatus InjectionFileSystem::ReuseWritableFile( + const std::string& fname, const std::string& old_fname, + const FileOptions& file_opts, std::unique_ptr* result, + IODebugContext* dbg) { + std::unique_ptr base; + auto rv = FileSystemWrapper::ReuseWritableFile(fname, old_fname, file_opts, + &base, dbg); + if (rv.ok()) { + result->reset(new InjectionWritableFile(std::move(base), this)); + } + return rv; +} + +IOStatus InjectionFileSystem::NewRandomRWFile( + const std::string& name, const FileOptions& options, + std::unique_ptr* result, IODebugContext* dbg) { + std::unique_ptr base; + auto rv = FileSystemWrapper::NewRandomRWFile(name, options, &base, dbg); + if (rv.ok()) { + result->reset(new InjectionRandomRWFile(std::move(base), this)); + } + return rv; +} + +IOStatus InjectionFileSystem::NewDirectory(const std::string& name, + const IOOptions& io_opts, + std::unique_ptr* result, + IODebugContext* dbg) { + std::unique_ptr base; + auto rv = FileSystemWrapper::NewDirectory(name, io_opts, &base, dbg); + if (rv.ok()) { + result->reset(new InjectionDirectory(std::move(base), this)); + } + return rv; +} + +} // namespace ROCKSDB_NAMESPACE diff --git a/utilities/injection_fs.h b/utilities/injection_fs.h new file mode 100644 index 0000000000..2ce715ed5b --- /dev/null +++ b/utilities/injection_fs.h @@ -0,0 +1,403 @@ +// Copyright (c) 2016-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + +#pragma once + +#include +#include + +#include "rocksdb/file_system.h" +#include "rocksdb/io_status.h" +#include "rocksdb/rocksdb_namespace.h" + +namespace ROCKSDB_NAMESPACE { +class Logger; + +// A base FileSystem class that can interject into File APIs. +// +// This class creates specialized File classes (e.g. InjectionSequentialFile) +// that calls back into methods in this base class. Implementations can +// override those base methods to inject their own code. Example use cases +// for this class include injecting failures into file operations, counting +// or timing file operations, or skipping file operations. +// +// Derived classes should override the methods they wish to intercept. +// Additionally, derived classes must implement the Name() method. +class InjectionFileSystem : public FileSystemWrapper { + public: + explicit InjectionFileSystem(const std::shared_ptr& base) + : FileSystemWrapper(base) {} + + IOStatus NewSequentialFile(const std::string& f, const FileOptions& options, + std::unique_ptr* r, + IODebugContext* dbg) override; + + IOStatus NewRandomAccessFile(const std::string& f, + const FileOptions& file_opts, + std::unique_ptr* r, + IODebugContext* dbg) override; + + IOStatus NewWritableFile(const std::string& f, const FileOptions& options, + std::unique_ptr* r, + IODebugContext* dbg) override; + IOStatus ReopenWritableFile(const std::string& fname, + const FileOptions& options, + std::unique_ptr* result, + IODebugContext* dbg) override; + + IOStatus ReuseWritableFile(const std::string& fname, + const std::string& old_fname, + const FileOptions& file_opts, + std::unique_ptr* result, + IODebugContext* dbg) override; + IOStatus NewRandomRWFile(const std::string& name, const FileOptions& options, + std::unique_ptr* result, + IODebugContext* dbg) override; + + IOStatus NewDirectory(const std::string& name, const IOOptions& io_opts, + std::unique_ptr* result, + IODebugContext* dbg) override; + + protected: + friend class InjectionSequentialFile; + friend class InjectionRandomAccessFile; + friend class InjectionWritableFile; + friend class InjectionRandomRWFile; + friend class InjectionDirectory; + + virtual IOStatus DoRead(FSSequentialFile* file, size_t n, + const IOOptions& options, Slice* result, + char* scratch, IODebugContext* dbg) { + return file->Read(n, options, result, scratch, dbg); + } + + virtual IOStatus DoPositionedRead(FSSequentialFile* file, uint64_t offset, + size_t n, const IOOptions& options, + Slice* result, char* scratch, + IODebugContext* dbg) { + return file->PositionedRead(offset, n, options, result, scratch, dbg); + } + + virtual void DoClose(FSSequentialFile* /*file*/) {} + + virtual IOStatus DoRead(FSRandomAccessFile* file, uint64_t offset, size_t n, + const IOOptions& options, Slice* result, + char* scratch, IODebugContext* dbg) { + return file->Read(offset, n, options, result, scratch, dbg); + } + + virtual IOStatus DoMultiRead(FSRandomAccessFile* file, FSReadRequest* reqs, + size_t num_reqs, const IOOptions& options, + IODebugContext* dbg) { + return file->MultiRead(reqs, num_reqs, options, dbg); + } + + virtual IOStatus DoReadAsync( + FSRandomAccessFile* file, FSReadRequest& req, const IOOptions& opts, + std::function cb, void* cb_arg, + void** io_handle, IOHandleDeleter* del_fn, IODebugContext* dbg) { + return file->ReadAsync(req, opts, cb, cb_arg, io_handle, del_fn, dbg); + } + + virtual size_t DoGetUniqueId(FSRandomAccessFile* file, char* id, + size_t max_size) { + return file->GetUniqueId(id, max_size); + } + + virtual void DoClose(FSRandomAccessFile* /*file*/) {} + + virtual IOStatus DoAppend(FSWritableFile* file, const Slice& data, + const IOOptions& options, IODebugContext* dbg) { + return file->Append(data, options, dbg); + } + + virtual IOStatus DoAppend(FSWritableFile* file, const Slice& data, + const IOOptions& options, + const DataVerificationInfo& info, + IODebugContext* dbg) { + return file->Append(data, options, info, dbg); + } + + virtual IOStatus DoPositionedAppend(FSWritableFile* file, const Slice& data, + uint64_t offset, const IOOptions& options, + IODebugContext* dbg) { + return file->PositionedAppend(data, offset, options, dbg); + } + + virtual IOStatus DoPositionedAppend(FSWritableFile* file, const Slice& data, + uint64_t offset, const IOOptions& options, + const DataVerificationInfo& info, + IODebugContext* dbg) { + return file->PositionedAppend(data, offset, options, info, dbg); + } + + virtual IOStatus DoTruncate(FSWritableFile* file, uint64_t size, + const IOOptions& options, IODebugContext* dbg) { + return file->Truncate(size, options, dbg); + } + + virtual IOStatus DoClose(FSWritableFile* file, const IOOptions& options, + IODebugContext* dbg) { + return file->Close(options, dbg); + } + + virtual IOStatus DoFlush(FSWritableFile* file, const IOOptions& options, + IODebugContext* dbg) { + return file->Flush(options, dbg); + } + + virtual IOStatus DoSync(FSWritableFile* file, const IOOptions& options, + IODebugContext* dbg) { + return file->Sync(options, dbg); + } + + virtual IOStatus DoFsync(FSWritableFile* file, const IOOptions& options, + IODebugContext* dbg) { + return file->Fsync(options, dbg); + } + + virtual IOStatus DoRangeSync(FSWritableFile* file, uint64_t offset, + uint64_t nbytes, const IOOptions& options, + IODebugContext* dbg) { + return file->RangeSync(offset, nbytes, options, dbg); + } + + virtual IOStatus DoWrite(FSRandomRWFile* file, uint64_t offset, + const Slice& data, const IOOptions& options, + IODebugContext* dbg) { + return file->Write(offset, data, options, dbg); + } + + virtual IOStatus DoRead(FSRandomRWFile* file, uint64_t offset, size_t n, + const IOOptions& options, Slice* result, + char* scratch, IODebugContext* dbg) { + return file->Read(offset, n, options, result, scratch, dbg); + } + + virtual IOStatus DoFlush(FSRandomRWFile* file, const IOOptions& options, + IODebugContext* dbg) { + return file->Flush(options, dbg); + } + + virtual IOStatus DoSync(FSRandomRWFile* file, const IOOptions& options, + IODebugContext* dbg) { + return file->Sync(options, dbg); + } + + virtual IOStatus DoFsync(FSRandomRWFile* file, const IOOptions& options, + IODebugContext* dbg) { + return file->Fsync(options, dbg); + } + + virtual IOStatus DoClose(FSRandomRWFile* file, const IOOptions& options, + IODebugContext* dbg) { + return file->Close(options, dbg); + } + + virtual IOStatus DoFsync(FSDirectory* dir, const IOOptions& options, + IODebugContext* dbg) { + return dir->Fsync(options, dbg); + } + + virtual IOStatus DoFsyncWithDirOptions(FSDirectory* dir, + const IOOptions& options, + IODebugContext* dbg, + const DirFsyncOptions& dir_options) { + return dir->FsyncWithDirOptions(options, dbg, dir_options); + } + + virtual size_t DoGetUniqueId(FSDirectory* dir, char* id, size_t max_size) { + return dir->GetUniqueId(id, max_size); + } + + virtual IOStatus DoClose(FSDirectory* dir, const IOOptions& options, + IODebugContext* dbg) { + return dir->Close(options, dbg); + } +}; + +class InjectionSequentialFile : public FSSequentialFileOwnerWrapper { + private: + InjectionFileSystem* fs_; + + public: + InjectionSequentialFile(std::unique_ptr&& f, + InjectionFileSystem* fs) + : FSSequentialFileOwnerWrapper(std::move(f)), fs_(fs) {} + + ~InjectionSequentialFile() override { fs_->DoClose(target()); } + + IOStatus Read(size_t n, const IOOptions& options, Slice* result, + char* scratch, IODebugContext* dbg) override { + return fs_->DoRead(target(), n, options, result, scratch, dbg); + } + + IOStatus PositionedRead(uint64_t offset, size_t n, const IOOptions& options, + Slice* result, char* scratch, + IODebugContext* dbg) override { + return fs_->DoPositionedRead(target(), offset, n, options, result, scratch, + dbg); + } +}; + +class InjectionRandomAccessFile : public FSRandomAccessFileOwnerWrapper { + private: + InjectionFileSystem* fs_; + + public: + InjectionRandomAccessFile(std::unique_ptr&& f, + InjectionFileSystem* fs) + : FSRandomAccessFileOwnerWrapper(std::move(f)), fs_(fs) {} + + ~InjectionRandomAccessFile() override { fs_->DoClose(target()); } + IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, + Slice* result, char* scratch, + IODebugContext* dbg) const override { + return fs_->DoRead(target(), offset, n, options, result, scratch, dbg); + } + + IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs, + const IOOptions& options, IODebugContext* dbg) override { + return fs_->DoMultiRead(target(), reqs, num_reqs, options, dbg); + } + + size_t GetUniqueId(char* id, size_t max_size) const override { + return fs_->DoGetUniqueId(target(), id, max_size); + } +}; + +class InjectionWritableFile : public FSWritableFileOwnerWrapper { + private: + InjectionFileSystem* fs_; + + public: + InjectionWritableFile(std::unique_ptr&& f, + InjectionFileSystem* fs) + : FSWritableFileOwnerWrapper(std::move(f)), fs_(fs) {} + + IOStatus Append(const Slice& data, const IOOptions& options, + IODebugContext* dbg) override { + return fs_->DoAppend(target(), data, options, dbg); + } + + IOStatus Append(const Slice& data, const IOOptions& options, + const DataVerificationInfo& info, + IODebugContext* dbg) override { + return fs_->DoAppend(target(), data, options, info, dbg); + } + + IOStatus Truncate(uint64_t size, const IOOptions& options, + IODebugContext* dbg) override { + return fs_->DoTruncate(target(), size, options, dbg); + } + + IOStatus PositionedAppend(const Slice& data, uint64_t offset, + const IOOptions& options, + IODebugContext* dbg) override { + return fs_->DoPositionedAppend(target(), data, offset, options, dbg); + } + + IOStatus PositionedAppend(const Slice& data, uint64_t offset, + const IOOptions& options, + const DataVerificationInfo& info, + IODebugContext* dbg) override { + return fs_->DoPositionedAppend(target(), data, offset, options, info, dbg); + } + + IOStatus Close(const IOOptions& options, IODebugContext* dbg) override { + return fs_->DoClose(target(), options, dbg); + } + + IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override { + return fs_->DoFlush(target(), options, dbg); + } + + IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override { + return fs_->DoSync(target(), options, dbg); + } + IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override { + return fs_->DoFsync(target(), options, dbg); + } + IOStatus RangeSync(uint64_t offset, uint64_t nbytes, const IOOptions& options, + IODebugContext* dbg) override { + return fs_->DoRangeSync(target(), offset, nbytes, options, dbg); + } +}; + +class InjectionRandomRWFile : public FSRandomRWFileOwnerWrapper { + private: + mutable InjectionFileSystem* fs_; + + public: + InjectionRandomRWFile(std::unique_ptr&& f, + InjectionFileSystem* fs) + : FSRandomRWFileOwnerWrapper(std::move(f)), fs_(fs) {} + IOStatus Write(uint64_t offset, const Slice& data, const IOOptions& options, + IODebugContext* dbg) override { + return fs_->DoWrite(target(), offset, data, options, dbg); + } + + IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, + Slice* result, char* scratch, + IODebugContext* dbg) const override { + return fs_->DoRead(target(), offset, n, options, result, scratch, dbg); + } + + IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override { + return fs_->DoFlush(target(), options, dbg); + } + + IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override { + return fs_->DoSync(target(), options, dbg); + } + + IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override { + return fs_->DoFsync(target(), options, dbg); + } + + IOStatus Close(const IOOptions& options, IODebugContext* dbg) override { + return fs_->DoClose(target(), options, dbg); + } +}; + +class InjectionDirectory : public FSDirectoryWrapper { + private: + mutable InjectionFileSystem* fs_; + bool closed_ = false; + + public: + InjectionDirectory(std::unique_ptr&& f, InjectionFileSystem* fs) + : FSDirectoryWrapper(std::move(f)), fs_(fs) {} + + ~InjectionDirectory() override { + if (!closed_) { + // TODO: fix DB+CF code to use explicit Close, not rely on destructor + fs_->DoClose(target_, IOOptions(), nullptr).PermitUncheckedError(); + } + } + + IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override { + return fs_->DoFsync(target_, options, dbg); + } + + IOStatus FsyncWithDirOptions(const IOOptions& options, IODebugContext* dbg, + const DirFsyncOptions& dir_options) override { + return fs_->DoFsyncWithDirOptions(target_, options, dbg, dir_options); + } + + // Close directory + IOStatus Close(const IOOptions& options, IODebugContext* dbg) override { + auto io_s = fs_->DoClose(target_, options, dbg); + if (io_s.ok()) { + closed_ = true; + } + return io_s; + } + + size_t GetUniqueId(char* id, size_t max_size) const override { + return fs_->DoGetUniqueId(target_, id, max_size); + } +}; +} // namespace ROCKSDB_NAMESPACE diff --git a/utilities/nosync_fs.cc b/utilities/nosync_fs.cc new file mode 100644 index 0000000000..34928c810a --- /dev/null +++ b/utilities/nosync_fs.cc @@ -0,0 +1,36 @@ +// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + +#include "utilities/nosync_fs.h" + +#include "rocksdb/utilities/options_type.h" + +namespace ROCKSDB_NAMESPACE { +namespace { +static std::unordered_map no_sync_fs_option_info = + { +#ifndef ROCKSDB_LITE + {"sync", + {offsetof(struct NoSyncOptions, do_sync), OptionType::kBoolean, + OptionVerificationType::kNormal, OptionTypeFlags::kCompareNever}}, + {"fsync", + {offsetof(struct NoSyncOptions, do_fsync), OptionType::kBoolean, + OptionVerificationType::kNormal, OptionTypeFlags::kCompareNever}}, + {"range_sync", + {offsetof(struct NoSyncOptions, do_rsync), OptionType::kBoolean, + OptionVerificationType::kNormal, OptionTypeFlags::kCompareNever}}, + {"dir_sync", + {offsetof(struct NoSyncOptions, do_dsync), OptionType::kBoolean, + OptionVerificationType::kNormal, OptionTypeFlags::kCompareNever}}, +#endif // ROCKSDB_LITE +}; +} // namespace + +NoSyncFileSystem::NoSyncFileSystem(const std::shared_ptr& base, + bool enabled) + : InjectionFileSystem(base), sync_opts_(enabled) { + RegisterOptions(&sync_opts_, &no_sync_fs_option_info); +} +} // namespace ROCKSDB_NAMESPACE diff --git a/utilities/nosync_fs.h b/utilities/nosync_fs.h new file mode 100644 index 0000000000..f1a6091ea9 --- /dev/null +++ b/utilities/nosync_fs.h @@ -0,0 +1,125 @@ +// Copyright (c) 2016-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + +#pragma once + +#include +#include + +#include "rocksdb/file_system.h" +#include "rocksdb/io_status.h" +#include "rocksdb/rocksdb_namespace.h" +#include "utilities/injection_fs.h" + +namespace ROCKSDB_NAMESPACE { +struct NoSyncOptions { + static const char* kName() { return "NoSyncOptions"; } + explicit NoSyncOptions(bool enabled = false) + : do_sync(enabled), + do_fsync(enabled), + do_rsync(enabled), + do_dsync(enabled) {} + + bool do_sync = false; + bool do_fsync = false; + bool do_rsync = false; + bool do_dsync = false; +}; + +// A FileSystem that allows the sync operations to be skipped +// By default, the NoSyncFileSystem will skip all sync (Sync, Fsync, +// RangeSync, and Fsync for directories) operations. +// +class NoSyncFileSystem : public InjectionFileSystem { + private: + NoSyncOptions sync_opts_; + + public: + // Creates a new NoSyncFileSystem wrapping the input base. + // If enabled=false, all sync operations are skipped (e.g. disabled). + // Sync operations can also be turned on or off by their type individually + // through the configuration or methods. + explicit NoSyncFileSystem(const std::shared_ptr& base, + bool enabled = false); + static const char* kClassName() { return "NoSyncFileSystem"; } + const char* Name() const override { return kClassName(); } + + void SetSyncEnabled(bool b) { sync_opts_.do_sync = b; } + void SetFSyncEnabled(bool b) { sync_opts_.do_fsync = b; } + void SetRangeSyncEnabled(bool b) { sync_opts_.do_rsync = b; } + void SetDirSyncEnabled(bool b) { sync_opts_.do_dsync = b; } + bool IsSyncEnabled() const { return sync_opts_.do_sync; } + bool IsFSyncEnabled() const { return sync_opts_.do_fsync; } + bool IsRangeSyncEnabled() const { return sync_opts_.do_rsync; } + bool IsDirSyncEnabled() const { return sync_opts_.do_dsync; } + + protected: + IOStatus DoSync(FSWritableFile* file, const IOOptions& options, + IODebugContext* dbg) override { + if (sync_opts_.do_sync) { + return InjectionFileSystem::DoSync(file, options, dbg); + } else { + return IOStatus::OK(); + } + } + + IOStatus DoFsync(FSWritableFile* file, const IOOptions& options, + IODebugContext* dbg) override { + if (sync_opts_.do_fsync) { + return InjectionFileSystem::DoFsync(file, options, dbg); + } else { + return IOStatus::OK(); + } + } + + IOStatus DoRangeSync(FSWritableFile* file, uint64_t offset, uint64_t nbytes, + const IOOptions& options, IODebugContext* dbg) override { + if (sync_opts_.do_rsync) { + return InjectionFileSystem::DoRangeSync(file, offset, nbytes, options, + dbg); + } else { + return IOStatus::OK(); + } + } + + IOStatus DoSync(FSRandomRWFile* file, const IOOptions& options, + IODebugContext* dbg) override { + if (sync_opts_.do_sync) { + return InjectionFileSystem::DoSync(file, options, dbg); + } else { + return IOStatus::OK(); + } + } + + IOStatus DoFsync(FSRandomRWFile* file, const IOOptions& options, + IODebugContext* dbg) override { + if (sync_opts_.do_fsync) { + return InjectionFileSystem::DoFsync(file, options, dbg); + } else { + return IOStatus::OK(); + } + } + + IOStatus DoFsync(FSDirectory* dir, const IOOptions& options, + IODebugContext* dbg) override { + if (sync_opts_.do_dsync) { + return InjectionFileSystem::DoFsync(dir, options, dbg); + } else { + return IOStatus::OK(); + } + } + + IOStatus DoFsyncWithDirOptions(FSDirectory* dir, const IOOptions& options, + IODebugContext* dbg, + const DirFsyncOptions& dir_options) override { + if (sync_opts_.do_dsync) { + return InjectionFileSystem::DoFsyncWithDirOptions(dir, options, dbg, + dir_options); + } else { + return IOStatus::OK(); + } + } +}; +} // namespace ROCKSDB_NAMESPACE