From e628f59e87ddad7a859949413421cd1e743d6a2a Mon Sep 17 00:00:00 2001 From: mrambacher Date: Wed, 6 Jan 2021 10:48:24 -0800 Subject: [PATCH] Create a CustomEnv class; Add WinFileSystem; Make LegacyFileSystemWrapper private (#7703) Summary: This PR does the following: -> Creates a WinFileSystem class. This class is the Windows equivalent of the PosixFileSystem and will be used on Windows systems. -> Introduces a CustomEnv class. A CustomEnv is an Env that takes a FileSystem as constructor argument. I believe there will only ever be two implementations of this class (PosixEnv and WinEnv). There is still a CustomEnvWrapper class that takes an Env and a FileSystem and wraps the Env calls with the input Env but uses the FileSystem for the FileSystem calls -> Eliminates the public uses of the LegacyFileSystemWrapper. With this change in place, there are effectively the following patterns of Env: - "Base Env classes" (PosixEnv, WinEnv). These classes implement the core Env functions (e.g. Threads) and have a hard-coded input FileSystem. These classes inherit from CompositeEnv, implement the core Env functions (threads) and delegate the FileSystem-like calls to the input file system. - Wrapped Composite Env classes (MemEnv). These classes take in an Env and a FileSystem. The core env functions are re-directed to the wrapped env. The file system calls are redirected to the input file system - Legacy Wrapped Env classes. These classes take in an Env input (but no FileSystem). The core env functions are re-directed to the wrapped env. A "Legacy File System" is created using this env and the file system calls directed to the env itself. With these changes in place, the PosixEnv becomes a singleton -- there is only ever one created. Any other use of the PosixEnv is via another wrapped env. This cleans up some of the issues with the env construction and destruction. Additionally, there were places in the code that required had an Env when they required a FileSystem. Many of these places would wrap the Env with a LegacyFileSystemWrapper instead of using the env->GetFileSystem(). These places were changed, thereby removing layers of additional redirection (LegacyFileSystem --> Env --> Env::FileSystem). Pull Request resolved: https://github.com/facebook/rocksdb/pull/7703 Reviewed By: zhichao-cao Differential Revision: D25762190 Pulled By: anand1976 fbshipit-source-id: 1a088e97fc916f28ac69c149cd1dcad0ab31704b --- db/blob/blob_file_builder_test.cc | 27 +- db/compaction/compaction_job_test.cc | 2 +- db/db_basic_test.cc | 4 +- db/db_impl/db_impl.cc | 5 +- db/db_test2.cc | 41 +- db/flush_job_test.cc | 2 +- db/repair.cc | 1 - db/repair_test.cc | 8 +- db/wal_manager_test.cc | 4 +- env/composite_env_wrapper.h | 364 ++-------- env/env.cc | 257 ++++++- env/env_posix.cc | 26 +- env/file_system.cc | 9 - file/delete_scheduler_test.cc | 9 +- file/file_util.h | 26 + file/prefetch_test.cc | 4 +- file/sst_file_manager_impl.cc | 9 +- include/rocksdb/env.h | 3 +- include/rocksdb/file_system.h | 7 +- port/win/env_default.cc | 2 +- port/win/env_win.cc | 956 ++++++++++++--------------- port/win/env_win.h | 397 +++++------ port/win/io_win.cc | 553 ++++++++-------- port/win/io_win.h | 258 +++++--- port/win/win_logger.cc | 18 +- port/win/win_logger.h | 15 +- test_util/testutil.cc | 20 + test_util/testutil.h | 4 + tools/db_bench_tool_test.cc | 6 +- utilities/blob_db/blob_db_test.cc | 8 +- utilities/options/options_util.cc | 10 +- 31 files changed, 1500 insertions(+), 1555 deletions(-) diff --git a/db/blob/blob_file_builder_test.cc b/db/blob/blob_file_builder_test.cc index 72e9ac47b..2baa2470f 100644 --- a/db/blob/blob_file_builder_test.cc +++ b/db/blob/blob_file_builder_test.cc @@ -15,7 +15,6 @@ #include "db/blob/blob_index.h" #include "db/blob/blob_log_format.h" #include "db/blob/blob_log_sequential_reader.h" -#include "env/composite_env_wrapper.h" #include "env/mock_env.h" #include "file/filename.h" #include "file/random_access_file_reader.h" @@ -40,7 +39,9 @@ class TestFileNumberGenerator { class BlobFileBuilderTest : public testing::Test { protected: - BlobFileBuilderTest() : mock_env_(Env::Default()), fs_(&mock_env_) {} + BlobFileBuilderTest() : mock_env_(Env::Default()) { + fs_ = mock_env_.GetFileSystem(); + } void VerifyBlobFile(uint64_t blob_file_number, const std::string& blob_file_path, @@ -54,7 +55,7 @@ class BlobFileBuilderTest : public testing::Test { std::unique_ptr file; constexpr IODebugContext* dbg = nullptr; ASSERT_OK( - fs_.NewRandomAccessFile(blob_file_path, file_options_, &file, dbg)); + fs_->NewRandomAccessFile(blob_file_path, file_options_, &file, dbg)); std::unique_ptr file_reader( new RandomAccessFileReader(std::move(file), blob_file_path, @@ -108,7 +109,7 @@ class BlobFileBuilderTest : public testing::Test { } MockEnv mock_env_; - LegacyFileSystemWrapper fs_; + std::shared_ptr fs_; FileOptions file_options_; }; @@ -138,7 +139,7 @@ TEST_F(BlobFileBuilderTest, BuildAndCheckOneFile) { std::vector blob_file_paths; std::vector blob_file_additions; - BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_, + BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, fs_.get(), &immutable_cf_options, &mutable_cf_options, &file_options_, job_id, column_family_id, column_family_name, io_priority, write_hint, @@ -221,7 +222,7 @@ TEST_F(BlobFileBuilderTest, BuildAndCheckMultipleFiles) { std::vector blob_file_paths; std::vector blob_file_additions; - BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_, + BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, fs_.get(), &immutable_cf_options, &mutable_cf_options, &file_options_, job_id, column_family_id, column_family_name, io_priority, write_hint, @@ -306,7 +307,7 @@ TEST_F(BlobFileBuilderTest, InlinedValues) { std::vector blob_file_paths; std::vector blob_file_additions; - BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_, + BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, fs_.get(), &immutable_cf_options, &mutable_cf_options, &file_options_, job_id, column_family_id, column_family_name, io_priority, write_hint, @@ -358,7 +359,7 @@ TEST_F(BlobFileBuilderTest, Compression) { std::vector blob_file_paths; std::vector blob_file_additions; - BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_, + BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, fs_.get(), &immutable_cf_options, &mutable_cf_options, &file_options_, job_id, column_family_id, column_family_name, io_priority, write_hint, @@ -440,7 +441,7 @@ TEST_F(BlobFileBuilderTest, CompressionError) { std::vector blob_file_paths; std::vector blob_file_additions; - BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_, + BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, fs_.get(), &immutable_cf_options, &mutable_cf_options, &file_options_, job_id, column_family_id, column_family_name, io_priority, write_hint, @@ -517,7 +518,7 @@ TEST_F(BlobFileBuilderTest, Checksum) { std::vector blob_file_paths; std::vector blob_file_additions; - BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_, + BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, fs_.get(), &immutable_cf_options, &mutable_cf_options, &file_options_, job_id, column_family_id, column_family_name, io_priority, write_hint, @@ -571,12 +572,12 @@ class BlobFileBuilderIOErrorTest BlobFileBuilderIOErrorTest() : mock_env_(Env::Default()), fault_injection_env_(&mock_env_), - fs_(&fault_injection_env_), + fs_(fault_injection_env_.GetFileSystem()), sync_point_(GetParam()) {} MockEnv mock_env_; FaultInjectionTestEnv fault_injection_env_; - LegacyFileSystemWrapper fs_; + std::shared_ptr fs_; FileOptions file_options_; std::string sync_point_; }; @@ -616,7 +617,7 @@ TEST_P(BlobFileBuilderIOErrorTest, IOError) { std::vector blob_file_additions; BlobFileBuilder builder(TestFileNumberGenerator(), &fault_injection_env_, - &fs_, &immutable_cf_options, &mutable_cf_options, + fs_.get(), &immutable_cf_options, &mutable_cf_options, &file_options_, job_id, column_family_id, column_family_name, io_priority, write_hint, &blob_file_paths, &blob_file_additions); diff --git a/db/compaction/compaction_job_test.cc b/db/compaction/compaction_job_test.cc index 9ac39e888..fa0393a9a 100644 --- a/db/compaction/compaction_job_test.cc +++ b/db/compaction/compaction_job_test.cc @@ -72,7 +72,7 @@ class CompactionJobTestBase : public testing::Test { CompactionJobTestBase(std::string dbname, const Comparator* ucmp, std::function encode_u64_ts) : env_(Env::Default()), - fs_(std::make_shared(env_)), + fs_(env_->GetFileSystem()), dbname_(std::move(dbname)), ucmp_(ucmp), db_options_(), diff --git a/db/db_basic_test.cc b/db/db_basic_test.cc index 5acc99868..63a225252 100644 --- a/db/db_basic_test.cc +++ b/db/db_basic_test.cc @@ -3274,7 +3274,9 @@ class DeadlineFS : public FileSystemWrapper { // Increment the IO counter and return a delay in microseconds IOStatus ShouldDelay(const IOOptions& opts) { - if (!deadline_.count() && !io_timeout_.count()) { + if (timedout_) { + return IOStatus::TimedOut(); + } else if (!deadline_.count() && !io_timeout_.count()) { return IOStatus::OK(); } if (!ignore_deadline_ && delay_trigger_ == io_count_++) { diff --git a/db/db_impl/db_impl.cc b/db/db_impl/db_impl.cc index 4c204e468..5e1b943df 100644 --- a/db/db_impl/db_impl.cc +++ b/db/db_impl/db_impl.cc @@ -53,7 +53,6 @@ #include "db/version_set.h" #include "db/write_batch_internal.h" #include "db/write_callback.h" -#include "env/composite_env_wrapper.h" #include "file/file_util.h" #include "file/filename.h" #include "file/random_access_file_reader.h" @@ -3099,8 +3098,8 @@ const std::string& DBImpl::GetName() const { return dbname_; } Env* DBImpl::GetEnv() const { return env_; } FileSystem* DB::GetFileSystem() const { - static LegacyFileSystemWrapper fs_wrap(GetEnv()); - return &fs_wrap; + const auto& fs = GetEnv()->GetFileSystem(); + return fs.get(); } FileSystem* DBImpl::GetFileSystem() const { diff --git a/db/db_test2.cc b/db/db_test2.cc index 4d7f93269..8587686e3 100644 --- a/db/db_test2.cc +++ b/db/db_test2.cc @@ -3685,20 +3685,26 @@ TEST_F(DBTest2, LiveFilesOmitObsoleteFiles) { TEST_F(DBTest2, TestNumPread) { Options options = CurrentOptions(); + bool prefetch_supported = + test::IsPrefetchSupported(env_->GetFileSystem(), dbname_); // disable block cache BlockBasedTableOptions table_options; table_options.no_block_cache = true; options.table_factory.reset(NewBlockBasedTableFactory(table_options)); Reopen(options); env_->count_random_reads_ = true; - env_->random_file_open_counter_.store(0); ASSERT_OK(Put("bar", "foo")); ASSERT_OK(Put("foo", "bar")); ASSERT_OK(Flush()); - // After flush, we'll open the file and read footer, meta block, - // property block and index block. - ASSERT_EQ(4, env_->random_read_counter_.Read()); + if (prefetch_supported) { + // After flush, we'll open the file and read footer, meta block, + // property block and index block. + ASSERT_EQ(4, env_->random_read_counter_.Read()); + } else { + // With prefetch not supported, we will do a single read into a buffer + ASSERT_EQ(1, env_->random_read_counter_.Read()); + } ASSERT_EQ(1, env_->random_file_open_counter_.load()); // One pread per a normal data block read @@ -3714,19 +3720,30 @@ TEST_F(DBTest2, TestNumPread) { ASSERT_OK(Put("bar2", "foo2")); ASSERT_OK(Put("foo2", "bar2")); ASSERT_OK(Flush()); - // After flush, we'll open the file and read footer, meta block, - // property block and index block. - ASSERT_EQ(4, env_->random_read_counter_.Read()); + if (prefetch_supported) { + // After flush, we'll open the file and read footer, meta block, + // property block and index block. + ASSERT_EQ(4, env_->random_read_counter_.Read()); + } else { + // With prefetch not supported, we will do a single read into a buffer + ASSERT_EQ(1, env_->random_read_counter_.Read()); + } ASSERT_EQ(1, env_->random_file_open_counter_.load()); - // Compaction needs two input blocks, which requires 2 preads, and - // generate a new SST file which needs 4 preads (footer, meta block, - // property block and index block). In total 6. env_->random_file_open_counter_.store(0); env_->random_read_counter_.Reset(); ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr)); - ASSERT_EQ(6, env_->random_read_counter_.Read()); - // All compactin input files should have already been opened. + if (prefetch_supported) { + // Compaction needs two input blocks, which requires 2 preads, and + // generate a new SST file which needs 4 preads (footer, meta block, + // property block and index block). In total 6. + ASSERT_EQ(6, env_->random_read_counter_.Read()); + } else { + // With prefetch off, compaction needs two input blocks, + // followed by a single buffered read. In total 3. + ASSERT_EQ(3, env_->random_read_counter_.Read()); + } + // All compaction input files should have already been opened. ASSERT_EQ(1, env_->random_file_open_counter_.load()); // One pread per a normal data block read diff --git a/db/flush_job_test.cc b/db/flush_job_test.cc index f1780314b..eab2e7f1a 100644 --- a/db/flush_job_test.cc +++ b/db/flush_job_test.cc @@ -32,7 +32,7 @@ class FlushJobTestBase : public testing::Test { protected: FlushJobTestBase(std::string dbname, const Comparator* ucmp) : env_(Env::Default()), - fs_(std::make_shared(env_)), + fs_(env_->GetFileSystem()), dbname_(std::move(dbname)), ucmp_(ucmp), options_(), diff --git a/db/repair.cc b/db/repair.cc index 342d9b63e..3795db371 100644 --- a/db/repair.cc +++ b/db/repair.cc @@ -439,7 +439,6 @@ class Repairer { range_del_iters.emplace_back(range_del_iter); } - LegacyFileSystemWrapper fs(env_); IOStatus io_s; status = BuildTable( dbname_, /* versions */ nullptr, immutable_db_options_, diff --git a/db/repair_test.cc b/db/repair_test.cc index 49a96bf8a..85337cbfd 100644 --- a/db/repair_test.cc +++ b/db/repair_test.cc @@ -80,8 +80,8 @@ TEST_F(RepairTest, CorruptManifest) { Close(); ASSERT_OK(env_->FileExists(manifest_path)); - LegacyFileSystemWrapper fs(env_); - ASSERT_OK(CreateFile(&fs, manifest_path, "blah", false /* use_fsync */)); + ASSERT_OK(CreateFile(env_->GetFileSystem(), manifest_path, "blah", + false /* use_fsync */)); ASSERT_OK(RepairDB(dbname_, CurrentOptions())); Reopen(CurrentOptions()); @@ -163,8 +163,8 @@ TEST_F(RepairTest, CorruptSst) { ASSERT_OK(GetFirstSstPath(&sst_path)); ASSERT_FALSE(sst_path.empty()); - LegacyFileSystemWrapper fs(env_); - ASSERT_OK(CreateFile(&fs, sst_path, "blah", false /* use_fsync */)); + ASSERT_OK(CreateFile(env_->GetFileSystem(), sst_path, "blah", + false /* use_fsync */)); Close(); ASSERT_OK(RepairDB(dbname_, CurrentOptions())); diff --git a/db/wal_manager_test.cc b/db/wal_manager_test.cc index f124bd5ad..618a50d75 100644 --- a/db/wal_manager_test.cc +++ b/db/wal_manager_test.cc @@ -47,8 +47,7 @@ class WalManagerTest : public testing::Test { std::numeric_limits::max()); db_options_.wal_dir = dbname_; db_options_.env = env_.get(); - fs_.reset(new LegacyFileSystemWrapper(env_.get())); - db_options_.fs = fs_; + db_options_.fs = env_->GetFileSystem(); versions_.reset( new VersionSet(dbname_, &db_options_, env_options_, table_cache_.get(), @@ -116,7 +115,6 @@ class WalManagerTest : public testing::Test { WriteBufferManager write_buffer_manager_; std::unique_ptr versions_; std::unique_ptr wal_manager_; - std::shared_ptr fs_; std::unique_ptr current_log_writer_; uint64_t current_log_number_; diff --git a/env/composite_env_wrapper.h b/env/composite_env_wrapper.h index 7a0da5c3e..f634eee52 100644 --- a/env/composite_env_wrapper.h +++ b/env/composite_env_wrapper.h @@ -8,6 +8,13 @@ #include "rocksdb/env.h" #include "rocksdb/file_system.h" +#ifdef _WIN32 +// Windows API macro interference +#undef DeleteFile +#undef GetCurrentTime +#undef LoadLibrary +#endif + namespace ROCKSDB_NAMESPACE { // The CompositeEnvWrapper class provides an interface that is compatible @@ -271,16 +278,11 @@ class CompositeDirectoryWrapper : public Directory { std::unique_ptr target_; }; -class CompositeEnvWrapper : public Env { +class CompositeEnv : public Env { public: // Initialize a CompositeEnvWrapper that delegates all thread/time related // calls to env, and all file operations to fs - explicit CompositeEnvWrapper(Env* env, std::shared_ptr fs) - : Env(fs), env_target_(env) {} - ~CompositeEnvWrapper() {} - - // Return the target to which this Env forwards all calls - Env* env_target() const { return env_target_; } + explicit CompositeEnv(const std::shared_ptr& fs) : Env(fs) {} Status RegisterDbPaths(const std::vector& paths) override { return file_system_->RegisterDbPaths(paths); @@ -498,6 +500,66 @@ class CompositeEnvWrapper : public Env { return file_system_->IsDirectory(path, io_opts, is_dir, &dbg); } + Status GetTestDirectory(std::string* path) override { + IOOptions io_opts; + IODebugContext dbg; + return file_system_->GetTestDirectory(io_opts, path, &dbg); + } + + EnvOptions OptimizeForLogRead(const EnvOptions& env_options) const override { + return file_system_->OptimizeForLogRead(FileOptions(env_options)); + } + + EnvOptions OptimizeForManifestRead( + const EnvOptions& env_options) const override { + return file_system_->OptimizeForManifestRead(FileOptions(env_options)); + } + + EnvOptions OptimizeForLogWrite(const EnvOptions& env_options, + const DBOptions& db_options) const override { + return file_system_->OptimizeForLogWrite(FileOptions(env_options), + db_options); + } + + EnvOptions OptimizeForManifestWrite( + const EnvOptions& env_options) const override { + return file_system_->OptimizeForManifestWrite(FileOptions(env_options)); + } + + EnvOptions OptimizeForCompactionTableWrite( + const EnvOptions& env_options, + const ImmutableDBOptions& immutable_ops) const override { + return file_system_->OptimizeForCompactionTableWrite( + FileOptions(env_options), immutable_ops); + } + EnvOptions OptimizeForCompactionTableRead( + const EnvOptions& env_options, + const ImmutableDBOptions& db_options) const override { + return file_system_->OptimizeForCompactionTableRead( + FileOptions(env_options), db_options); + } + + // This seems to clash with a macro on Windows, so #undef it here +#ifdef GetFreeSpace +#undef GetFreeSpace +#endif + Status GetFreeSpace(const std::string& path, uint64_t* diskfree) override { + IOOptions io_opts; + IODebugContext dbg; + return file_system_->GetFreeSpace(path, io_opts, diskfree, &dbg); + } +}; + +class CompositeEnvWrapper : public CompositeEnv { + public: + // Initialize a CompositeEnvWrapper that delegates all thread/time related + // calls to env, and all file operations to fs + explicit CompositeEnvWrapper(Env* env, const std::shared_ptr& fs) + : CompositeEnv(fs), env_target_(env) {} + + // Return the target to which this Env forwards all calls + Env* env_target() const { return env_target_; } + #if !defined(OS_WIN) && !defined(ROCKSDB_NO_DYNAMIC_EXTENSION) Status LoadLibrary(const std::string& lib_name, const std::string& search_path, @@ -522,11 +584,7 @@ class CompositeEnvWrapper : public Env { unsigned int GetThreadPoolQueueLen(Priority pri = LOW) const override { return env_target_->GetThreadPoolQueueLen(pri); } - Status GetTestDirectory(std::string* path) override { - IOOptions io_opts; - IODebugContext dbg; - return file_system_->GetTestDirectory(io_opts, path, &dbg); - } + uint64_t NowMicros() override { return env_target_->NowMicros(); } uint64_t NowNanos() override { return env_target_->NowNanos(); } uint64_t NowCPUNanos() override { return env_target_->NowCPUNanos(); } @@ -585,45 +643,6 @@ class CompositeEnvWrapper : public Env { return env_target_->GenerateUniqueId(); } - EnvOptions OptimizeForLogRead(const EnvOptions& env_options) const override { - return file_system_->OptimizeForLogRead(FileOptions(env_options)); - } - EnvOptions OptimizeForManifestRead( - const EnvOptions& env_options) const override { - return file_system_->OptimizeForManifestRead(FileOptions(env_options)); - } - EnvOptions OptimizeForLogWrite(const EnvOptions& env_options, - const DBOptions& db_options) const override { - return file_system_->OptimizeForLogWrite(FileOptions(env_options), - db_options); - } - EnvOptions OptimizeForManifestWrite( - const EnvOptions& env_options) const override { - return file_system_->OptimizeForManifestWrite(FileOptions(env_options)); - } - EnvOptions OptimizeForCompactionTableWrite( - const EnvOptions& env_options, - const ImmutableDBOptions& immutable_ops) const override { - return file_system_->OptimizeForCompactionTableWrite( - FileOptions(env_options), immutable_ops); - } - EnvOptions OptimizeForCompactionTableRead( - const EnvOptions& env_options, - const ImmutableDBOptions& db_options) const override { - return file_system_->OptimizeForCompactionTableRead( - FileOptions(env_options), db_options); - } - - // This seems to clash with a macro on Windows, so #undef it here -#ifdef GetFreeSpace -#undef GetFreeSpace -#endif - Status GetFreeSpace(const std::string& path, uint64_t* diskfree) override { - IOOptions io_opts; - IODebugContext dbg; - return file_system_->GetFreeSpace(path, io_opts, diskfree, &dbg); - } - private: Env* env_target_; }; @@ -880,249 +899,6 @@ class LegacyDirectoryWrapper : public FSDirectory { std::unique_ptr target_; }; -class LegacyFileSystemWrapper : public FileSystem { - public: - // Initialize an EnvWrapper that delegates all calls to *t - explicit LegacyFileSystemWrapper(Env* t) : target_(t) {} - ~LegacyFileSystemWrapper() override {} - - const char* Name() const override { return "Legacy File System"; } - - // Return the target to which this Env forwards all calls - Env* target() const { return target_; } - - // The following text is boilerplate that forwards all methods to target() - IOStatus NewSequentialFile(const std::string& f, - const FileOptions& file_opts, - std::unique_ptr* r, - IODebugContext* /*dbg*/) override { - std::unique_ptr file; - Status s = target_->NewSequentialFile(f, &file, file_opts); - if (s.ok()) { - r->reset(new LegacySequentialFileWrapper(std::move(file))); - } - return status_to_io_status(std::move(s)); - } - IOStatus NewRandomAccessFile(const std::string& f, - const FileOptions& file_opts, - std::unique_ptr* r, - IODebugContext* /*dbg*/) override { - std::unique_ptr file; - Status s = target_->NewRandomAccessFile(f, &file, file_opts); - if (s.ok()) { - r->reset(new LegacyRandomAccessFileWrapper(std::move(file))); - } - return status_to_io_status(std::move(s)); - } - IOStatus NewWritableFile(const std::string& f, const FileOptions& file_opts, - std::unique_ptr* r, - IODebugContext* /*dbg*/) override { - std::unique_ptr file; - Status s = target_->NewWritableFile(f, &file, file_opts); - if (s.ok()) { - r->reset(new LegacyWritableFileWrapper(std::move(file))); - } - return status_to_io_status(std::move(s)); - } - IOStatus ReopenWritableFile(const std::string& fname, - const FileOptions& file_opts, - std::unique_ptr* result, - IODebugContext* /*dbg*/) override { - std::unique_ptr file; - Status s = target_->ReopenWritableFile(fname, &file, file_opts); - if (s.ok()) { - result->reset(new LegacyWritableFileWrapper(std::move(file))); - } - return status_to_io_status(std::move(s)); - } - IOStatus ReuseWritableFile(const std::string& fname, - const std::string& old_fname, - const FileOptions& file_opts, - std::unique_ptr* r, - IODebugContext* /*dbg*/) override { - std::unique_ptr file; - Status s = target_->ReuseWritableFile(fname, old_fname, &file, file_opts); - if (s.ok()) { - r->reset(new LegacyWritableFileWrapper(std::move(file))); - } - return status_to_io_status(std::move(s)); - } - IOStatus NewRandomRWFile(const std::string& fname, - const FileOptions& file_opts, - std::unique_ptr* result, - IODebugContext* /*dbg*/) override { - std::unique_ptr file; - Status s = target_->NewRandomRWFile(fname, &file, file_opts); - if (s.ok()) { - result->reset(new LegacyRandomRWFileWrapper(std::move(file))); - } - return status_to_io_status(std::move(s)); - } - IOStatus NewMemoryMappedFileBuffer( - const std::string& fname, - std::unique_ptr* result) override { - return status_to_io_status( - target_->NewMemoryMappedFileBuffer(fname, result)); - } - IOStatus NewDirectory(const std::string& name, const IOOptions& /*io_opts*/, - std::unique_ptr* result, - IODebugContext* /*dbg*/) override { - std::unique_ptr dir; - Status s = target_->NewDirectory(name, &dir); - if (s.ok()) { - result->reset(new LegacyDirectoryWrapper(std::move(dir))); - } - return status_to_io_status(std::move(s)); - } - IOStatus FileExists(const std::string& f, const IOOptions& /*io_opts*/, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->FileExists(f)); - } - IOStatus GetChildren(const std::string& dir, const IOOptions& /*io_opts*/, - std::vector* r, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->GetChildren(dir, r)); - } - IOStatus GetChildrenFileAttributes(const std::string& dir, - const IOOptions& /*options*/, - std::vector* result, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->GetChildrenFileAttributes(dir, result)); - } - IOStatus DeleteFile(const std::string& f, const IOOptions& /*options*/, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->DeleteFile(f)); - } - IOStatus Truncate(const std::string& fname, size_t size, - const IOOptions& /*options*/, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->Truncate(fname, size)); - } - IOStatus CreateDir(const std::string& d, const IOOptions& /*options*/, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->CreateDir(d)); - } - IOStatus CreateDirIfMissing(const std::string& d, - const IOOptions& /*options*/, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->CreateDirIfMissing(d)); - } - IOStatus DeleteDir(const std::string& d, const IOOptions& /*options*/, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->DeleteDir(d)); - } - IOStatus GetFileSize(const std::string& f, const IOOptions& /*options*/, - uint64_t* s, IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->GetFileSize(f, s)); - } - - IOStatus GetFileModificationTime(const std::string& fname, - const IOOptions& /*options*/, - uint64_t* file_mtime, - IODebugContext* /*dbg*/) override { - return status_to_io_status( - target_->GetFileModificationTime(fname, file_mtime)); - } - - IOStatus GetAbsolutePath(const std::string& db_path, - const IOOptions& /*options*/, - std::string* output_path, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->GetAbsolutePath(db_path, output_path)); - } - - IOStatus RenameFile(const std::string& s, const std::string& t, - const IOOptions& /*options*/, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->RenameFile(s, t)); - } - - IOStatus LinkFile(const std::string& s, const std::string& t, - const IOOptions& /*options*/, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->LinkFile(s, t)); - } - - IOStatus NumFileLinks(const std::string& fname, const IOOptions& /*options*/, - uint64_t* count, IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->NumFileLinks(fname, count)); - } - - IOStatus AreFilesSame(const std::string& first, const std::string& second, - const IOOptions& /*options*/, bool* res, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->AreFilesSame(first, second, res)); - } - - IOStatus LockFile(const std::string& f, const IOOptions& /*options*/, - FileLock** l, IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->LockFile(f, l)); - } - - IOStatus UnlockFile(FileLock* l, const IOOptions& /*options*/, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->UnlockFile(l)); - } - - IOStatus GetTestDirectory(const IOOptions& /*options*/, std::string* path, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->GetTestDirectory(path)); - } - IOStatus NewLogger(const std::string& fname, const IOOptions& /*options*/, - std::shared_ptr* result, - IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->NewLogger(fname, result)); - } - - void SanitizeFileOptions(FileOptions* opts) const override { - target_->SanitizeEnvOptions(opts); - } - - FileOptions OptimizeForLogRead( - const FileOptions& file_options) const override { - return target_->OptimizeForLogRead(file_options); - } - FileOptions OptimizeForManifestRead( - const FileOptions& file_options) const override { - return target_->OptimizeForManifestRead(file_options); - } - FileOptions OptimizeForLogWrite(const FileOptions& file_options, - const DBOptions& db_options) const override { - return target_->OptimizeForLogWrite(file_options, db_options); - } - FileOptions OptimizeForManifestWrite( - const FileOptions& file_options) const override { - return target_->OptimizeForManifestWrite(file_options); - } - FileOptions OptimizeForCompactionTableWrite( - const FileOptions& file_options, - const ImmutableDBOptions& immutable_ops) const override { - return target_->OptimizeForCompactionTableWrite(file_options, - immutable_ops); - } - FileOptions OptimizeForCompactionTableRead( - const FileOptions& file_options, - const ImmutableDBOptions& db_options) const override { - return target_->OptimizeForCompactionTableRead(file_options, db_options); - } - -// This seems to clash with a macro on Windows, so #undef it here -#ifdef GetFreeSpace -#undef GetFreeSpace -#endif - IOStatus GetFreeSpace(const std::string& path, const IOOptions& /*options*/, - uint64_t* diskfree, IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->GetFreeSpace(path, diskfree)); - } - IOStatus IsDirectory(const std::string& path, const IOOptions& /*options*/, - bool* is_dir, IODebugContext* /*dbg*/) override { - return status_to_io_status(target_->IsDirectory(path, is_dir)); - } - - private: - Env* target_; -}; - inline std::unique_ptr NewLegacySequentialFileWrapper( std::unique_ptr& file) { return std::unique_ptr( diff --git a/env/env.cc b/env/env.cc index 06dffce1c..7371fa328 100644 --- a/env/env.cc +++ b/env/env.cc @@ -20,6 +20,248 @@ #include "util/autovector.h" namespace ROCKSDB_NAMESPACE { +namespace { +class LegacyFileSystemWrapper : public FileSystem { + public: + // Initialize an EnvWrapper that delegates all calls to *t + explicit LegacyFileSystemWrapper(Env* t) : target_(t) {} + ~LegacyFileSystemWrapper() override {} + + const char* Name() const override { return "Legacy File System"; } + + // Return the target to which this Env forwards all calls + Env* target() const { return target_; } + + // The following text is boilerplate that forwards all methods to target() + IOStatus NewSequentialFile(const std::string& f, const FileOptions& file_opts, + std::unique_ptr* r, + IODebugContext* /*dbg*/) override { + std::unique_ptr file; + Status s = target_->NewSequentialFile(f, &file, file_opts); + if (s.ok()) { + r->reset(new LegacySequentialFileWrapper(std::move(file))); + } + return status_to_io_status(std::move(s)); + } + IOStatus NewRandomAccessFile(const std::string& f, + const FileOptions& file_opts, + std::unique_ptr* r, + IODebugContext* /*dbg*/) override { + std::unique_ptr file; + Status s = target_->NewRandomAccessFile(f, &file, file_opts); + if (s.ok()) { + r->reset(new LegacyRandomAccessFileWrapper(std::move(file))); + } + return status_to_io_status(std::move(s)); + } + IOStatus NewWritableFile(const std::string& f, const FileOptions& file_opts, + std::unique_ptr* r, + IODebugContext* /*dbg*/) override { + std::unique_ptr file; + Status s = target_->NewWritableFile(f, &file, file_opts); + if (s.ok()) { + r->reset(new LegacyWritableFileWrapper(std::move(file))); + } + return status_to_io_status(std::move(s)); + } + IOStatus ReopenWritableFile(const std::string& fname, + const FileOptions& file_opts, + std::unique_ptr* result, + IODebugContext* /*dbg*/) override { + std::unique_ptr file; + Status s = target_->ReopenWritableFile(fname, &file, file_opts); + if (s.ok()) { + result->reset(new LegacyWritableFileWrapper(std::move(file))); + } + return status_to_io_status(std::move(s)); + } + IOStatus ReuseWritableFile(const std::string& fname, + const std::string& old_fname, + const FileOptions& file_opts, + std::unique_ptr* r, + IODebugContext* /*dbg*/) override { + std::unique_ptr file; + Status s = target_->ReuseWritableFile(fname, old_fname, &file, file_opts); + if (s.ok()) { + r->reset(new LegacyWritableFileWrapper(std::move(file))); + } + return status_to_io_status(std::move(s)); + } + IOStatus NewRandomRWFile(const std::string& fname, + const FileOptions& file_opts, + std::unique_ptr* result, + IODebugContext* /*dbg*/) override { + std::unique_ptr file; + Status s = target_->NewRandomRWFile(fname, &file, file_opts); + if (s.ok()) { + result->reset(new LegacyRandomRWFileWrapper(std::move(file))); + } + return status_to_io_status(std::move(s)); + } + IOStatus NewMemoryMappedFileBuffer( + const std::string& fname, + std::unique_ptr* result) override { + return status_to_io_status( + target_->NewMemoryMappedFileBuffer(fname, result)); + } + IOStatus NewDirectory(const std::string& name, const IOOptions& /*io_opts*/, + std::unique_ptr* result, + IODebugContext* /*dbg*/) override { + std::unique_ptr dir; + Status s = target_->NewDirectory(name, &dir); + if (s.ok()) { + result->reset(new LegacyDirectoryWrapper(std::move(dir))); + } + return status_to_io_status(std::move(s)); + } + IOStatus FileExists(const std::string& f, const IOOptions& /*io_opts*/, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->FileExists(f)); + } + IOStatus GetChildren(const std::string& dir, const IOOptions& /*io_opts*/, + std::vector* r, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->GetChildren(dir, r)); + } + IOStatus GetChildrenFileAttributes(const std::string& dir, + const IOOptions& /*options*/, + std::vector* result, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->GetChildrenFileAttributes(dir, result)); + } + IOStatus DeleteFile(const std::string& f, const IOOptions& /*options*/, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->DeleteFile(f)); + } + IOStatus Truncate(const std::string& fname, size_t size, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->Truncate(fname, size)); + } + IOStatus CreateDir(const std::string& d, const IOOptions& /*options*/, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->CreateDir(d)); + } + IOStatus CreateDirIfMissing(const std::string& d, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->CreateDirIfMissing(d)); + } + IOStatus DeleteDir(const std::string& d, const IOOptions& /*options*/, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->DeleteDir(d)); + } + IOStatus GetFileSize(const std::string& f, const IOOptions& /*options*/, + uint64_t* s, IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->GetFileSize(f, s)); + } + + IOStatus GetFileModificationTime(const std::string& fname, + const IOOptions& /*options*/, + uint64_t* file_mtime, + IODebugContext* /*dbg*/) override { + return status_to_io_status( + target_->GetFileModificationTime(fname, file_mtime)); + } + + IOStatus GetAbsolutePath(const std::string& db_path, + const IOOptions& /*options*/, + std::string* output_path, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->GetAbsolutePath(db_path, output_path)); + } + + IOStatus RenameFile(const std::string& s, const std::string& t, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->RenameFile(s, t)); + } + + IOStatus LinkFile(const std::string& s, const std::string& t, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->LinkFile(s, t)); + } + + IOStatus NumFileLinks(const std::string& fname, const IOOptions& /*options*/, + uint64_t* count, IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->NumFileLinks(fname, count)); + } + + IOStatus AreFilesSame(const std::string& first, const std::string& second, + const IOOptions& /*options*/, bool* res, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->AreFilesSame(first, second, res)); + } + + IOStatus LockFile(const std::string& f, const IOOptions& /*options*/, + FileLock** l, IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->LockFile(f, l)); + } + + IOStatus UnlockFile(FileLock* l, const IOOptions& /*options*/, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->UnlockFile(l)); + } + + IOStatus GetTestDirectory(const IOOptions& /*options*/, std::string* path, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->GetTestDirectory(path)); + } + IOStatus NewLogger(const std::string& fname, const IOOptions& /*options*/, + std::shared_ptr* result, + IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->NewLogger(fname, result)); + } + + void SanitizeFileOptions(FileOptions* opts) const override { + target_->SanitizeEnvOptions(opts); + } + + FileOptions OptimizeForLogRead( + const FileOptions& file_options) const override { + return target_->OptimizeForLogRead(file_options); + } + FileOptions OptimizeForManifestRead( + const FileOptions& file_options) const override { + return target_->OptimizeForManifestRead(file_options); + } + FileOptions OptimizeForLogWrite(const FileOptions& file_options, + const DBOptions& db_options) const override { + return target_->OptimizeForLogWrite(file_options, db_options); + } + FileOptions OptimizeForManifestWrite( + const FileOptions& file_options) const override { + return target_->OptimizeForManifestWrite(file_options); + } + FileOptions OptimizeForCompactionTableWrite( + const FileOptions& file_options, + const ImmutableDBOptions& immutable_ops) const override { + return target_->OptimizeForCompactionTableWrite(file_options, + immutable_ops); + } + FileOptions OptimizeForCompactionTableRead( + const FileOptions& file_options, + const ImmutableDBOptions& db_options) const override { + return target_->OptimizeForCompactionTableRead(file_options, db_options); + } + +#ifdef GetFreeSpace +#undef GetFreeSpace +#endif + IOStatus GetFreeSpace(const std::string& path, const IOOptions& /*options*/, + uint64_t* diskfree, IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->GetFreeSpace(path, diskfree)); + } + IOStatus IsDirectory(const std::string& path, const IOOptions& /*options*/, + bool* is_dir, IODebugContext* /*dbg*/) override { + return status_to_io_status(target_->IsDirectory(path, is_dir)); + } + + private: + Env* target_; +}; +} // end anonymous namespace Env::Env() : thread_status_updater_(nullptr) { file_system_ = std::make_shared(this); @@ -386,13 +628,13 @@ void Log(const std::shared_ptr& info_log, const char* format, ...) { Status WriteStringToFile(Env* env, const Slice& data, const std::string& fname, bool should_sync) { - LegacyFileSystemWrapper lfsw(env); - return WriteStringToFile(&lfsw, data, fname, should_sync); + const auto& fs = env->GetFileSystem(); + return WriteStringToFile(fs.get(), data, fname, should_sync); } Status ReadFileToString(Env* env, const std::string& fname, std::string* data) { - LegacyFileSystemWrapper lfsw(env); - return ReadFileToString(&lfsw, fname, data); + const auto& fs = env->GetFileSystem(); + return ReadFileToString(fs.get(), fname, data); } EnvWrapper::~EnvWrapper() { @@ -488,11 +730,4 @@ Status NewEnvLogger(const std::string& fname, Env* env, const std::shared_ptr& Env::GetFileSystem() const { return file_system_; } - -#ifdef OS_WIN -std::unique_ptr NewCompositeEnv(std::shared_ptr fs) { - return std::unique_ptr(new CompositeEnvWrapper(Env::Default(), fs)); -} -#endif - } // namespace ROCKSDB_NAMESPACE diff --git a/env/env_posix.cc b/env/env_posix.cc index f7efbae80..b28e606eb 100644 --- a/env/env_posix.cc +++ b/env/env_posix.cc @@ -122,14 +122,9 @@ class PosixDynamicLibrary : public DynamicLibrary { }; #endif // !ROCKSDB_NO_DYNAMIC_EXTENSION -class PosixEnv : public CompositeEnvWrapper { +class PosixEnv : public CompositeEnv { public: - // This constructor is for constructing non-default Envs, mainly by - // NewCompositeEnv(). It allows new instances to share the same - // threadpool and other resources as the default Env, while allowing - // a non-default FileSystem implementation - PosixEnv(const PosixEnv* default_env, std::shared_ptr fs); - + PosixEnv(const PosixEnv* default_env, const std::shared_ptr& fs); ~PosixEnv() override { if (this == Env::Default()) { for (const auto tid : threads_to_join_) { @@ -387,7 +382,7 @@ class PosixEnv : public CompositeEnvWrapper { }; PosixEnv::PosixEnv() - : CompositeEnvWrapper(this, FileSystem::Default()), + : CompositeEnv(FileSystem::Default()), thread_pools_storage_(Priority::TOTAL), allow_non_owner_access_storage_(true), thread_pools_(thread_pools_storage_), @@ -404,12 +399,13 @@ PosixEnv::PosixEnv() thread_status_updater_ = CreateThreadStatusUpdater(); } -PosixEnv::PosixEnv(const PosixEnv* default_env, std::shared_ptr fs) - : CompositeEnvWrapper(this, fs), - thread_pools_(default_env->thread_pools_), - mu_(default_env->mu_), - threads_to_join_(default_env->threads_to_join_), - allow_non_owner_access_(default_env->allow_non_owner_access_) { +PosixEnv::PosixEnv(const PosixEnv* default_env, + const std::shared_ptr& fs) + : CompositeEnv(fs), + thread_pools_(default_env->thread_pools_), + mu_(default_env->mu_), + threads_to_join_(default_env->threads_to_join_), + allow_non_owner_access_(default_env->allow_non_owner_access_) { thread_status_updater_ = default_env->thread_status_updater_; } @@ -508,7 +504,7 @@ Env* Env::Default() { return &default_env; } -std::unique_ptr NewCompositeEnv(std::shared_ptr fs) { +std::unique_ptr NewCompositeEnv(const std::shared_ptr& fs) { PosixEnv* default_env = static_cast(Env::Default()); return std::unique_ptr(new PosixEnv(default_env, fs)); } diff --git a/env/file_system.cc b/env/file_system.cc index d2fc06c6c..2a76ee5d3 100644 --- a/env/file_system.cc +++ b/env/file_system.cc @@ -129,13 +129,4 @@ IOStatus ReadFileToString(FileSystem* fs, const std::string& fname, return s; } -#ifdef OS_WIN -std::shared_ptr FileSystem::Default() { - static LegacyFileSystemWrapper default_fs(Env::Default()); - static std::shared_ptr default_fs_ptr( - &default_fs, [](LegacyFileSystemWrapper*) {}); - return default_fs_ptr; -} -#endif - } // namespace ROCKSDB_NAMESPACE diff --git a/file/delete_scheduler_test.cc b/file/delete_scheduler_test.cc index 67eaa50e6..7241dfba5 100644 --- a/file/delete_scheduler_test.cc +++ b/file/delete_scheduler_test.cc @@ -10,7 +10,6 @@ #include #include -#include "env/composite_env_wrapper.h" #include "file/file_util.h" #include "file/sst_file_manager_impl.h" #include "rocksdb/env.h" @@ -96,11 +95,9 @@ class DeleteSchedulerTest : public testing::Test { // Tests in this file are for DeleteScheduler component and don't create any // DBs, so we need to set max_trash_db_ratio to 100% (instead of default // 25%) - std::shared_ptr - fs(std::make_shared(env_)); - sst_file_mgr_.reset( - new SstFileManagerImpl(env_, fs, nullptr, rate_bytes_per_sec_, - /* max_trash_db_ratio= */ 1.1, 128 * 1024)); + sst_file_mgr_.reset(new SstFileManagerImpl( + env_, env_->GetFileSystem(), nullptr, rate_bytes_per_sec_, + /* max_trash_db_ratio= */ 1.1, 128 * 1024)); delete_scheduler_ = sst_file_mgr_->delete_scheduler(); sst_file_mgr_->SetStatisticsPtr(stats_); } diff --git a/file/file_util.h b/file/file_util.h index de92c5e21..ef5ca922f 100644 --- a/file/file_util.h +++ b/file/file_util.h @@ -22,10 +22,23 @@ extern IOStatus CopyFile(FileSystem* fs, const std::string& source, const std::string& destination, uint64_t size, bool use_fsync, const std::shared_ptr& io_tracer = nullptr); +inline IOStatus CopyFile(const std::shared_ptr& fs, + const std::string& source, + const std::string& destination, uint64_t size, + bool use_fsync, + const std::shared_ptr& io_tracer = nullptr) { + return CopyFile(fs.get(), source, destination, size, use_fsync, io_tracer); +} extern IOStatus CreateFile(FileSystem* fs, const std::string& destination, const std::string& contents, bool use_fsync); +inline IOStatus CreateFile(const std::shared_ptr& fs, + const std::string& destination, + const std::string& contents, bool use_fsync) { + return CreateFile(fs.get(), destination, contents, use_fsync); +} + extern Status DeleteDBFile(const ImmutableDBOptions* db_options, const std::string& fname, const std::string& path_to_sync, const bool force_bg, @@ -41,6 +54,19 @@ extern IOStatus GenerateOneFileChecksum( size_t verify_checksums_readahead_size, bool allow_mmap_reads, std::shared_ptr& io_tracer, RateLimiter* rate_limiter = nullptr); +inline IOStatus GenerateOneFileChecksum( + const std::shared_ptr& fs, const std::string& file_path, + FileChecksumGenFactory* checksum_factory, + const std::string& requested_checksum_func_name, std::string* file_checksum, + std::string* file_checksum_func_name, + size_t verify_checksums_readahead_size, bool allow_mmap_reads, + std::shared_ptr& io_tracer) { + return GenerateOneFileChecksum( + fs.get(), file_path, checksum_factory, requested_checksum_func_name, + file_checksum, file_checksum_func_name, verify_checksums_readahead_size, + allow_mmap_reads, io_tracer); +} + inline IOStatus PrepareIOFromReadOptions(const ReadOptions& ro, Env* env, IOOptions& opts) { if (!env) { diff --git a/file/prefetch_test.cc b/file/prefetch_test.cc index 9cd7d1949..3dabb2094 100644 --- a/file/prefetch_test.cc +++ b/file/prefetch_test.cc @@ -75,7 +75,9 @@ std::string BuildKey(int num, std::string postfix = "") { TEST_P(PrefetchTest, Basic) { // First param is if the mockFS support_prefetch or not - bool support_prefetch = std::get<0>(GetParam()); + bool support_prefetch = + std::get<0>(GetParam()) && + test::IsPrefetchSupported(env_->GetFileSystem(), dbname_); // Second param is if directIO is enabled or not bool use_direct_io = std::get<1>(GetParam()); diff --git a/file/sst_file_manager_impl.cc b/file/sst_file_manager_impl.cc index baf58d6b8..46d1a8920 100644 --- a/file/sst_file_manager_impl.cc +++ b/file/sst_file_manager_impl.cc @@ -9,7 +9,6 @@ #include #include "db/db_impl/db_impl.h" -#include "env/composite_env_wrapper.h" #include "port/port.h" #include "rocksdb/env.h" #include "rocksdb/sst_file_manager.h" @@ -485,13 +484,7 @@ SstFileManager* NewSstFileManager(Env* env, std::shared_ptr info_log, bool delete_existing_trash, Status* status, double max_trash_db_ratio, uint64_t bytes_max_delete_chunk) { - std::shared_ptr fs; - - if (env == Env::Default()) { - fs = FileSystem::Default(); - } else { - fs.reset(new LegacyFileSystemWrapper(env)); - } + const auto& fs = env->GetFileSystem(); return NewSstFileManager(env, fs, info_log, trash_dir, rate_bytes_per_sec, delete_existing_trash, status, max_trash_db_ratio, diff --git a/include/rocksdb/env.h b/include/rocksdb/env.h index a129b19a0..5a0ace8cc 100644 --- a/include/rocksdb/env.h +++ b/include/rocksdb/env.h @@ -30,6 +30,7 @@ // Windows API macro interference #undef DeleteFile #undef GetCurrentTime +#undef LoadLibrary #endif #if defined(__GNUC__) || defined(__clang__) @@ -1663,6 +1664,6 @@ Env* NewTimedEnv(Env* base_env); Status NewEnvLogger(const std::string& fname, Env* env, std::shared_ptr* result); -std::unique_ptr NewCompositeEnv(std::shared_ptr fs); +std::unique_ptr NewCompositeEnv(const std::shared_ptr& fs); } // namespace ROCKSDB_NAMESPACE diff --git a/include/rocksdb/file_system.h b/include/rocksdb/file_system.h index e38929db6..393b7647a 100644 --- a/include/rocksdb/file_system.h +++ b/include/rocksdb/file_system.h @@ -366,6 +366,10 @@ class FileSystem { return IOStatus::OK(); } +// This seems to clash with a macro on Windows, so #undef it here +#ifdef DeleteFile +#undef DeleteFile +#endif // Delete the named file. virtual IOStatus DeleteFile(const std::string& fname, const IOOptions& options, @@ -1048,7 +1052,8 @@ class FSDirectory { class FileSystemWrapper : public FileSystem { public: // Initialize an EnvWrapper that delegates all calls to *t - explicit FileSystemWrapper(std::shared_ptr t) : target_(t) {} + explicit FileSystemWrapper(const std::shared_ptr& t) + : target_(t) {} ~FileSystemWrapper() override {} const char* Name() const override { return target_->Name(); } diff --git a/port/win/env_default.cc b/port/win/env_default.cc index 36f95fbe3..0c9958ddd 100644 --- a/port/win/env_default.cc +++ b/port/win/env_default.cc @@ -11,8 +11,8 @@ #include -#include #include "port/win/env_win.h" +#include "rocksdb/env.h" #include "test_util/sync_point.h" #include "util/compression_context_cache.h" #include "util/thread_local.h" diff --git a/port/win/env_win.cc b/port/win/env_win.cc index f7d8f9ce3..9832dc347 100644 --- a/port/win/env_win.cc +++ b/port/win/env_win.cc @@ -10,36 +10,36 @@ #if defined(OS_WIN) #include "port/win/env_win.h" -#include "port/win/win_thread.h" -#include -#include -#include +#include // _rmdir, _mkdir, _getcwd #include -#include // _access -#include // _rmdir, _mkdir, _getcwd -#include +#include // _access +#include // for uuid generation +#include #include +#include +#include -#include "rocksdb/env.h" -#include "rocksdb/slice.h" - -#include "port/port.h" -#include "port/port_dirent.h" -#include "port/win/win_logger.h" -#include "port/win/io_win.h" +#include +#include +#include #include "monitoring/iostats_context_imp.h" - #include "monitoring/thread_status_updater.h" #include "monitoring/thread_status_util.h" - -#include // for uuid generation -#include -#include +#include "port/port.h" +#include "port/port_dirent.h" +#include "port/win/io_win.h" +#include "port/win/win_logger.h" +#include "port/win/win_thread.h" +#include "rocksdb/env.h" +#include "rocksdb/slice.h" #include "strsafe.h" -#include +// Undefine the functions windows might use (again)... +#undef GetCurrentTime +#undef DeleteFile +#undef LoadLibrary namespace ROCKSDB_NAMESPACE { @@ -66,24 +66,13 @@ void WinthreadCall(const char* label, std::error_code result) { } } -} +} // namespace namespace port { - -WinEnvIO::WinEnvIO(Env* hosted_env) - : hosted_env_(hosted_env), - page_size_(4 * 1024), - allocation_granularity_(page_size_), - perf_counter_frequency_(0), +WinClock::WinClock() + : perf_counter_frequency_(0), nano_seconds_per_period_(0), GetSystemTimePreciseAsFileTime_(NULL) { - - SYSTEM_INFO sinfo; - GetSystemInfo(&sinfo); - - page_size_ = sinfo.dwPageSize; - allocation_granularity_ = sinfo.dwAllocationGranularity; - { LARGE_INTEGER qpf; BOOL ret __attribute__((__unused__)); @@ -99,38 +88,95 @@ WinEnvIO::WinEnvIO(Env* hosted_env) HMODULE module = GetModuleHandle("kernel32.dll"); if (module != NULL) { GetSystemTimePreciseAsFileTime_ = - (FnGetSystemTimePreciseAsFileTime)GetProcAddress( - module, "GetSystemTimePreciseAsFileTime"); + (FnGetSystemTimePreciseAsFileTime)GetProcAddress( + module, "GetSystemTimePreciseAsFileTime"); } } -WinEnvIO::~WinEnvIO() { +const std::shared_ptr& WinClock::Default() { + static std::shared_ptr clock = std::make_shared(); + return clock; +} +void WinClock::SleepForMicroseconds(int micros) { + std::this_thread::sleep_for(std::chrono::microseconds(micros)); } -Status WinEnvIO::DeleteFile(const std::string& fname) { - Status result; +std::string WinClock::TimeToString(uint64_t secondsSince1970) { + std::string result; - BOOL ret = RX_DeleteFile(RX_FN(fname).c_str()); + const time_t seconds = secondsSince1970; + const int maxsize = 64; - if(!ret) { - auto lastError = GetLastError(); - result = IOErrorFromWindowsError("Failed to delete: " + fname, - lastError); + struct tm t; + errno_t ret = localtime_s(&t, &seconds); + + if (ret) { + result = std::to_string(seconds); + } else { + result.resize(maxsize); + char* p = &result[0]; + + int len = + snprintf(p, maxsize, "%04d/%02d/%02d-%02d:%02d:%02d ", t.tm_year + 1900, + t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); + assert(len > 0); + + result.resize(len); } return result; } -Status WinEnvIO::Truncate(const std::string& fname, size_t size) { - Status s; - int result = ROCKSDB_NAMESPACE::port::Truncate(fname, size); - if (result != 0) { - s = IOError("Failed to truncate: " + fname, errno); +uint64_t WinClock::NowMicros() { + if (GetSystemTimePreciseAsFileTime_ != NULL) { + // all std::chrono clocks on windows proved to return + // values that may repeat that is not good enough for some uses. + const int64_t c_UnixEpochStartTicks = 116444736000000000LL; + const int64_t c_FtToMicroSec = 10; + + // This interface needs to return system time and not + // just any microseconds because it is often used as an argument + // to TimedWait() on condition variable + FILETIME ftSystemTime; + GetSystemTimePreciseAsFileTime_(&ftSystemTime); + + LARGE_INTEGER li; + li.LowPart = ftSystemTime.dwLowDateTime; + li.HighPart = ftSystemTime.dwHighDateTime; + // Subtract unix epoch start + li.QuadPart -= c_UnixEpochStartTicks; + // Convert to microsecs + li.QuadPart /= c_FtToMicroSec; + return li.QuadPart; } - return s; + using namespace std::chrono; + return duration_cast(system_clock::now().time_since_epoch()) + .count(); +} + +uint64_t WinClock::NowNanos() { + if (nano_seconds_per_period_ != 0) { + // all std::chrono clocks on windows have the same resolution that is only + // good enough for microseconds but not nanoseconds + // On Windows 8 and Windows 2012 Server + // GetSystemTimePreciseAsFileTime(¤t_time) can be used + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + // Convert performance counter to nanoseconds by precomputed ratio. + // Directly multiply nano::den with li.QuadPart causes overflow. + // Only do this when nano::den is divisible by perf_counter_frequency_, + // which most likely is the case in reality. If it's not, fall back to + // high_resolution_clock, which may be less precise under old compilers. + li.QuadPart *= nano_seconds_per_period_; + return li.QuadPart; + } + using namespace std::chrono; + return duration_cast( + high_resolution_clock::now().time_since_epoch()) + .count(); } -Status WinEnvIO::GetCurrentTime(int64_t* unix_time) { +Status WinClock::GetCurrentTime(int64_t* unix_time) { time_t time = std::time(nullptr); if (time == (time_t)(-1)) { return Status::NotSupported("Failed to get time"); @@ -140,10 +186,55 @@ Status WinEnvIO::GetCurrentTime(int64_t* unix_time) { return Status::OK(); } -Status WinEnvIO::NewSequentialFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options) { - Status s; +WinFileSystem::WinFileSystem(const std::shared_ptr& clock) + : clock_(clock), page_size_(4 * 1024), allocation_granularity_(page_size_) { + SYSTEM_INFO sinfo; + GetSystemInfo(&sinfo); + + page_size_ = sinfo.dwPageSize; + allocation_granularity_ = sinfo.dwAllocationGranularity; +} + +const std::shared_ptr& WinFileSystem::Default() { + static std::shared_ptr fs = + std::make_shared(WinClock::Default()); + return fs; +} + +WinEnvIO::WinEnvIO(Env* hosted_env) : hosted_env_(hosted_env) {} + +WinEnvIO::~WinEnvIO() {} + +IOStatus WinFileSystem::DeleteFile(const std::string& fname, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { + IOStatus result; + + BOOL ret = RX_DeleteFile(RX_FN(fname).c_str()); + + if (!ret) { + auto lastError = GetLastError(); + result = IOErrorFromWindowsError("Failed to delete: " + fname, lastError); + } + + return result; +} + +IOStatus WinFileSystem::Truncate(const std::string& fname, size_t size, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { + IOStatus s; + int result = ROCKSDB_NAMESPACE::port::Truncate(fname, size); + if (result != 0) { + s = IOError("Failed to truncate: " + fname, errno); + } + return s; +} + +IOStatus WinFileSystem::NewSequentialFile( + const std::string& fname, const FileOptions& options, + std::unique_ptr* result, IODebugContext* /*dbg*/) { + IOStatus s; result->reset(); @@ -177,11 +268,11 @@ Status WinEnvIO::NewSequentialFile(const std::string& fname, return s; } -Status WinEnvIO::NewRandomAccessFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options) { +IOStatus WinFileSystem::NewRandomAccessFile( + const std::string& fname, const FileOptions& options, + std::unique_ptr* result, IODebugContext* dbg) { result->reset(); - Status s; + IOStatus s; // Open the file for read-only random access // Random access is to disable read-ahead as the system reads too much data @@ -198,10 +289,10 @@ Status WinEnvIO::NewRandomAccessFile(const std::string& fname, HANDLE hFile = 0; { IOSTATS_TIMER_GUARD(open_nanos); - hFile = RX_CreateFile( - RX_FN(fname).c_str(), GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, fileFlags, NULL); + hFile = + RX_CreateFile(RX_FN(fname).c_str(), GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, fileFlags, NULL); } if (INVALID_HANDLE_VALUE == hFile) { @@ -217,13 +308,13 @@ Status WinEnvIO::NewRandomAccessFile(const std::string& fname, // Use mmap when virtual address-space is plentiful. uint64_t fileSize; - s = GetFileSize(fname, &fileSize); + s = GetFileSize(fname, IOOptions(), &fileSize, dbg); if (s.ok()) { // Will not map empty files if (fileSize == 0) { - return IOError( - "NewRandomAccessFile failed to map empty file: " + fname, EINVAL); + return IOError("NewRandomAccessFile failed to map empty file: " + fname, + EINVAL); } HANDLE hMap = RX_CreateFileMapping(hFile, NULL, PAGE_READONLY, @@ -241,11 +332,11 @@ Status WinEnvIO::NewRandomAccessFile(const std::string& fname, UniqueCloseHandlePtr mapGuard(hMap, CloseHandleFunc); const void* mapped_region = - MapViewOfFileEx(hMap, FILE_MAP_READ, - 0, // High DWORD of access start - 0, // Low DWORD - static_cast(fileSize), - NULL); // Let the OS choose the mapping + MapViewOfFileEx(hMap, FILE_MAP_READ, + 0, // High DWORD of access start + 0, // Low DWORD + static_cast(fileSize), + NULL); // Let the OS choose the mapping if (!mapped_region) { auto lastError = GetLastError(); @@ -261,26 +352,22 @@ Status WinEnvIO::NewRandomAccessFile(const std::string& fname, fileGuard.release(); } } else { - result->reset(new WinRandomAccessFile(fname, hFile, - std::max(GetSectorSize(fname), - page_size_), - options)); + result->reset(new WinRandomAccessFile( + fname, hFile, std::max(GetSectorSize(fname), page_size_), options)); fileGuard.release(); } return s; } -Status WinEnvIO::OpenWritableFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options, - bool reopen) { - +IOStatus WinFileSystem::OpenWritableFile( + const std::string& fname, const FileOptions& options, + std::unique_ptr* result, bool reopen) { const size_t c_BufferCapacity = 64 * 1024; EnvOptions local_options(options); result->reset(); - Status s; + IOStatus s; DWORD fileFlags = FILE_ATTRIBUTE_NORMAL; @@ -317,11 +404,11 @@ Status WinEnvIO::OpenWritableFile(const std::string& fname, RX_FN(fname).c_str(), desired_access, // Access desired shared_mode, - NULL, // Security attributes + NULL, // Security attributes // Posix env says (reopen) ? (O_CREATE | O_APPEND) : O_CREAT | O_TRUNC creation_disposition, - fileFlags, // Flags - NULL); // Template File + fileFlags, // Flags + NULL); // Template File } if (INVALID_HANDLE_VALUE == hFile) { @@ -351,25 +438,37 @@ Status WinEnvIO::OpenWritableFile(const std::string& fname, } else { // Here we want the buffer allocation to be aligned by the SSD page size // and to be a multiple of it - result->reset(new WinWritableFile(fname, hFile, - std::max(GetSectorSize(fname), - GetPageSize()), - c_BufferCapacity, local_options)); + result->reset(new WinWritableFile( + fname, hFile, std::max(GetSectorSize(fname), GetPageSize()), + c_BufferCapacity, local_options)); } return s; } -Status WinEnvIO::NewRandomRWFile(const std::string & fname, - std::unique_ptr* result, - const EnvOptions & options) { +IOStatus WinFileSystem::NewWritableFile(const std::string& fname, + const FileOptions& options, + std::unique_ptr* result, + IODebugContext* /*dbg*/) { + return OpenWritableFile(fname, options, result, false); +} - Status s; +IOStatus WinFileSystem::ReopenWritableFile( + const std::string& fname, const FileOptions& options, + std::unique_ptr* result, IODebugContext* /*dbg*/) { + return OpenWritableFile(fname, options, result, true); +} + +IOStatus WinFileSystem::NewRandomRWFile(const std::string& fname, + const FileOptions& options, + std::unique_ptr* result, + IODebugContext* /*dbg*/) { + IOStatus s; // Open the file for read-only random access // Random access is to disable read-ahead as the system reads too much data DWORD desired_access = GENERIC_READ | GENERIC_WRITE; DWORD shared_mode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - DWORD creation_disposition = OPEN_EXISTING; // Fail if file does not exist + DWORD creation_disposition = OPEN_EXISTING; // Fail if file does not exist DWORD file_flags = FILE_FLAG_RANDOM_ACCESS; if (options.use_direct_reads && options.use_direct_writes) { @@ -381,36 +480,28 @@ Status WinEnvIO::NewRandomRWFile(const std::string & fname, HANDLE hFile = 0; { IOSTATS_TIMER_GUARD(open_nanos); - hFile = - RX_CreateFile(RX_FN(fname).c_str(), - desired_access, - shared_mode, - NULL, // Security attributes - creation_disposition, - file_flags, - NULL); + hFile = RX_CreateFile(RX_FN(fname).c_str(), desired_access, shared_mode, + NULL, // Security attributes + creation_disposition, file_flags, NULL); } if (INVALID_HANDLE_VALUE == hFile) { auto lastError = GetLastError(); return IOErrorFromWindowsError( - "NewRandomRWFile failed to Create/Open: " + fname, lastError); + "NewRandomRWFile failed to Create/Open: " + fname, lastError); } UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc); - result->reset(new WinRandomRWFile(fname, hFile, - std::max(GetSectorSize(fname), - GetPageSize()), - options)); + result->reset(new WinRandomRWFile( + fname, hFile, std::max(GetSectorSize(fname), GetPageSize()), options)); fileGuard.release(); return s; } -Status WinEnvIO::NewMemoryMappedFileBuffer( - const std::string & fname, - std::unique_ptr* result) { - Status s; +IOStatus WinFileSystem::NewMemoryMappedFileBuffer( + const std::string& fname, std::unique_ptr* result) { + IOStatus s; result->reset(); DWORD fileFlags = FILE_ATTRIBUTE_READONLY; @@ -420,11 +511,9 @@ Status WinEnvIO::NewMemoryMappedFileBuffer( IOSTATS_TIMER_GUARD(open_nanos); hFile = RX_CreateFile( RX_FN(fname).c_str(), GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, // Open only if it exists - fileFlags, - NULL); + fileFlags, NULL); } if (INVALID_HANDLE_VALUE == hFile) { @@ -436,21 +525,21 @@ Status WinEnvIO::NewMemoryMappedFileBuffer( UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc); uint64_t fileSize = 0; - s = GetFileSize(fname, &fileSize); + s = GetFileSize(fname, IOOptions(), &fileSize, nullptr); if (!s.ok()) { return s; } // Will not map empty files if (fileSize == 0) { - return Status::NotSupported( + return IOStatus::NotSupported( "NewMemoryMappedFileBuffer can not map zero length files: " + fname); } // size_t is 32-bit with 32-bit builds if (fileSize > std::numeric_limits::max()) { - return Status::NotSupported( - "The specified file size does not fit into 32-bit memory addressing: " - + fname); + return IOStatus::NotSupported( + "The specified file size does not fit into 32-bit memory addressing: " + + fname); } HANDLE hMap = RX_CreateFileMapping(hFile, NULL, PAGE_READWRITE, @@ -487,15 +576,16 @@ Status WinEnvIO::NewMemoryMappedFileBuffer( return s; } -Status WinEnvIO::NewDirectory(const std::string& name, - std::unique_ptr* result) { - Status s; +IOStatus WinFileSystem::NewDirectory(const std::string& name, + const IOOptions& /*options*/, + std::unique_ptr* result, + IODebugContext* /*dbg*/) { + IOStatus s; // Must be nullptr on failure result->reset(); if (!DirExists(name)) { - s = IOErrorFromWindowsError( - "open folder: " + name, ERROR_DIRECTORY); + s = IOErrorFromWindowsError("open folder: " + name, ERROR_DIRECTORY); return s; } @@ -505,10 +595,9 @@ Status WinEnvIO::NewDirectory(const std::string& name, IOSTATS_TIMER_GUARD(open_nanos); handle = RX_CreateFile( RX_FN(name).c_str(), 0, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, // make opening folders possible + FILE_FLAG_BACKUP_SEMANTICS, // make opening folders possible NULL); } @@ -523,8 +612,10 @@ Status WinEnvIO::NewDirectory(const std::string& name, return s; } -Status WinEnvIO::FileExists(const std::string& fname) { - Status s; +IOStatus WinFileSystem::FileExists(const std::string& fname, + const IOOptions& /*opts*/, + IODebugContext* /*dbg*/) { + IOStatus s; // TODO: This does not follow symbolic links at this point // which is consistent with _access() impl on windows // but can be added @@ -533,25 +624,26 @@ Status WinEnvIO::FileExists(const std::string& fname) { GetFileExInfoStandard, &attrs)) { auto lastError = GetLastError(); switch (lastError) { - case ERROR_ACCESS_DENIED: - case ERROR_NOT_FOUND: - case ERROR_FILE_NOT_FOUND: - case ERROR_PATH_NOT_FOUND: - s = Status::NotFound(); - break; - default: - s = IOErrorFromWindowsError("Unexpected error for: " + fname, - lastError); - break; + case ERROR_ACCESS_DENIED: + case ERROR_NOT_FOUND: + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + s = IOStatus::NotFound(); + break; + default: + s = IOErrorFromWindowsError("Unexpected error for: " + fname, + lastError); + break; } } return s; } -Status WinEnvIO::GetChildren(const std::string& dir, - std::vector* result) { - - Status status; +IOStatus WinFileSystem::GetChildren(const std::string& dir, + const IOOptions& /*opts*/, + std::vector* result, + IODebugContext* /*dbg*/) { + IOStatus status; result->clear(); std::vector output; @@ -560,26 +652,25 @@ Status WinEnvIO::GetChildren(const std::string& dir, std::string pattern(dir); pattern.append("\\").append("*"); - HANDLE handle = RX_FindFirstFileEx(RX_FN(pattern).c_str(), - // Do not want alternative name - FindExInfoBasic, - &data, - FindExSearchNameMatch, - NULL, // lpSearchFilter - 0); + HANDLE handle = + RX_FindFirstFileEx(RX_FN(pattern).c_str(), + // Do not want alternative name + FindExInfoBasic, &data, FindExSearchNameMatch, + NULL, // lpSearchFilter + 0); if (handle == INVALID_HANDLE_VALUE) { auto lastError = GetLastError(); switch (lastError) { - case ERROR_NOT_FOUND: - case ERROR_ACCESS_DENIED: - case ERROR_FILE_NOT_FOUND: - case ERROR_PATH_NOT_FOUND: - status = Status::NotFound(); - break; - default: - status = IOErrorFromWindowsError( - "Failed to GetChhildren for: " + dir, lastError); + case ERROR_NOT_FOUND: + case ERROR_ACCESS_DENIED: + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + status = IOStatus::NotFound(); + break; + default: + status = IOErrorFromWindowsError("Failed to GetChhildren for: " + dir, + lastError); } return status; } @@ -596,7 +687,7 @@ Status WinEnvIO::GetChildren(const std::string& dir, while (true) { auto x = RX_FILESTRING(data.cFileName, RX_FNLEN(data.cFileName)); output.emplace_back(FN_TO_RX(x)); - BOOL ret =- RX_FindNextFile(handle, &data); + BOOL ret = -RX_FindNextFile(handle, &data); // If the function fails the return value is zero // and non-zero otherwise. Not TRUE or FALSE. if (ret == FALSE) { @@ -609,20 +700,24 @@ Status WinEnvIO::GetChildren(const std::string& dir, return status; } -Status WinEnvIO::CreateDir(const std::string& name) { - Status result; +IOStatus WinFileSystem::CreateDir(const std::string& name, + const IOOptions& /*opts*/, + IODebugContext* /*dbg*/) { + IOStatus result; BOOL ret = RX_CreateDirectory(RX_FN(name).c_str(), NULL); if (!ret) { auto lastError = GetLastError(); - result = IOErrorFromWindowsError( - "Failed to create a directory: " + name, lastError); + result = IOErrorFromWindowsError("Failed to create a directory: " + name, + lastError); } return result; } -Status WinEnvIO::CreateDirIfMissing(const std::string& name) { - Status result; +IOStatus WinFileSystem::CreateDirIfMissing(const std::string& name, + const IOOptions& /*opts*/, + IODebugContext* /*dbg*/) { + IOStatus result; if (DirExists(name)) { return result; @@ -632,30 +727,32 @@ Status WinEnvIO::CreateDirIfMissing(const std::string& name) { if (!ret) { auto lastError = GetLastError(); if (lastError != ERROR_ALREADY_EXISTS) { - result = IOErrorFromWindowsError( - "Failed to create a directory: " + name, lastError); + result = IOErrorFromWindowsError("Failed to create a directory: " + name, + lastError); } else { - result = - Status::IOError(name + ": exists but is not a directory"); + result = IOStatus::IOError(name + ": exists but is not a directory"); } } return result; } -Status WinEnvIO::DeleteDir(const std::string& name) { - Status result; +IOStatus WinFileSystem::DeleteDir(const std::string& name, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { + IOStatus result; BOOL ret = RX_RemoveDirectory(RX_FN(name).c_str()); if (!ret) { auto lastError = GetLastError(); - result = IOErrorFromWindowsError("Failed to remove dir: " + name, - lastError); + result = + IOErrorFromWindowsError("Failed to remove dir: " + name, lastError); } return result; } -Status WinEnvIO::GetFileSize(const std::string& fname, - uint64_t* size) { - Status s; +IOStatus WinFileSystem::GetFileSize(const std::string& fname, + const IOOptions& /*opts*/, uint64_t* size, + IODebugContext* /*dbg*/) { + IOStatus s; WIN32_FILE_ATTRIBUTE_DATA attrs; if (RX_GetFileAttributesEx(RX_FN(fname).c_str(), GetFileExInfoStandard, @@ -671,7 +768,7 @@ Status WinEnvIO::GetFileSize(const std::string& fname, return s; } -uint64_t WinEnvIO::FileTimeToUnixTime(const FILETIME& ftTime) { +uint64_t WinFileSystem::FileTimeToUnixTime(const FILETIME& ftTime) { const uint64_t c_FileTimePerSecond = 10000000U; // UNIX epoch starts on 1970-01-01T00:00:00Z // Windows FILETIME starts on 1601-01-01T00:00:00Z @@ -685,31 +782,35 @@ uint64_t WinEnvIO::FileTimeToUnixTime(const FILETIME& ftTime) { li.LowPart = ftTime.dwLowDateTime; uint64_t result = - (li.QuadPart / c_FileTimePerSecond) - c_SecondBeforeUnixEpoch; + (li.QuadPart / c_FileTimePerSecond) - c_SecondBeforeUnixEpoch; return result; } -Status WinEnvIO::GetFileModificationTime(const std::string& fname, - uint64_t* file_mtime) { - Status s; +IOStatus WinFileSystem::GetFileModificationTime(const std::string& fname, + const IOOptions& /*opts*/, + uint64_t* file_mtime, + IODebugContext* /*dbg*/) { + IOStatus s; WIN32_FILE_ATTRIBUTE_DATA attrs; if (RX_GetFileAttributesEx(RX_FN(fname).c_str(), GetFileExInfoStandard, - &attrs)) { + &attrs)) { *file_mtime = FileTimeToUnixTime(attrs.ftLastWriteTime); } else { auto lastError = GetLastError(); s = IOErrorFromWindowsError( - "Can not get file modification time for: " + fname, lastError); + "Can not get file modification time for: " + fname, lastError); *file_mtime = 0; } return s; } -Status WinEnvIO::RenameFile(const std::string& src, - const std::string& target) { - Status result; +IOStatus WinFileSystem::RenameFile(const std::string& src, + const std::string& target, + const IOOptions& /*opts*/, + IODebugContext* /*dbg*/) { + IOStatus result; // rename() is not capable of replacing the existing file as on Linux // so use OS API directly @@ -726,14 +827,16 @@ Status WinEnvIO::RenameFile(const std::string& src, return result; } -Status WinEnvIO::LinkFile(const std::string& src, - const std::string& target) { - Status result; +IOStatus WinFileSystem::LinkFile(const std::string& src, + const std::string& target, + const IOOptions& /*opts*/, + IODebugContext* /*dbg*/) { + IOStatus result; - if (!RX_CreateHardLink(RX_FN(target).c_str(), RX_FN(src).c_str(), NULL)) { + if (!RX_CreateHardLink(RX_FN(target).c_str(), RX_FN(src).c_str(), NULL)) { DWORD lastError = GetLastError(); if (lastError == ERROR_NOT_SAME_DEVICE) { - return Status::NotSupported("No cross FS links allowed"); + return IOStatus::NotSupported("No cross FS links allowed"); } std::string text("Failed to link: "); @@ -745,12 +848,14 @@ Status WinEnvIO::LinkFile(const std::string& src, return result; } -Status WinEnvIO::NumFileLinks(const std::string& fname, uint64_t* count) { - Status s; - HANDLE handle = RX_CreateFile( - RX_FN(fname).c_str(), 0, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); +IOStatus WinFileSystem::NumFileLinks(const std::string& fname, + const IOOptions& /*opts*/, uint64_t* count, + IODebugContext* /*dbg*/) { + IOStatus s; + HANDLE handle = + RX_CreateFile(RX_FN(fname).c_str(), 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (INVALID_HANDLE_VALUE == handle) { auto lastError = GetLastError(); @@ -771,26 +876,27 @@ Status WinEnvIO::NumFileLinks(const std::string& fname, uint64_t* count) { return s; } -Status WinEnvIO::AreFilesSame(const std::string& first, - const std::string& second, bool* res) { +IOStatus WinFileSystem::AreFilesSame(const std::string& first, + const std::string& second, + const IOOptions& /*opts*/, bool* res, + IODebugContext* /*dbg*/) { // For MinGW builds #if (_WIN32_WINNT == _WIN32_WINNT_VISTA) - Status s = Status::NotSupported(); + IOStatus s = IOStatus::NotSupported(); #else assert(res != nullptr); - Status s; + IOStatus s; if (res == nullptr) { - s = Status::InvalidArgument("res"); + s = IOStatus::InvalidArgument("res"); return s; } // 0 - for access means read metadata HANDLE file_1 = RX_CreateFile( RX_FN(first).c_str(), 0, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, // make opening folders possible + FILE_FLAG_BACKUP_SEMANTICS, // make opening folders possible NULL); if (INVALID_HANDLE_VALUE == file_1) { @@ -802,9 +908,9 @@ Status WinEnvIO::AreFilesSame(const std::string& first, HANDLE file_2 = RX_CreateFile( RX_FN(second).c_str(), 0, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, // make opening folders possible + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, // make opening folders possible NULL); if (INVALID_HANDLE_VALUE == file_2) { @@ -824,9 +930,9 @@ Status WinEnvIO::AreFilesSame(const std::string& first, return s; } - FILE_ID_INFO FileInfo_2; - result = GetFileInformationByHandleEx(file_2, FileIdInfo, &FileInfo_2, - sizeof(FileInfo_2)); + FILE_ID_INFO FileInfo_2; + result = GetFileInformationByHandleEx(file_2, FileIdInfo, &FileInfo_2, + sizeof(FileInfo_2)); if (!result) { auto lastError = GetLastError(); @@ -835,9 +941,9 @@ Status WinEnvIO::AreFilesSame(const std::string& first, } if (FileInfo_1.VolumeSerialNumber == FileInfo_2.VolumeSerialNumber) { - *res = (0 == memcmp(FileInfo_1.FileId.Identifier, - FileInfo_2.FileId.Identifier, - sizeof(FileInfo_1.FileId.Identifier))); + *res = + (0 == memcmp(FileInfo_1.FileId.Identifier, FileInfo_2.FileId.Identifier, + sizeof(FileInfo_1.FileId.Identifier))); } else { *res = false; } @@ -845,12 +951,13 @@ Status WinEnvIO::AreFilesSame(const std::string& first, return s; } -Status WinEnvIO::LockFile(const std::string& lockFname, - FileLock** lock) { +IOStatus WinFileSystem::LockFile(const std::string& lockFname, + const IOOptions& /*opts*/, FileLock** lock, + IODebugContext* /*dbg*/) { assert(lock != nullptr); *lock = NULL; - Status result; + IOStatus result; // No-sharing, this is a LOCK file const DWORD ExclusiveAccessON = 0; @@ -862,15 +969,14 @@ Status WinEnvIO::LockFile(const std::string& lockFname, { IOSTATS_TIMER_GUARD(open_nanos); hFile = RX_CreateFile(RX_FN(lockFname).c_str(), - (GENERIC_READ | GENERIC_WRITE), - ExclusiveAccessON, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); + (GENERIC_READ | GENERIC_WRITE), ExclusiveAccessON, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); } if (INVALID_HANDLE_VALUE == hFile) { auto lastError = GetLastError(); - result = IOErrorFromWindowsError( - "Failed to create lock file: " + lockFname, lastError); + result = IOErrorFromWindowsError("Failed to create lock file: " + lockFname, + lastError); } else { *lock = new WinFileLock(hFile); } @@ -878,8 +984,9 @@ Status WinEnvIO::LockFile(const std::string& lockFname, return result; } -Status WinEnvIO::UnlockFile(FileLock* lock) { - Status result; +IOStatus WinFileSystem::UnlockFile(FileLock* lock, const IOOptions& /*opts*/, + IODebugContext* /*dbg*/) { + IOStatus result; assert(lock != nullptr); @@ -888,8 +995,9 @@ Status WinEnvIO::UnlockFile(FileLock* lock) { return result; } -Status WinEnvIO::GetTestDirectory(std::string* result) { - +IOStatus WinFileSystem::GetTestDirectory(const IOOptions& opts, + std::string* result, + IODebugContext* dbg) { std::string output; const char* env = getenv("TEST_TMPDIR"); @@ -904,21 +1012,23 @@ Status WinEnvIO::GetTestDirectory(std::string* result) { output = "c:\\tmp"; } } - CreateDir(output); + CreateDir(output, opts, dbg); output.append("\\testrocksdb-"); output.append(std::to_string(GetCurrentProcessId())); - CreateDir(output); + CreateDir(output, opts, dbg); output.swap(*result); - return Status::OK(); + return IOStatus::OK(); } -Status WinEnvIO::NewLogger(const std::string& fname, - std::shared_ptr* result) { - Status s; +IOStatus WinFileSystem::NewLogger(const std::string& fname, + const IOOptions& /*opts*/, + std::shared_ptr* result, + IODebugContext* /*dbg*/) { + IOStatus s; result->reset(); @@ -951,72 +1061,25 @@ Status WinEnvIO::NewLogger(const std::string& fname, // Set creation, last access and last write time to the same value SetFileTime(hFile, &ft, &ft, &ft); } - result->reset(new WinLogger(&WinEnvThreads::gettid, hosted_env_, hFile)); + result->reset(new WinLogger(&WinEnvThreads::gettid, clock_, hFile)); } return s; } -Status WinEnvIO::IsDirectory(const std::string& path, bool* is_dir) { +IOStatus WinFileSystem::IsDirectory(const std::string& path, + const IOOptions& /*opts*/, bool* is_dir, + IODebugContext* /*dbg*/) { BOOL ret = RX_PathIsDirectory(RX_FN(path).c_str()); if (is_dir) { *is_dir = ret ? true : false; } - return Status::OK(); -} - -uint64_t WinEnvIO::NowMicros() { - - if (GetSystemTimePreciseAsFileTime_ != NULL) { - // all std::chrono clocks on windows proved to return - // values that may repeat that is not good enough for some uses. - const int64_t c_UnixEpochStartTicks = 116444736000000000LL; - const int64_t c_FtToMicroSec = 10; - - // This interface needs to return system time and not - // just any microseconds because it is often used as an argument - // to TimedWait() on condition variable - FILETIME ftSystemTime; - GetSystemTimePreciseAsFileTime_(&ftSystemTime); - - LARGE_INTEGER li; - li.LowPart = ftSystemTime.dwLowDateTime; - li.HighPart = ftSystemTime.dwHighDateTime; - // Subtract unix epoch start - li.QuadPart -= c_UnixEpochStartTicks; - // Convert to microsecs - li.QuadPart /= c_FtToMicroSec; - return li.QuadPart; - } - using namespace std::chrono; - return duration_cast(system_clock::now().time_since_epoch()) - .count(); -} - -uint64_t WinEnvIO::NowNanos() { - if (nano_seconds_per_period_ != 0) { - // all std::chrono clocks on windows have the same resolution that is only - // good enough for microseconds but not nanoseconds - // On Windows 8 and Windows 2012 Server - // GetSystemTimePreciseAsFileTime(¤t_time) can be used - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - // Convert performance counter to nanoseconds by precomputed ratio. - // Directly multiply nano::den with li.QuadPart causes overflow. - // Only do this when nano::den is divisible by perf_counter_frequency_, - // which most likely is the case in reality. If it's not, fall back to - // high_resolution_clock, which may be less precise under old compilers. - li.QuadPart *= nano_seconds_per_period_; - return li.QuadPart; - } - using namespace std::chrono; - return duration_cast( - high_resolution_clock::now().time_since_epoch()).count(); + return IOStatus::OK(); } Status WinEnvIO::GetHostName(char* name, uint64_t len) { Status s; DWORD nSize = static_cast( - std::min(len, std::numeric_limits::max())); + std::min(len, std::numeric_limits::max())); if (!::GetComputerNameA(name, &nSize)) { auto lastError = GetLastError(); @@ -1028,15 +1091,17 @@ Status WinEnvIO::GetHostName(char* name, uint64_t len) { return s; } -Status WinEnvIO::GetAbsolutePath(const std::string& db_path, - std::string* output_path) { +IOStatus WinFileSystem::GetAbsolutePath(const std::string& db_path, + const IOOptions& /*options*/, + std::string* output_path, + IODebugContext* dbg) { // Check if we already have an absolute path // For test compatibility we will consider starting slash as an // absolute path if ((!db_path.empty() && (db_path[0] == '\\' || db_path[0] == '/')) || - !RX_PathIsRelative(RX_FN(db_path).c_str())) { + !RX_PathIsRelative(RX_FN(db_path).c_str())) { *output_path = db_path; - return Status::OK(); + return IOStatus::OK(); } RX_FILESTRING result; @@ -1055,42 +1120,19 @@ Status WinEnvIO::GetAbsolutePath(const std::string& db_path, std::string res = FN_TO_RX(result); res.swap(*output_path); - return Status::OK(); -} - -std::string WinEnvIO::TimeToString(uint64_t secondsSince1970) { - std::string result; - - const time_t seconds = secondsSince1970; - const int maxsize = 64; - - struct tm t; - errno_t ret = localtime_s(&t, &seconds); - - if (ret) { - result = std::to_string(seconds); - } else { - result.resize(maxsize); - char* p = &result[0]; - - int len = snprintf(p, maxsize, "%04d/%02d/%02d-%02d:%02d:%02d ", - t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, - t.tm_min, t.tm_sec); - assert(len > 0); - - result.resize(len); - } - - return result; + return IOStatus::OK(); } -Status WinEnvIO::GetFreeSpace(const std::string& path, uint64_t* diskfree) { +IOStatus WinFileSystem::GetFreeSpace(const std::string& path, + const IOOptions& /*options*/, + uint64_t* diskfree, + IODebugContext* /*dbg*/) { assert(diskfree != nullptr); ULARGE_INTEGER freeBytes; BOOL f = RX_GetDiskFreeSpaceEx(RX_FN(path).c_str(), &freeBytes, NULL, NULL); if (f) { *diskfree = freeBytes.QuadPart; - return Status::OK(); + return IOStatus::OK(); } else { DWORD lastError = GetLastError(); return IOErrorFromWindowsError("Failed to get free space: " + path, @@ -1098,9 +1140,9 @@ Status WinEnvIO::GetFreeSpace(const std::string& path, uint64_t* diskfree) { } } -EnvOptions WinEnvIO::OptimizeForLogWrite(const EnvOptions& env_options, - const DBOptions& db_options) const { - EnvOptions optimized(env_options); +FileOptions WinFileSystem::OptimizeForLogWrite( + const FileOptions& file_options, const DBOptions& db_options) const { + FileOptions optimized(file_options); // These two the same as default optimizations optimized.bytes_per_sync = db_options.wal_bytes_per_sync; optimized.writable_file_max_buffer_size = @@ -1114,33 +1156,33 @@ EnvOptions WinEnvIO::OptimizeForLogWrite(const EnvOptions& env_options, return optimized; } -EnvOptions WinEnvIO::OptimizeForManifestWrite( - const EnvOptions& env_options) const { - EnvOptions optimized(env_options); +FileOptions WinFileSystem::OptimizeForManifestWrite( + const FileOptions& options) const { + FileOptions optimized(options); optimized.use_mmap_writes = false; optimized.use_direct_reads = false; return optimized; } -EnvOptions WinEnvIO::OptimizeForManifestRead( - const EnvOptions& env_options) const { - EnvOptions optimized(env_options); +FileOptions WinFileSystem::OptimizeForManifestRead( + const FileOptions& file_options) const { + FileOptions optimized(file_options); optimized.use_mmap_writes = false; optimized.use_direct_reads = false; return optimized; } // Returns true iff the named directory exists and is a directory. -bool WinEnvIO::DirExists(const std::string& dname) { +bool WinFileSystem::DirExists(const std::string& dname) { WIN32_FILE_ATTRIBUTE_DATA attrs; - if (RX_GetFileAttributesEx(RX_FN(dname).c_str(), - GetFileExInfoStandard, &attrs)) { + if (RX_GetFileAttributesEx(RX_FN(dname).c_str(), GetFileExInfoStandard, + &attrs)) { return 0 != (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); } return false; } -size_t WinEnvIO::GetSectorSize(const std::string& fname) { +size_t WinFileSystem::GetSectorSize(const std::string& fname) { size_t sector_size = kSectorSize; if (RX_PathIsRelative(RX_FN(fname).c_str())) { @@ -1170,21 +1212,21 @@ size_t WinEnvIO::GetSectorSize(const std::string& fname) { BYTE output_buffer[sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR)]; DWORD output_bytes = 0; - BOOL ret = DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, - &spropertyquery, sizeof(spropertyquery), - output_buffer, - sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR), - &output_bytes, nullptr); + BOOL ret = DeviceIoControl( + hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &spropertyquery, + sizeof(spropertyquery), output_buffer, + sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR), &output_bytes, nullptr); if (ret) { - sector_size = ((STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR *)output_buffer)->BytesPerLogicalSector; + sector_size = ((STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR*)output_buffer) + ->BytesPerLogicalSector; } else { - // many devices do not support StorageProcessAlignmentProperty. Any failure here and we - // fall back to logical alignment + // many devices do not support StorageProcessAlignmentProperty. Any failure + // here and we fall back to logical alignment - DISK_GEOMETRY_EX geometry = { 0 }; - ret = DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, - nullptr, 0, &geometry, sizeof(geometry), &output_bytes, nullptr); + DISK_GEOMETRY_EX geometry = {0}; + ret = DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, nullptr, 0, + &geometry, sizeof(geometry), &output_bytes, nullptr); if (ret) { sector_size = geometry.Geometry.BytesPerSector; } @@ -1202,17 +1244,15 @@ size_t WinEnvIO::GetSectorSize(const std::string& fname) { WinEnvThreads::WinEnvThreads(Env* hosted_env) : hosted_env_(hosted_env), thread_pools_(Env::Priority::TOTAL) { - for (int pool_id = 0; pool_id < Env::Priority::TOTAL; ++pool_id) { thread_pools_[pool_id].SetThreadPriority( - static_cast(pool_id)); + static_cast(pool_id)); // This allows later initializing the thread-local-env of each thread. thread_pools_[pool_id].SetHostEnv(hosted_env); } } WinEnvThreads::~WinEnvThreads() { - WaitForJoin(); for (auto& thpool : thread_pools_) { @@ -1220,9 +1260,9 @@ WinEnvThreads::~WinEnvThreads() { } } -void WinEnvThreads::Schedule(void(*function)(void*), void* arg, +void WinEnvThreads::Schedule(void (*function)(void*), void* arg, Env::Priority pri, void* tag, - void(*unschedFunction)(void* arg)) { + void (*unschedFunction)(void* arg)) { assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH); thread_pools_[pri].Schedule(function, arg, tag, unschedFunction); } @@ -1233,21 +1273,21 @@ int WinEnvThreads::UnSchedule(void* arg, Env::Priority pri) { namespace { - struct StartThreadState { - void(*user_function)(void*); - void* arg; - }; +struct StartThreadState { + void (*user_function)(void*); + void* arg; +}; - void* StartThreadWrapper(void* arg) { - std::unique_ptr state( +void* StartThreadWrapper(void* arg) { + std::unique_ptr state( reinterpret_cast(arg)); - state->user_function(state->arg); - return nullptr; - } - + state->user_function(state->arg); + return nullptr; } -void WinEnvThreads::StartThread(void(*function)(void* arg), void* arg) { +} // namespace + +void WinEnvThreads::StartThread(void (*function)(void* arg), void* arg) { std::unique_ptr state(new StartThreadState); state->user_function = function; state->arg = arg; @@ -1282,10 +1322,6 @@ uint64_t WinEnvThreads::gettid() { uint64_t WinEnvThreads::GetThreadID() const { return gettid(); } -void WinEnvThreads::SleepForMicroseconds(int micros) { - std::this_thread::sleep_for(std::chrono::microseconds(micros)); -} - void WinEnvThreads::SetBackgroundThreads(int num, Env::Priority pri) { assert(pri >= Env::Priority::BOTTOM && pri <= Env::Priority::HIGH); thread_pools_[pri].SetBackgroundThreads(num); @@ -1304,12 +1340,15 @@ void WinEnvThreads::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) { ///////////////////////////////////////////////////////////////////////// // WinEnv -WinEnv::WinEnv() : winenv_io_(this), winenv_threads_(this) { +WinEnv::WinEnv() + : CompositeEnv(WinFileSystem::Default()), + winenv_io_(this), + winenv_threads_(this) { // Protected member of the base class + clock_ = WinClock::Default(); thread_status_updater_ = CreateThreadStatusUpdater(); } - WinEnv::~WinEnv() { // All threads must be joined before the deletion of // thread_status_updater_. @@ -1321,155 +1360,24 @@ Status WinEnv::GetThreadList(std::vector* thread_list) { return thread_status_updater_->GetThreadList(thread_list); } -Status WinEnv::DeleteFile(const std::string& fname) { - return winenv_io_.DeleteFile(fname); -} - -Status WinEnv::Truncate(const std::string& fname, size_t size) { - return winenv_io_.Truncate(fname, size); -} - Status WinEnv::GetCurrentTime(int64_t* unix_time) { - return winenv_io_.GetCurrentTime(unix_time); -} - -Status WinEnv::NewSequentialFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options) { - return winenv_io_.NewSequentialFile(fname, result, options); -} - -Status WinEnv::NewRandomAccessFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options) { - return winenv_io_.NewRandomAccessFile(fname, result, options); -} - -Status WinEnv::NewWritableFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options) { - return winenv_io_.OpenWritableFile(fname, result, options, false); -} - -Status WinEnv::ReopenWritableFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options) { - return winenv_io_.OpenWritableFile(fname, result, options, true); -} - -Status WinEnv::NewRandomRWFile(const std::string & fname, - std::unique_ptr* result, - const EnvOptions & options) { - return winenv_io_.NewRandomRWFile(fname, result, options); -} - -Status WinEnv::NewMemoryMappedFileBuffer( - const std::string& fname, - std::unique_ptr* result) { - return winenv_io_.NewMemoryMappedFileBuffer(fname, result); -} - -Status WinEnv::NewDirectory(const std::string& name, - std::unique_ptr* result) { - return winenv_io_.NewDirectory(name, result); -} - -Status WinEnv::FileExists(const std::string& fname) { - return winenv_io_.FileExists(fname); -} - -Status WinEnv::GetChildren(const std::string& dir, - std::vector* result) { - return winenv_io_.GetChildren(dir, result); -} - -Status WinEnv::CreateDir(const std::string& name) { - return winenv_io_.CreateDir(name); -} - -Status WinEnv::CreateDirIfMissing(const std::string& name) { - return winenv_io_.CreateDirIfMissing(name); -} - -Status WinEnv::DeleteDir(const std::string& name) { - return winenv_io_.DeleteDir(name); -} - -Status WinEnv::GetFileSize(const std::string& fname, - uint64_t* size) { - return winenv_io_.GetFileSize(fname, size); -} - -Status WinEnv::GetFileModificationTime(const std::string& fname, - uint64_t* file_mtime) { - return winenv_io_.GetFileModificationTime(fname, file_mtime); -} - -Status WinEnv::RenameFile(const std::string& src, - const std::string& target) { - return winenv_io_.RenameFile(src, target); -} - -Status WinEnv::LinkFile(const std::string& src, - const std::string& target) { - return winenv_io_.LinkFile(src, target); -} - -Status WinEnv::NumFileLinks(const std::string& fname, uint64_t* count) { - return winenv_io_.NumFileLinks(fname, count); -} - -Status WinEnv::AreFilesSame(const std::string& first, - const std::string& second, bool* res) { - return winenv_io_.AreFilesSame(first, second, res); -} - -Status WinEnv::LockFile(const std::string& lockFname, - FileLock** lock) { - return winenv_io_.LockFile(lockFname, lock); -} - -Status WinEnv::UnlockFile(FileLock* lock) { - return winenv_io_.UnlockFile(lock); -} - -Status WinEnv::GetTestDirectory(std::string* result) { - return winenv_io_.GetTestDirectory(result); -} - -Status WinEnv::NewLogger(const std::string& fname, - std::shared_ptr* result) { - return winenv_io_.NewLogger(fname, result); + return clock_->GetCurrentTime(unix_time); } -Status WinEnv::IsDirectory(const std::string& path, bool* is_dir) { - return winenv_io_.IsDirectory(path, is_dir); -} +uint64_t WinEnv::NowMicros() { return clock_->NowMicros(); } -uint64_t WinEnv::NowMicros() { - return winenv_io_.NowMicros(); -} - -uint64_t WinEnv::NowNanos() { - return winenv_io_.NowNanos(); -} +uint64_t WinEnv::NowNanos() { return clock_->NowNanos(); } Status WinEnv::GetHostName(char* name, uint64_t len) { return winenv_io_.GetHostName(name, len); } -Status WinEnv::GetAbsolutePath(const std::string& db_path, - std::string* output_path) { - return winenv_io_.GetAbsolutePath(db_path, output_path); -} - std::string WinEnv::TimeToString(uint64_t secondsSince1970) { - return winenv_io_.TimeToString(secondsSince1970); + return clock_->TimeToString(secondsSince1970); } -void WinEnv::Schedule(void(*function)(void*), void* arg, Env::Priority pri, - void* tag, - void(*unschedFunction)(void* arg)) { +void WinEnv::Schedule(void (*function)(void*), void* arg, Env::Priority pri, + void* tag, void (*unschedFunction)(void* arg)) { return winenv_threads_.Schedule(function, arg, pri, tag, unschedFunction); } @@ -1477,32 +1385,24 @@ int WinEnv::UnSchedule(void* arg, Env::Priority pri) { return winenv_threads_.UnSchedule(arg, pri); } -void WinEnv::StartThread(void(*function)(void* arg), void* arg) { +void WinEnv::StartThread(void (*function)(void* arg), void* arg) { return winenv_threads_.StartThread(function, arg); } -void WinEnv::WaitForJoin() { - return winenv_threads_.WaitForJoin(); -} +void WinEnv::WaitForJoin() { return winenv_threads_.WaitForJoin(); } -unsigned int WinEnv::GetThreadPoolQueueLen(Env::Priority pri) const { +unsigned int WinEnv::GetThreadPoolQueueLen(Env::Priority pri) const { return winenv_threads_.GetThreadPoolQueueLen(pri); } -uint64_t WinEnv::GetThreadID() const { - return winenv_threads_.GetThreadID(); -} - -Status WinEnv::GetFreeSpace(const std::string& path, uint64_t* diskfree) { - return winenv_io_.GetFreeSpace(path, diskfree); -} +uint64_t WinEnv::GetThreadID() const { return winenv_threads_.GetThreadID(); } void WinEnv::SleepForMicroseconds(int micros) { - return winenv_threads_.SleepForMicroseconds(micros); + return clock_->SleepForMicroseconds(micros); } // Allow increasing the number of worker threads. -void WinEnv::SetBackgroundThreads(int num, Env::Priority pri) { +void WinEnv::SetBackgroundThreads(int num, Env::Priority pri) { return winenv_threads_.SetBackgroundThreads(num, pri); } @@ -1510,25 +1410,10 @@ int WinEnv::GetBackgroundThreads(Env::Priority pri) { return winenv_threads_.GetBackgroundThreads(pri); } -void WinEnv::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) { +void WinEnv::IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) { return winenv_threads_.IncBackgroundThreadsIfNeeded(num, pri); } -EnvOptions WinEnv::OptimizeForManifestRead( - const EnvOptions& env_options) const { - return winenv_io_.OptimizeForManifestRead(env_options); -} - -EnvOptions WinEnv::OptimizeForLogWrite(const EnvOptions& env_options, - const DBOptions& db_options) const { - return winenv_io_.OptimizeForLogWrite(env_options, db_options); -} - -EnvOptions WinEnv::OptimizeForManifestWrite( - const EnvOptions& env_options) const { - return winenv_io_.OptimizeForManifestWrite(env_options); -} - } // namespace port std::string Env::GenerateUniqueId() { @@ -1550,6 +1435,13 @@ std::string Env::GenerateUniqueId() { return result; } +std::shared_ptr FileSystem::Default() { + return port::WinFileSystem::Default(); +} + +std::unique_ptr NewCompositeEnv(const std::shared_ptr& fs) { + return std::unique_ptr(new CompositeEnvWrapper(Env::Default(), fs)); +} } // namespace ROCKSDB_NAMESPACE #endif diff --git a/port/win/env_win.h b/port/win/env_win.h index 24e3a56fe..da4e955ac 100644 --- a/port/win/env_win.h +++ b/port/win/env_win.h @@ -15,30 +15,29 @@ // multiple threads without any external synchronization. #pragma once - -#include "port/win/win_thread.h" -#include -#include "util/threadpool_imp.h" - #include #include #include -#include #include +#include +#include "env/composite_env_wrapper.h" +#include "port/win/win_thread.h" +#include "rocksdb/env.h" +#include "rocksdb/file_system.h" +#include "util/threadpool_imp.h" #undef GetCurrentTime #undef DeleteFile -#undef GetTickCount +#undef LoadLibrary namespace ROCKSDB_NAMESPACE { namespace port { // Currently not designed for inheritance but rather a replacement class WinEnvThreads { -public: - + public: explicit WinEnvThreads(Env* hosted_env); ~WinEnvThreads(); @@ -46,12 +45,12 @@ public: WinEnvThreads(const WinEnvThreads&) = delete; WinEnvThreads& operator=(const WinEnvThreads&) = delete; - void Schedule(void(*function)(void*), void* arg, Env::Priority pri, - void* tag, void(*unschedFunction)(void* arg)); + void Schedule(void (*function)(void*), void* arg, Env::Priority pri, + void* tag, void (*unschedFunction)(void* arg)); int UnSchedule(void* arg, Env::Priority pri); - void StartThread(void(*function)(void* arg), void* arg); + void StartThread(void (*function)(void* arg), void* arg); void WaitForJoin(); @@ -61,235 +60,198 @@ public: uint64_t GetThreadID() const; - void SleepForMicroseconds(int micros); - // Allow increasing the number of worker threads. void SetBackgroundThreads(int num, Env::Priority pri); int GetBackgroundThreads(Env::Priority pri); void IncBackgroundThreadsIfNeeded(int num, Env::Priority pri); -private: - + private: Env* hosted_env_; mutable std::mutex mu_; std::vector thread_pools_; std::vector threads_to_join_; - }; -// Designed for inheritance so can be re-used -// but certain parts replaced -class WinEnvIO { -public: - explicit WinEnvIO(Env* hosted_env); - - virtual ~WinEnvIO(); - - virtual Status DeleteFile(const std::string& fname); - - Status Truncate(const std::string& fname, size_t size); - - virtual Status GetCurrentTime(int64_t* unix_time); - - virtual Status NewSequentialFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options); - - // Helper for NewWritable and ReopenWritableFile - virtual Status OpenWritableFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options, - bool reopen); - - virtual Status NewRandomAccessFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options); - - // The returned file will only be accessed by one thread at a time. - virtual Status NewRandomRWFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options); - - virtual Status NewMemoryMappedFileBuffer( - const std::string& fname, - std::unique_ptr* result); - - virtual Status NewDirectory(const std::string& name, - std::unique_ptr* result); - - virtual Status FileExists(const std::string& fname); - - virtual Status GetChildren(const std::string& dir, - std::vector* result); - - virtual Status CreateDir(const std::string& name); - - virtual Status CreateDirIfMissing(const std::string& name); - - virtual Status DeleteDir(const std::string& name); - - virtual Status GetFileSize(const std::string& fname, uint64_t* size); - - static uint64_t FileTimeToUnixTime(const FILETIME& ftTime); - - virtual Status GetFileModificationTime(const std::string& fname, - uint64_t* file_mtime); - - virtual Status RenameFile(const std::string& src, const std::string& target); - - virtual Status LinkFile(const std::string& src, const std::string& target); - - virtual Status NumFileLinks(const std::string& /*fname*/, - uint64_t* /*count*/); - - virtual Status AreFilesSame(const std::string& first, - const std::string& second, bool* res); - - virtual Status LockFile(const std::string& lockFname, FileLock** lock); - - virtual Status UnlockFile(FileLock* lock); - - virtual Status GetTestDirectory(std::string* result); - - virtual Status NewLogger(const std::string& fname, - std::shared_ptr* result); - - virtual Status IsDirectory(const std::string& path, bool* is_dir); +class WinClock { + public: + static const std::shared_ptr& Default(); + WinClock(); + virtual ~WinClock() {} virtual uint64_t NowMicros(); virtual uint64_t NowNanos(); - virtual Status GetHostName(char* name, uint64_t len); - - virtual Status GetAbsolutePath(const std::string& db_path, - std::string* output_path); - - // This seems to clash with a macro on Windows, so #undef it here -#undef GetFreeSpace - - // Get the amount of free disk space - virtual Status GetFreeSpace(const std::string& path, uint64_t* diskfree); - - virtual std::string TimeToString(uint64_t secondsSince1970); - - virtual EnvOptions OptimizeForLogWrite(const EnvOptions& env_options, - const DBOptions& db_options) const; - - virtual EnvOptions OptimizeForManifestWrite( - const EnvOptions& env_options) const; - - virtual EnvOptions OptimizeForManifestRead( - const EnvOptions& env_options) const; - - size_t GetPageSize() const { return page_size_; } + virtual void SleepForMicroseconds(int micros); - size_t GetAllocationGranularity() const { return allocation_granularity_; } + virtual Status GetCurrentTime(int64_t* unix_time); + // Converts seconds-since-Jan-01-1970 to a printable string + virtual std::string TimeToString(uint64_t time); uint64_t GetPerfCounterFrequency() const { return perf_counter_frequency_; } - static size_t GetSectorSize(const std::string& fname); - -private: - // Returns true iff the named directory exists and is a directory. - virtual bool DirExists(const std::string& dname); - - typedef VOID(WINAPI * FnGetSystemTimePreciseAsFileTime)(LPFILETIME); + private: + typedef VOID(WINAPI* FnGetSystemTimePreciseAsFileTime)(LPFILETIME); - Env* hosted_env_; - size_t page_size_; - size_t allocation_granularity_; uint64_t perf_counter_frequency_; uint64_t nano_seconds_per_period_; FnGetSystemTimePreciseAsFileTime GetSystemTimePreciseAsFileTime_; }; -class WinEnv : public Env { -public: - WinEnv(); - - ~WinEnv(); - - Status DeleteFile(const std::string& fname) override; - - Status Truncate(const std::string& fname, size_t size) override; - - Status GetCurrentTime(int64_t* unix_time) override; +class WinFileSystem : public FileSystem { + public: + static const std::shared_ptr& Default(); + WinFileSystem(const std::shared_ptr& clock); + ~WinFileSystem() {} + const char* Name() const { return "WinFS"; } + static size_t GetSectorSize(const std::string& fname); + size_t GetPageSize() const { return page_size_; } + size_t GetAllocationGranularity() const { return allocation_granularity_; } - Status NewSequentialFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options) override; - - Status NewRandomAccessFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options) override; - - Status NewWritableFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options) override; - - // Create an object that writes to a new file with the specified - // name. Deletes any existing file with the same name and creates a - // new file. On success, stores a pointer to the new file in - // *result and returns OK. On failure stores nullptr in *result and - // returns non-OK. - // - // The returned file will only be accessed by one thread at a time. - Status ReopenWritableFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options) override; - - // The returned file will only be accessed by one thread at a time. - Status NewRandomRWFile(const std::string& fname, - std::unique_ptr* result, - const EnvOptions& options) override; - - Status NewMemoryMappedFileBuffer( + IOStatus DeleteFile(const std::string& fname, const IOOptions& options, + IODebugContext* dbg) override; + + // Truncate the named file to the specified size. + IOStatus Truncate(const std::string& /*fname*/, size_t /*size*/, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) override; + IOStatus NewSequentialFile(const std::string& fname, + const FileOptions& file_opts, + std::unique_ptr* result, + IODebugContext* dbg) override; + + IOStatus NewRandomAccessFile(const std::string& fname, + const FileOptions& options, + std::unique_ptr* result, + IODebugContext* /*dbg*/) override; + IOStatus NewWritableFile(const std::string& f, const FileOptions& file_opts, + std::unique_ptr* r, + IODebugContext* dbg) override; + IOStatus ReopenWritableFile(const std::string& fname, + const FileOptions& options, + std::unique_ptr* result, + IODebugContext* dbg) override; + + IOStatus NewRandomRWFile(const std::string& fname, + const FileOptions& file_opts, + std::unique_ptr* result, + IODebugContext* dbg) override; + IOStatus NewMemoryMappedFileBuffer( const std::string& fname, std::unique_ptr* result) override; - Status NewDirectory(const std::string& name, - std::unique_ptr* result) override; - - Status FileExists(const std::string& fname) override; - - Status GetChildren(const std::string& dir, - std::vector* result) override; - - Status CreateDir(const std::string& name) override; - - Status CreateDirIfMissing(const std::string& name) override; - - Status DeleteDir(const std::string& name) override; - - Status GetFileSize(const std::string& fname, - uint64_t* size) override; - - Status GetFileModificationTime(const std::string& fname, - uint64_t* file_mtime) override; - - Status RenameFile(const std::string& src, - const std::string& target) override; + IOStatus NewDirectory(const std::string& name, const IOOptions& io_opts, + std::unique_ptr* result, + IODebugContext* dbg) override; + IOStatus FileExists(const std::string& f, const IOOptions& io_opts, + IODebugContext* dbg) override; + IOStatus GetChildren(const std::string& dir, const IOOptions& io_opts, + std::vector* r, + IODebugContext* dbg) override; + IOStatus CreateDir(const std::string& dirname, const IOOptions& options, + IODebugContext* dbg) override; + + // Creates directory if missing. Return Ok if it exists, or successful in + // Creating. + IOStatus CreateDirIfMissing(const std::string& dirname, + const IOOptions& options, + IODebugContext* dbg) override; + + // Delete the specified directory. + IOStatus DeleteDir(const std::string& dirname, const IOOptions& options, + IODebugContext* dbg) override; + // Store the size of fname in *file_size. + IOStatus GetFileSize(const std::string& fname, const IOOptions& options, + uint64_t* file_size, IODebugContext* dbg) override; + // Store the last modification time of fname in *file_mtime. + IOStatus GetFileModificationTime(const std::string& fname, + const IOOptions& options, + uint64_t* file_mtime, + IODebugContext* dbg) override; + // Rename file src to target. + IOStatus RenameFile(const std::string& src, const std::string& target, + const IOOptions& options, IODebugContext* dbg) override; + + // Hard Link file src to target. + IOStatus LinkFile(const std::string& /*src*/, const std::string& /*target*/, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) override; + IOStatus NumFileLinks(const std::string& /*fname*/, + const IOOptions& /*options*/, uint64_t* /*count*/, + IODebugContext* /*dbg*/) override; + IOStatus AreFilesSame(const std::string& /*first*/, + const std::string& /*second*/, + const IOOptions& /*options*/, bool* /*res*/, + IODebugContext* /*dbg*/) override; + IOStatus LockFile(const std::string& fname, const IOOptions& options, + FileLock** lock, IODebugContext* dbg) override; + IOStatus UnlockFile(FileLock* lock, const IOOptions& options, + IODebugContext* dbg) override; + IOStatus GetTestDirectory(const IOOptions& options, std::string* path, + IODebugContext* dbg) override; + + // Create and returns a default logger (an instance of EnvLogger) for storing + // informational messages. Derived classes can overide to provide custom + // logger. + IOStatus NewLogger(const std::string& fname, const IOOptions& io_opts, + std::shared_ptr* result, + IODebugContext* dbg) override; + // Get full directory name for this db. + IOStatus GetAbsolutePath(const std::string& db_path, const IOOptions& options, + std::string* output_path, + IODebugContext* dbg) override; + IOStatus IsDirectory(const std::string& /*path*/, const IOOptions& options, + bool* is_dir, IODebugContext* /*dgb*/) override; + // This seems to clash with a macro on Windows, so #undef it here +#undef GetFreeSpace + IOStatus GetFreeSpace(const std::string& /*path*/, + const IOOptions& /*options*/, uint64_t* /*diskfree*/, + IODebugContext* /*dbg*/) override; + FileOptions OptimizeForLogWrite(const FileOptions& file_options, + const DBOptions& db_options) const override; + FileOptions OptimizeForManifestRead( + const FileOptions& file_options) const override; + FileOptions OptimizeForManifestWrite( + const FileOptions& file_options) const override; + + protected: + static uint64_t FileTimeToUnixTime(const FILETIME& ftTime); + // Returns true iff the named directory exists and is a directory. - Status LinkFile(const std::string& src, - const std::string& target) override; + virtual bool DirExists(const std::string& dname); + // Helper for NewWritable and ReopenWritableFile + virtual IOStatus OpenWritableFile(const std::string& fname, + const FileOptions& options, + std::unique_ptr* result, + bool reopen); - Status NumFileLinks(const std::string& fname, uint64_t* count) override; + private: + std::shared_ptr clock_; + size_t page_size_; + size_t allocation_granularity_; +}; - Status AreFilesSame(const std::string& first, - const std::string& second, bool* res) override; +// Designed for inheritance so can be re-used +// but certain parts replaced +class WinEnvIO { + public: + explicit WinEnvIO(Env* hosted_env); - Status LockFile(const std::string& lockFname, FileLock** lock) override; + virtual ~WinEnvIO(); - Status UnlockFile(FileLock* lock) override; + virtual Status GetHostName(char* name, uint64_t len); - Status GetTestDirectory(std::string* result) override; + private: + Env* hosted_env_; +}; - Status NewLogger(const std::string& fname, - std::shared_ptr* result) override; +class WinEnv : public CompositeEnv { + public: + WinEnv(); - Status IsDirectory(const std::string& path, bool* is_dir) override; + ~WinEnv(); + Status GetCurrentTime(int64_t* unix_time) override; uint64_t NowMicros() override; @@ -297,19 +259,16 @@ public: Status GetHostName(char* name, uint64_t len) override; - Status GetAbsolutePath(const std::string& db_path, - std::string* output_path) override; - std::string TimeToString(uint64_t secondsSince1970) override; Status GetThreadList(std::vector* thread_list) override; - void Schedule(void(*function)(void*), void* arg, Env::Priority pri, - void* tag, void(*unschedFunction)(void* arg)) override; + void Schedule(void (*function)(void*), void* arg, Env::Priority pri, + void* tag, void (*unschedFunction)(void* arg)) override; int UnSchedule(void* arg, Env::Priority pri) override; - void StartThread(void(*function)(void* arg), void* arg) override; + void StartThread(void (*function)(void* arg), void* arg) override; void WaitForJoin() override; @@ -317,12 +276,6 @@ public: uint64_t GetThreadID() const override; - // This seems to clash with a macro on Windows, so #undef it here -#undef GetFreeSpace - - // Get the amount of free disk space - Status GetFreeSpace(const std::string& path, uint64_t* diskfree) override; - void SleepForMicroseconds(int micros) override; // Allow increasing the number of worker threads. @@ -331,21 +284,11 @@ public: void IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) override; - EnvOptions OptimizeForManifestRead( - const EnvOptions& env_options) const override; - - EnvOptions OptimizeForLogWrite(const EnvOptions& env_options, - const DBOptions& db_options) const override; - - EnvOptions OptimizeForManifestWrite( - const EnvOptions& env_options) const override; - - -private: - + private: + std::shared_ptr clock_; WinEnvIO winenv_io_; WinEnvThreads winenv_threads_; }; -} // namespace port +} // namespace port } // namespace ROCKSDB_NAMESPACE diff --git a/port/win/io_win.cc b/port/win/io_win.cc index f8d1c3dbb..2ec7710f4 100644 --- a/port/win/io_win.cc +++ b/port/win/io_win.cc @@ -20,36 +20,32 @@ namespace ROCKSDB_NAMESPACE { namespace port { /* -* DirectIOHelper -*/ + * DirectIOHelper + */ namespace { const size_t kSectorSize = 512; -inline -bool IsPowerOfTwo(const size_t alignment) { +inline bool IsPowerOfTwo(const size_t alignment) { return ((alignment) & (alignment - 1)) == 0; } -inline -bool IsSectorAligned(const size_t off) { +inline bool IsSectorAligned(const size_t off) { return (off & (kSectorSize - 1)) == 0; } -inline -bool IsAligned(size_t alignment, const void* ptr) { +inline bool IsAligned(size_t alignment, const void* ptr) { return ((uintptr_t(ptr)) & (alignment - 1)) == 0; } -} - +} // namespace std::string GetWindowsErrSz(DWORD err) { LPSTR lpMsgBuf; FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, err, - 0, // Default language - reinterpret_cast(&lpMsgBuf), 0, NULL); + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, + 0, // Default language + reinterpret_cast(&lpMsgBuf), 0, NULL); std::string Err = lpMsgBuf; LocalFree(lpMsgBuf); @@ -69,21 +65,20 @@ std::string GetWindowsErrSz(DWORD err) { // Because all the reads/writes happen by the specified offset, the caller in // theory should not // rely on the current file offset. -Status pwrite(const WinFileData* file_data, const Slice& data, - uint64_t offset, size_t& bytes_written) { - - Status s; +IOStatus pwrite(const WinFileData* file_data, const Slice& data, + uint64_t offset, size_t& bytes_written) { + IOStatus s; bytes_written = 0; size_t num_bytes = data.size(); if (num_bytes > std::numeric_limits::max()) { // May happen in 64-bit builds where size_t is 64-bits but // long is still 32-bit, but that's the API here at the moment - return Status::InvalidArgument("num_bytes is too large for a single write: " + - file_data->GetName()); + return IOStatus::InvalidArgument( + "num_bytes is too large for a single write: " + file_data->GetName()); } - OVERLAPPED overlapped = { 0 }; + OVERLAPPED overlapped = {0}; ULARGE_INTEGER offsetUnion; offsetUnion.QuadPart = offset; @@ -92,11 +87,12 @@ Status pwrite(const WinFileData* file_data, const Slice& data, DWORD bytesWritten = 0; - if (FALSE == WriteFile(file_data->GetFileHandle(), data.data(), static_cast(num_bytes), - &bytesWritten, &overlapped)) { + if (FALSE == WriteFile(file_data->GetFileHandle(), data.data(), + static_cast(num_bytes), &bytesWritten, + &overlapped)) { auto lastError = GetLastError(); s = IOErrorFromWindowsError("WriteFile failed: " + file_data->GetName(), - lastError); + lastError); } else { bytes_written = bytesWritten; } @@ -105,18 +101,17 @@ Status pwrite(const WinFileData* file_data, const Slice& data, } // See comments for pwrite above -Status pread(const WinFileData* file_data, char* src, size_t num_bytes, - uint64_t offset, size_t& bytes_read) { - - Status s; +IOStatus pread(const WinFileData* file_data, char* src, size_t num_bytes, + uint64_t offset, size_t& bytes_read) { + IOStatus s; bytes_read = 0; if (num_bytes > std::numeric_limits::max()) { - return Status::InvalidArgument("num_bytes is too large for a single read: " + - file_data->GetName()); + return IOStatus::InvalidArgument( + "num_bytes is too large for a single read: " + file_data->GetName()); } - OVERLAPPED overlapped = { 0 }; + OVERLAPPED overlapped = {0}; ULARGE_INTEGER offsetUnion; offsetUnion.QuadPart = offset; @@ -125,13 +120,14 @@ Status pread(const WinFileData* file_data, char* src, size_t num_bytes, DWORD bytesRead = 0; - if (FALSE == ReadFile(file_data->GetFileHandle(), src, static_cast(num_bytes), - &bytesRead, &overlapped)) { + if (FALSE == ReadFile(file_data->GetFileHandle(), src, + static_cast(num_bytes), &bytesRead, + &overlapped)) { auto lastError = GetLastError(); // EOF is OK with zero bytes read if (lastError != ERROR_HANDLE_EOF) { s = IOErrorFromWindowsError("ReadFile failed: " + file_data->GetName(), - lastError); + lastError); } } else { bytes_read = bytesRead; @@ -143,35 +139,34 @@ Status pread(const WinFileData* file_data, char* src, size_t num_bytes, // SetFileInformationByHandle() is capable of fast pre-allocates. // However, this does not change the file end position unless the file is // truncated and the pre-allocated space is not considered filled with zeros. -Status fallocate(const std::string& filename, HANDLE hFile, - uint64_t to_size) { - Status status; +IOStatus fallocate(const std::string& filename, HANDLE hFile, + uint64_t to_size) { + IOStatus status; FILE_ALLOCATION_INFO alloc_info; alloc_info.AllocationSize.QuadPart = to_size; if (!SetFileInformationByHandle(hFile, FileAllocationInfo, &alloc_info, - sizeof(FILE_ALLOCATION_INFO))) { + sizeof(FILE_ALLOCATION_INFO))) { auto lastError = GetLastError(); status = IOErrorFromWindowsError( - "Failed to pre-allocate space: " + filename, lastError); + "Failed to pre-allocate space: " + filename, lastError); } return status; } -Status ftruncate(const std::string& filename, HANDLE hFile, - uint64_t toSize) { - Status status; +IOStatus ftruncate(const std::string& filename, HANDLE hFile, uint64_t toSize) { + IOStatus status; FILE_END_OF_FILE_INFO end_of_file; end_of_file.EndOfFile.QuadPart = toSize; if (!SetFileInformationByHandle(hFile, FileEndOfFileInfo, &end_of_file, - sizeof(FILE_END_OF_FILE_INFO))) { + sizeof(FILE_END_OF_FILE_INFO))) { auto lastError = GetLastError(); status = IOErrorFromWindowsError("Failed to Set end of file: " + filename, - lastError); + lastError); } return status; @@ -212,9 +207,11 @@ WinMmapReadableFile::~WinMmapReadableFile() { assert(ret); } -Status WinMmapReadableFile::Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const { - Status s; +IOStatus WinMmapReadableFile::Read(uint64_t offset, size_t n, + const IOOptions& /*options*/, Slice* result, + char* scratch, + IODebugContext* /*dbg*/) const { + IOStatus s; if (offset > length_) { *result = Slice(); @@ -222,13 +219,12 @@ Status WinMmapReadableFile::Read(uint64_t offset, size_t n, Slice* result, } else if (offset + n > length_) { n = length_ - static_cast(offset); } - *result = - Slice(reinterpret_cast(mapped_region_)+offset, n); + *result = Slice(reinterpret_cast(mapped_region_) + offset, n); return s; } -Status WinMmapReadableFile::InvalidateCache(size_t offset, size_t length) { - return Status::OK(); +IOStatus WinMmapReadableFile::InvalidateCache(size_t offset, size_t length) { + return IOStatus::OK(); } size_t WinMmapReadableFile::GetUniqueId(char* id, size_t max_size) const { @@ -238,20 +234,19 @@ size_t WinMmapReadableFile::GetUniqueId(char* id, size_t max_size) const { /////////////////////////////////////////////////////////////////////////////// /// WinMmapFile - // Can only truncate or reserve to a sector size aligned if // used on files that are opened with Unbuffered I/O -Status WinMmapFile::TruncateFile(uint64_t toSize) { +IOStatus WinMmapFile::TruncateFile(uint64_t toSize) { return ftruncate(filename_, hFile_, toSize); } -Status WinMmapFile::UnmapCurrentRegion() { - Status status; +IOStatus WinMmapFile::UnmapCurrentRegion() { + IOStatus status; if (mapped_begin_ != nullptr) { if (!::UnmapViewOfFile(mapped_begin_)) { status = IOErrorFromWindowsError( - "Failed to unmap file view: " + filename_, GetLastError()); + "Failed to unmap file view: " + filename_, GetLastError()); } // Move on to the next portion of the file @@ -271,16 +266,16 @@ Status WinMmapFile::UnmapCurrentRegion() { return status; } -Status WinMmapFile::MapNewRegion() { - - Status status; +IOStatus WinMmapFile::MapNewRegion(const IOOptions& options, + IODebugContext* dbg) { + IOStatus status; assert(mapped_begin_ == nullptr); size_t minDiskSize = static_cast(file_offset_) + view_size_; if (minDiskSize > reserved_size_) { - status = Allocate(file_offset_, view_size_); + status = Allocate(file_offset_, view_size_, options, dbg); if (!status.ok()) { return status; } @@ -288,7 +283,6 @@ Status WinMmapFile::MapNewRegion() { // Need to remap if (hMap_ == NULL || reserved_size_ > mapping_size_) { - if (hMap_ != NULL) { // Unmap the previous one BOOL ret __attribute__((__unused__)); @@ -301,18 +295,18 @@ Status WinMmapFile::MapNewRegion() { mappingSize.QuadPart = reserved_size_; hMap_ = CreateFileMappingA( - hFile_, - NULL, // Security attributes - PAGE_READWRITE, // There is not a write only mode for mapping - mappingSize.HighPart, // Enable mapping the whole file but the actual - // amount mapped is determined by MapViewOfFile - mappingSize.LowPart, - NULL); // Mapping name + hFile_, + NULL, // Security attributes + PAGE_READWRITE, // There is not a write only mode for mapping + mappingSize.HighPart, // Enable mapping the whole file but the actual + // amount mapped is determined by MapViewOfFile + mappingSize.LowPart, + NULL); // Mapping name if (NULL == hMap_) { return IOErrorFromWindowsError( - "WindowsMmapFile failed to create file mapping for: " + filename_, - GetLastError()); + "WindowsMmapFile failed to create file mapping for: " + filename_, + GetLastError()); } mapping_size_ = reserved_size_; @@ -323,13 +317,13 @@ Status WinMmapFile::MapNewRegion() { // View must begin at the granularity aligned offset mapped_begin_ = reinterpret_cast( - MapViewOfFileEx(hMap_, FILE_MAP_WRITE, offset.HighPart, offset.LowPart, - view_size_, NULL)); + MapViewOfFileEx(hMap_, FILE_MAP_WRITE, offset.HighPart, offset.LowPart, + view_size_, NULL)); if (!mapped_begin_) { status = IOErrorFromWindowsError( - "WindowsMmapFile failed to map file view: " + filename_, - GetLastError()); + "WindowsMmapFile failed to map file view: " + filename_, + GetLastError()); } else { mapped_end_ = mapped_begin_ + view_size_; dst_ = mapped_begin_; @@ -339,15 +333,15 @@ Status WinMmapFile::MapNewRegion() { return status; } -Status WinMmapFile::PreallocateInternal(uint64_t spaceToReserve) { +IOStatus WinMmapFile::PreallocateInternal(uint64_t spaceToReserve) { return fallocate(filename_, hFile_, spaceToReserve); } WinMmapFile::WinMmapFile(const std::string& fname, HANDLE hFile, size_t page_size, size_t allocation_granularity, - const EnvOptions& options) + const FileOptions& options) : WinFileData(fname, hFile, false), - WritableFile(options), + FSWritableFile(options), hMap_(NULL), page_size_(page_size), allocation_granularity_(allocation_granularity), @@ -373,17 +367,19 @@ WinMmapFile::WinMmapFile(const std::string& fname, HANDLE hFile, // View size must be both the multiple of allocation_granularity AND the // page size and the granularity is usually a multiple of a page size. - const size_t viewSize = 32 * 1024; // 32Kb similar to the Windows File Cache in buffered mode + const size_t viewSize = + 32 * 1024; // 32Kb similar to the Windows File Cache in buffered mode view_size_ = Roundup(viewSize, allocation_granularity_); } WinMmapFile::~WinMmapFile() { if (hFile_) { - this->Close(); + this->Close(IOOptions(), nullptr); } } -Status WinMmapFile::Append(const Slice& data) { +IOStatus WinMmapFile::Append(const Slice& data, const IOOptions& options, + IODebugContext* dbg) { const char* src = data.data(); size_t left = data.size(); @@ -392,9 +388,9 @@ Status WinMmapFile::Append(const Slice& data) { size_t avail = mapped_end_ - dst_; if (avail == 0) { - Status s = UnmapCurrentRegion(); + IOStatus s = UnmapCurrentRegion(); if (s.ok()) { - s = MapNewRegion(); + s = MapNewRegion(options, dbg); } if (!s.ok()) { @@ -416,30 +412,31 @@ Status WinMmapFile::Append(const Slice& data) { memset(dst_, 0, bytesToPad); } - return Status::OK(); + return IOStatus::OK(); } // Means Close() will properly take care of truncate // and it does not need any additional information -Status WinMmapFile::Truncate(uint64_t size) { - return Status::OK(); +IOStatus WinMmapFile::Truncate(uint64_t size, const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { + return IOStatus::OK(); } -Status WinMmapFile::Close() { - Status s; +IOStatus WinMmapFile::Close(const IOOptions& options, IODebugContext* dbg) { + IOStatus s; assert(NULL != hFile_); // We truncate to the precise size so no // uninitialized data at the end. SetEndOfFile // which we use does not write zeros and it is good. - uint64_t targetSize = GetFileSize(); + uint64_t targetSize = GetFileSize(options, dbg); if (mapped_begin_ != nullptr) { // Sync before unmapping to make sure everything // is on disk and there is not a lazy writing // so we are deterministic with the tests - Sync(); + Sync(options, dbg); s = UnmapCurrentRegion(); } @@ -448,14 +445,13 @@ Status WinMmapFile::Close() { if (!ret && s.ok()) { auto lastError = GetLastError(); s = IOErrorFromWindowsError( - "Failed to Close mapping for file: " + filename_, lastError); + "Failed to Close mapping for file: " + filename_, lastError); } hMap_ = NULL; } if (hFile_ != NULL) { - TruncateFile(targetSize); BOOL ret = ::CloseHandle(hFile_); @@ -464,18 +460,22 @@ Status WinMmapFile::Close() { if (!ret && s.ok()) { auto lastError = GetLastError(); s = IOErrorFromWindowsError( - "Failed to close file map handle: " + filename_, lastError); + "Failed to close file map handle: " + filename_, lastError); } } return s; } -Status WinMmapFile::Flush() { return Status::OK(); } +IOStatus WinMmapFile::Flush(const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { + return IOStatus::OK(); +} // Flush only data -Status WinMmapFile::Sync() { - Status s; +IOStatus WinMmapFile::Sync(const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { + IOStatus s; // Some writes occurred since last sync if (dst_ > last_sync_) { @@ -485,15 +485,15 @@ Status WinMmapFile::Sync() { assert(dst_ < mapped_end_); size_t page_begin = - TruncateToPageBoundary(page_size_, last_sync_ - mapped_begin_); + TruncateToPageBoundary(page_size_, last_sync_ - mapped_begin_); size_t page_end = - TruncateToPageBoundary(page_size_, dst_ - mapped_begin_ - 1); + TruncateToPageBoundary(page_size_, dst_ - mapped_begin_ - 1); // Flush only the amount of that is a multiple of pages if (!::FlushViewOfFile(mapped_begin_ + page_begin, - (page_end - page_begin) + page_size_)) { + (page_end - page_begin) + page_size_)) { s = IOErrorFromWindowsError("Failed to FlushViewOfFile: " + filename_, - GetLastError()); + GetLastError()); } else { last_sync_ = dst_; } @@ -503,16 +503,16 @@ Status WinMmapFile::Sync() { } /** -* Flush data as well as metadata to stable storage. -*/ -Status WinMmapFile::Fsync() { - Status s = Sync(); + * Flush data as well as metadata to stable storage. + */ +IOStatus WinMmapFile::Fsync(const IOOptions& options, IODebugContext* dbg) { + IOStatus s = Sync(options, dbg); // Flush metadata if (s.ok() && pending_sync_) { if (!::FlushFileBuffers(hFile_)) { s = IOErrorFromWindowsError("Failed to FlushFileBuffers: " + filename_, - GetLastError()); + GetLastError()); } pending_sync_ = false; } @@ -521,27 +521,31 @@ Status WinMmapFile::Fsync() { } /** -* Get the size of valid data in the file. This will not match the -* size that is returned from the filesystem because we use mmap -* to extend file by map_size every time. -*/ -uint64_t WinMmapFile::GetFileSize() { + * Get the size of valid data in the file. This will not match the + * size that is returned from the filesystem because we use mmap + * to extend file by map_size every time. + */ +uint64_t WinMmapFile::GetFileSize(const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { size_t used = dst_ - mapped_begin_; return file_offset_ + used; } -Status WinMmapFile::InvalidateCache(size_t offset, size_t length) { - return Status::OK(); +IOStatus WinMmapFile::InvalidateCache(size_t offset, size_t length) { + return IOStatus::OK(); } -Status WinMmapFile::Allocate(uint64_t offset, uint64_t len) { - Status status; +IOStatus WinMmapFile::Allocate(uint64_t offset, uint64_t len, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { + IOStatus status; TEST_KILL_RANDOM("WinMmapFile::Allocate", rocksdb_kill_odds); // Make sure that we reserve an aligned amount of space // since the reservation block size is driven outside so we want // to check if we are ok with reservation here - size_t spaceToReserve = Roundup(static_cast(offset + len), view_size_); + size_t spaceToReserve = + Roundup(static_cast(offset + len), view_size_); // Nothing to do if (spaceToReserve <= reserved_size_) { return status; @@ -563,31 +567,34 @@ size_t WinMmapFile::GetUniqueId(char* id, size_t max_size) const { // WinSequentialFile WinSequentialFile::WinSequentialFile(const std::string& fname, HANDLE f, - const EnvOptions& options) + const FileOptions& options) : WinFileData(fname, f, options.use_direct_reads) {} WinSequentialFile::~WinSequentialFile() { assert(hFile_ != INVALID_HANDLE_VALUE); } -Status WinSequentialFile::Read(size_t n, Slice* result, char* scratch) { - Status s; +IOStatus WinSequentialFile::Read(size_t n, const IOOptions& /*opts*/, + Slice* result, char* scratch, + IODebugContext* /*dbg*/) { + IOStatus s; size_t r = 0; assert(result != nullptr); if (WinFileData::use_direct_io()) { - return Status::NotSupported("Read() does not support direct_io"); + return IOStatus::NotSupported("Read() does not support direct_io"); } // Windows ReadFile API accepts a DWORD. // While it is possible to read in a loop if n is too big // it is an unlikely case. if (n > std::numeric_limits::max()) { - return Status::InvalidArgument("n is too big for a single ReadFile: " - + filename_); + return IOStatus::InvalidArgument("n is too big for a single ReadFile: " + + filename_); } - DWORD bytesToRead = static_cast(n); //cast is safe due to the check above + DWORD bytesToRead = + static_cast(n); // cast is safe due to the check above DWORD bytesRead = 0; BOOL ret = ReadFile(hFile_, scratch, bytesToRead, &bytesRead, NULL); if (ret != FALSE) { @@ -595,8 +602,7 @@ Status WinSequentialFile::Read(size_t n, Slice* result, char* scratch) { } else { auto lastError = GetLastError(); if (lastError != ERROR_HANDLE_EOF) { - s = IOErrorFromWindowsError("ReadFile failed: " + filename_, - lastError); + s = IOErrorFromWindowsError("ReadFile failed: " + filename_, lastError); } } @@ -604,99 +610,91 @@ Status WinSequentialFile::Read(size_t n, Slice* result, char* scratch) { return s; } -Status WinSequentialFile::PositionedReadInternal(char* src, size_t numBytes, - uint64_t offset, size_t& bytes_read) const { +IOStatus WinSequentialFile::PositionedReadInternal(char* src, size_t numBytes, + uint64_t offset, + size_t& bytes_read) const { return pread(this, src, numBytes, offset, bytes_read); } -Status WinSequentialFile::PositionedRead(uint64_t offset, size_t n, Slice* result, - char* scratch) { - - Status s; - +IOStatus WinSequentialFile::PositionedRead(uint64_t offset, size_t n, + const IOOptions& /*opts*/, + Slice* result, char* scratch, + IODebugContext* /*dbg*/) { if (!WinFileData::use_direct_io()) { - return Status::NotSupported("This function is only used for direct_io"); + return IOStatus::NotSupported("This function is only used for direct_io"); } - if (!IsSectorAligned(static_cast(offset)) || - !IsSectorAligned(n)) { - return Status::InvalidArgument( + if (!IsSectorAligned(static_cast(offset)) || !IsSectorAligned(n)) { + return IOStatus::InvalidArgument( "WinSequentialFile::PositionedRead: offset is not properly aligned"); } - size_t bytes_read = 0; // out param - s = PositionedReadInternal(scratch, static_cast(n), offset, bytes_read); + size_t bytes_read = 0; // out param + IOStatus s = PositionedReadInternal(scratch, static_cast(n), offset, + bytes_read); *result = Slice(scratch, bytes_read); return s; } - -Status WinSequentialFile::Skip(uint64_t n) { - // Can't handle more than signed max as SetFilePointerEx accepts a signed 64-bit - // integer. As such it is a highly unlikley case to have n so large. +IOStatus WinSequentialFile::Skip(uint64_t n) { + // Can't handle more than signed max as SetFilePointerEx accepts a signed + // 64-bit integer. As such it is a highly unlikley case to have n so large. if (n > static_cast(std::numeric_limits::max())) { - return Status::InvalidArgument("n is too large for a single SetFilePointerEx() call" + - filename_); + return IOStatus::InvalidArgument( + "n is too large for a single SetFilePointerEx() call" + filename_); } LARGE_INTEGER li; - li.QuadPart = static_cast(n); //cast is safe due to the check above + li.QuadPart = static_cast(n); // cast is safe due to the check + // above BOOL ret = SetFilePointerEx(hFile_, li, NULL, FILE_CURRENT); if (ret == FALSE) { auto lastError = GetLastError(); return IOErrorFromWindowsError("Skip SetFilePointerEx():" + filename_, lastError); } - return Status::OK(); + return IOStatus::OK(); } -Status WinSequentialFile::InvalidateCache(size_t offset, size_t length) { - return Status::OK(); +IOStatus WinSequentialFile::InvalidateCache(size_t offset, size_t length) { + return IOStatus::OK(); } ////////////////////////////////////////////////////////////////////////////////////////////////// /// WinRandomAccessBase -inline -Status WinRandomAccessImpl::PositionedReadInternal(char* src, - size_t numBytes, - uint64_t offset, - size_t& bytes_read) const { +inline IOStatus WinRandomAccessImpl::PositionedReadInternal( + char* src, size_t numBytes, uint64_t offset, size_t& bytes_read) const { return pread(file_base_, src, numBytes, offset, bytes_read); } -inline -WinRandomAccessImpl::WinRandomAccessImpl(WinFileData* file_base, - size_t alignment, - const EnvOptions& options) : - file_base_(file_base), - alignment_(alignment) { - +inline WinRandomAccessImpl::WinRandomAccessImpl(WinFileData* file_base, + size_t alignment, + const FileOptions& options) + : file_base_(file_base), alignment_(alignment) { assert(!options.use_mmap_reads); } -inline -Status WinRandomAccessImpl::ReadImpl(uint64_t offset, size_t n, Slice* result, - char* scratch) const { - - Status s; - +inline IOStatus WinRandomAccessImpl::ReadImpl(uint64_t offset, size_t n, + Slice* result, + char* scratch) const { // Check buffer alignment if (file_base_->use_direct_io()) { if (!IsSectorAligned(static_cast(offset)) || !IsAligned(alignment_, scratch)) { - return Status::InvalidArgument( - "WinRandomAccessImpl::ReadImpl: offset or scratch is not properly aligned"); + return IOStatus::InvalidArgument( + "WinRandomAccessImpl::ReadImpl: offset or scratch is not properly " + "aligned"); } } if (n == 0) { *result = Slice(scratch, 0); - return s; + return IOStatus::OK(); } size_t bytes_read = 0; - s = PositionedReadInternal(scratch, n, offset, bytes_read); + IOStatus s = PositionedReadInternal(scratch, n, offset, bytes_read); *result = Slice(scratch, bytes_read); return s; } @@ -706,20 +704,21 @@ Status WinRandomAccessImpl::ReadImpl(uint64_t offset, size_t n, Slice* result, WinRandomAccessFile::WinRandomAccessFile(const std::string& fname, HANDLE hFile, size_t alignment, - const EnvOptions& options) + const FileOptions& options) : WinFileData(fname, hFile, options.use_direct_reads), WinRandomAccessImpl(this, alignment, options) {} -WinRandomAccessFile::~WinRandomAccessFile() { -} +WinRandomAccessFile::~WinRandomAccessFile() {} -Status WinRandomAccessFile::Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const { +IOStatus WinRandomAccessFile::Read(uint64_t offset, size_t n, + const IOOptions& /*options*/, Slice* result, + char* scratch, + IODebugContext* /*dbg*/) const { return ReadImpl(offset, n, result, scratch); } -Status WinRandomAccessFile::InvalidateCache(size_t offset, size_t length) { - return Status::OK(); +IOStatus WinRandomAccessFile::InvalidateCache(size_t offset, size_t length) { + return IOStatus::OK(); } size_t WinRandomAccessFile::GetUniqueId(char* id, size_t max_size) const { @@ -734,27 +733,26 @@ size_t WinRandomAccessFile::GetRequiredBufferAlignment() const { // WinWritableImpl // -inline -Status WinWritableImpl::PreallocateInternal(uint64_t spaceToReserve) { - return fallocate(file_data_->GetName(), file_data_->GetFileHandle(), spaceToReserve); +inline IOStatus WinWritableImpl::PreallocateInternal(uint64_t spaceToReserve) { + return fallocate(file_data_->GetName(), file_data_->GetFileHandle(), + spaceToReserve); } -inline -WinWritableImpl::WinWritableImpl(WinFileData* file_data, size_t alignment) - : file_data_(file_data), - alignment_(alignment), - next_write_offset_(0), - reservedsize_(0) { - +inline WinWritableImpl::WinWritableImpl(WinFileData* file_data, + size_t alignment) + : file_data_(file_data), + alignment_(alignment), + next_write_offset_(0), + reservedsize_(0) { // Query current position in case ReopenWritableFile is called // This position is only important for buffered writes // for unbuffered writes we explicitely specify the position. LARGE_INTEGER zero_move; - zero_move.QuadPart = 0; // Do not move + zero_move.QuadPart = 0; // Do not move LARGE_INTEGER pos; pos.QuadPart = 0; BOOL ret = SetFilePointerEx(file_data_->GetFileHandle(), zero_move, &pos, - FILE_CURRENT); + FILE_CURRENT); // Querying no supped to fail if (ret != 0) { next_write_offset_ = pos.QuadPart; @@ -763,17 +761,15 @@ WinWritableImpl::WinWritableImpl(WinFileData* file_data, size_t alignment) } } -inline -Status WinWritableImpl::AppendImpl(const Slice& data) { - - Status s; +inline IOStatus WinWritableImpl::AppendImpl(const Slice& data) { + IOStatus s; if (data.size() > std::numeric_limits::max()) { - return Status::InvalidArgument("data is too long for a single write" + - file_data_->GetName()); + return IOStatus::InvalidArgument("data is too long for a single write" + + file_data_->GetName()); } - size_t bytes_written = 0; // out param + size_t bytes_written = 0; // out param if (file_data_->use_direct_io()) { // With no offset specified we are appending @@ -781,56 +777,53 @@ Status WinWritableImpl::AppendImpl(const Slice& data) { assert(IsSectorAligned(next_write_offset_)); if (!IsSectorAligned(data.size()) || !IsAligned(static_cast(GetAlignement()), data.data())) { - s = Status::InvalidArgument( - "WriteData must be page aligned, size must be sector aligned"); + s = IOStatus::InvalidArgument( + "WriteData must be page aligned, size must be sector aligned"); } else { s = pwrite(file_data_, data, next_write_offset_, bytes_written); } } else { - DWORD bytesWritten = 0; if (!WriteFile(file_data_->GetFileHandle(), data.data(), - static_cast(data.size()), &bytesWritten, NULL)) { + static_cast(data.size()), &bytesWritten, NULL)) { auto lastError = GetLastError(); s = IOErrorFromWindowsError( - "Failed to WriteFile: " + file_data_->GetName(), - lastError); + "Failed to WriteFile: " + file_data_->GetName(), lastError); } else { bytes_written = bytesWritten; } } - if(s.ok()) { + if (s.ok()) { if (bytes_written == data.size()) { // This matters for direct_io cases where // we rely on the fact that next_write_offset_ // is sector aligned next_write_offset_ += bytes_written; } else { - s = Status::IOError("Failed to write all bytes: " + - file_data_->GetName()); + s = IOStatus::IOError("Failed to write all bytes: " + + file_data_->GetName()); } } return s; } -inline -Status WinWritableImpl::PositionedAppendImpl(const Slice& data, uint64_t offset) { - - if(file_data_->use_direct_io()) { +inline IOStatus WinWritableImpl::PositionedAppendImpl(const Slice& data, + uint64_t offset) { + if (file_data_->use_direct_io()) { if (!IsSectorAligned(static_cast(offset)) || !IsSectorAligned(data.size()) || !IsAligned(static_cast(GetAlignement()), data.data())) { - return Status::InvalidArgument( - "Data and offset must be page aligned, size must be sector aligned"); + return IOStatus::InvalidArgument( + "Data and offset must be page aligned, size must be sector aligned"); } } size_t bytes_written = 0; - Status s = pwrite(file_data_, data, offset, bytes_written); + IOStatus s = pwrite(file_data_, data, offset, bytes_written); - if(s.ok()) { + if (s.ok()) { if (bytes_written == data.size()) { // For sequential write this would be simple // size extension by data.size() @@ -839,23 +832,21 @@ Status WinWritableImpl::PositionedAppendImpl(const Slice& data, uint64_t offset) next_write_offset_ = write_end; } } else { - s = Status::IOError("Failed to write all of the requested data: " + - file_data_->GetName()); + s = IOStatus::IOError("Failed to write all of the requested data: " + + file_data_->GetName()); } } return s; } -inline -Status WinWritableImpl::TruncateImpl(uint64_t size) { - +inline IOStatus WinWritableImpl::TruncateImpl(uint64_t size) { // It is tempting to check for the size for sector alignment // but truncation may come at the end and there is not a requirement // for this to be sector aligned so long as we do not attempt to write // after that. The interface docs state that the behavior is undefined // in that case. - Status s = ftruncate(file_data_->GetName(), file_data_->GetFileHandle(), - size); + IOStatus s = + ftruncate(file_data_->GetName(), file_data_->GetFileHandle(), size); if (s.ok()) { next_write_offset_ = size; @@ -863,50 +854,48 @@ Status WinWritableImpl::TruncateImpl(uint64_t size) { return s; } -inline -Status WinWritableImpl::CloseImpl() { - - Status s; +inline IOStatus WinWritableImpl::CloseImpl() { + IOStatus s; auto hFile = file_data_->GetFileHandle(); assert(INVALID_HANDLE_VALUE != hFile); if (!::FlushFileBuffers(hFile)) { auto lastError = GetLastError(); - s = IOErrorFromWindowsError("FlushFileBuffers failed at Close() for: " + - file_data_->GetName(), - lastError); + s = IOErrorFromWindowsError( + "FlushFileBuffers failed at Close() for: " + file_data_->GetName(), + lastError); } - if(!file_data_->CloseFile() && s.ok()) { + if (!file_data_->CloseFile() && s.ok()) { auto lastError = GetLastError(); - s = IOErrorFromWindowsError("CloseHandle failed for: " + file_data_->GetName(), - lastError); + s = IOErrorFromWindowsError( + "CloseHandle failed for: " + file_data_->GetName(), lastError); } return s; } -inline -Status WinWritableImpl::SyncImpl() { - Status s; - if (!::FlushFileBuffers (file_data_->GetFileHandle())) { +inline IOStatus WinWritableImpl::SyncImpl(const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { + IOStatus s; + if (!::FlushFileBuffers(file_data_->GetFileHandle())) { auto lastError = GetLastError(); s = IOErrorFromWindowsError( - "FlushFileBuffers failed at Sync() for: " + file_data_->GetName(), lastError); + "FlushFileBuffers failed at Sync() for: " + file_data_->GetName(), + lastError); } return s; } - -inline -Status WinWritableImpl::AllocateImpl(uint64_t offset, uint64_t len) { - Status status; +inline IOStatus WinWritableImpl::AllocateImpl(uint64_t offset, uint64_t len) { + IOStatus status; TEST_KILL_RANDOM("WinWritableFile::Allocate", rocksdb_kill_odds); // Make sure that we reserve an aligned amount of space // since the reservation block size is driven outside so we want // to check if we are ok with reservation here - size_t spaceToReserve = Roundup(static_cast(offset + len), static_cast(alignment_)); + size_t spaceToReserve = Roundup(static_cast(offset + len), + static_cast(alignment_)); // Nothing to do if (spaceToReserve <= reservedsize_) { return status; @@ -920,66 +909,78 @@ Status WinWritableImpl::AllocateImpl(uint64_t offset, uint64_t len) { return status; } - //////////////////////////////////////////////////////////////////////////////// /// WinWritableFile WinWritableFile::WinWritableFile(const std::string& fname, HANDLE hFile, size_t alignment, size_t /* capacity */, - const EnvOptions& options) + const FileOptions& options) : WinFileData(fname, hFile, options.use_direct_writes), WinWritableImpl(this, alignment), - WritableFile(options) { + FSWritableFile(options) { assert(!options.use_mmap_writes); } -WinWritableFile::~WinWritableFile() { -} +WinWritableFile::~WinWritableFile() {} // Indicates if the class makes use of direct I/O -bool WinWritableFile::use_direct_io() const { return WinFileData::use_direct_io(); } +bool WinWritableFile::use_direct_io() const { + return WinFileData::use_direct_io(); +} size_t WinWritableFile::GetRequiredBufferAlignment() const { return static_cast(GetAlignement()); } -Status WinWritableFile::Append(const Slice& data) { +IOStatus WinWritableFile::Append(const Slice& data, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { return AppendImpl(data); } -Status WinWritableFile::PositionedAppend(const Slice& data, uint64_t offset) { +IOStatus WinWritableFile::PositionedAppend(const Slice& data, uint64_t offset, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { return PositionedAppendImpl(data, offset); } // Need to implement this so the file is truncated correctly // when buffered and unbuffered mode -Status WinWritableFile::Truncate(uint64_t size) { +IOStatus WinWritableFile::Truncate(uint64_t size, const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { return TruncateImpl(size); } -Status WinWritableFile::Close() { +IOStatus WinWritableFile::Close(const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { return CloseImpl(); } - // write out the cached data to the OS cache - // This is now taken care of the WritableFileWriter -Status WinWritableFile::Flush() { - return Status::OK(); +// write out the cached data to the OS cache +// This is now taken care of the WritableFileWriter +IOStatus WinWritableFile::Flush(const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { + return IOStatus::OK(); } -Status WinWritableFile::Sync() { - return SyncImpl(); +IOStatus WinWritableFile::Sync(const IOOptions& options, IODebugContext* dbg) { + return SyncImpl(options, dbg); } -Status WinWritableFile::Fsync() { return SyncImpl(); } +IOStatus WinWritableFile::Fsync(const IOOptions& options, IODebugContext* dbg) { + return SyncImpl(options, dbg); +} bool WinWritableFile::IsSyncThreadSafe() const { return true; } -uint64_t WinWritableFile::GetFileSize() { +uint64_t WinWritableFile::GetFileSize(const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { return GetFileNextWriteOffset(); } -Status WinWritableFile::Allocate(uint64_t offset, uint64_t len) { +IOStatus WinWritableFile::Allocate(uint64_t offset, uint64_t len, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { return AllocateImpl(offset, len); } @@ -991,36 +992,43 @@ size_t WinWritableFile::GetUniqueId(char* id, size_t max_size) const { /// WinRandomRWFile WinRandomRWFile::WinRandomRWFile(const std::string& fname, HANDLE hFile, - size_t alignment, const EnvOptions& options) + size_t alignment, const FileOptions& options) : WinFileData(fname, hFile, options.use_direct_reads && options.use_direct_writes), WinRandomAccessImpl(this, alignment, options), WinWritableImpl(this, alignment) {} -bool WinRandomRWFile::use_direct_io() const { return WinFileData::use_direct_io(); } +bool WinRandomRWFile::use_direct_io() const { + return WinFileData::use_direct_io(); +} size_t WinRandomRWFile::GetRequiredBufferAlignment() const { return static_cast(GetAlignement()); } -Status WinRandomRWFile::Write(uint64_t offset, const Slice & data) { +IOStatus WinRandomRWFile::Write(uint64_t offset, const Slice& data, + const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { return PositionedAppendImpl(data, offset); } -Status WinRandomRWFile::Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const { +IOStatus WinRandomRWFile::Read(uint64_t offset, size_t n, + const IOOptions& /*options*/, Slice* result, + char* scratch, IODebugContext* /*dbg*/) const { return ReadImpl(offset, n, result, scratch); } -Status WinRandomRWFile::Flush() { - return Status::OK(); +IOStatus WinRandomRWFile::Flush(const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { + return IOStatus::OK(); } -Status WinRandomRWFile::Sync() { - return SyncImpl(); +IOStatus WinRandomRWFile::Sync(const IOOptions& options, IODebugContext* dbg) { + return SyncImpl(options, dbg); } -Status WinRandomRWFile::Close() { +IOStatus WinRandomRWFile::Close(const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { return CloseImpl(); } @@ -1029,9 +1037,9 @@ Status WinRandomRWFile::Close() { WinMemoryMappedBuffer::~WinMemoryMappedBuffer() { BOOL ret #if defined(_MSC_VER) - = FALSE; + = FALSE; #else - __attribute__((__unused__)); + __attribute__((__unused__)); #endif if (base_ != nullptr) { ret = ::UnmapViewOfFile(base_); @@ -1053,7 +1061,10 @@ WinMemoryMappedBuffer::~WinMemoryMappedBuffer() { ////////////////////////////////////////////////////////////////////////// /// WinDirectory -Status WinDirectory::Fsync() { return Status::OK(); } +IOStatus WinDirectory::Fsync(const IOOptions& /*options*/, + IODebugContext* /*dbg*/) { + return IOStatus::OK(); +} size_t WinDirectory::GetUniqueId(char* id, size_t max_size) const { return GetUniqueIdFromFile(handle_, id, max_size); @@ -1067,7 +1078,7 @@ WinFileLock::~WinFileLock() { assert(ret); } -} +} // namespace port } // namespace ROCKSDB_NAMESPACE #endif diff --git a/port/win/io_win.h b/port/win/io_win.h index d7aa7b483..d9a6bd774 100644 --- a/port/win/io_win.h +++ b/port/win/io_win.h @@ -9,51 +9,51 @@ #pragma once #include +#include + #include #include +#include "rocksdb/file_system.h" #include "rocksdb/status.h" -#include "rocksdb/env.h" #include "util/aligned_buffer.h" -#include - namespace ROCKSDB_NAMESPACE { namespace port { std::string GetWindowsErrSz(DWORD err); -inline Status IOErrorFromWindowsError(const std::string& context, DWORD err) { +inline IOStatus IOErrorFromWindowsError(const std::string& context, DWORD err) { return ((err == ERROR_HANDLE_DISK_FULL) || (err == ERROR_DISK_FULL)) - ? Status::NoSpace(context, GetWindowsErrSz(err)) + ? IOStatus::NoSpace(context, GetWindowsErrSz(err)) : ((err == ERROR_FILE_NOT_FOUND) || (err == ERROR_PATH_NOT_FOUND)) - ? Status::PathNotFound(context, GetWindowsErrSz(err)) - : Status::IOError(context, GetWindowsErrSz(err)); + ? IOStatus::PathNotFound(context, GetWindowsErrSz(err)) + : IOStatus::IOError(context, GetWindowsErrSz(err)); } -inline Status IOErrorFromLastWindowsError(const std::string& context) { +inline IOStatus IOErrorFromLastWindowsError(const std::string& context) { return IOErrorFromWindowsError(context, GetLastError()); } -inline Status IOError(const std::string& context, int err_number) { +inline IOStatus IOError(const std::string& context, int err_number) { return (err_number == ENOSPC) - ? Status::NoSpace(context, strerror(err_number)) + ? IOStatus::NoSpace(context, strerror(err_number)) : (err_number == ENOENT) - ? Status::PathNotFound(context, strerror(err_number)) - : Status::IOError(context, strerror(err_number)); + ? IOStatus::PathNotFound(context, strerror(err_number)) + : IOStatus::IOError(context, strerror(err_number)); } class WinFileData; -Status pwrite(const WinFileData* file_data, const Slice& data, - uint64_t offset, size_t& bytes_written); +IOStatus pwrite(const WinFileData* file_data, const Slice& data, + uint64_t offset, size_t& bytes_written); -Status pread(const WinFileData* file_data, char* src, size_t num_bytes, - uint64_t offset, size_t& bytes_read); +IOStatus pread(const WinFileData* file_data, char* src, size_t num_bytes, + uint64_t offset, size_t& bytes_read); -Status fallocate(const std::string& filename, HANDLE hFile, uint64_t to_size); +IOStatus fallocate(const std::string& filename, HANDLE hFile, uint64_t to_size); -Status ftruncate(const std::string& filename, HANDLE hFile, uint64_t toSize); +IOStatus ftruncate(const std::string& filename, HANDLE hFile, uint64_t toSize); size_t GetUniqueIdFromFile(HANDLE hFile, char* id, size_t max_size); @@ -95,34 +95,38 @@ class WinFileData { WinFileData& operator=(const WinFileData&) = delete; }; -class WinSequentialFile : protected WinFileData, public SequentialFile { - +class WinSequentialFile : protected WinFileData, public FSSequentialFile { // Override for behavior change when creating a custom env - virtual Status PositionedReadInternal(char* src, size_t numBytes, - uint64_t offset, size_t& bytes_read) const; + virtual IOStatus PositionedReadInternal(char* src, size_t numBytes, + uint64_t offset, + size_t& bytes_read) const; -public: + public: WinSequentialFile(const std::string& fname, HANDLE f, - const EnvOptions& options); + const FileOptions& options); ~WinSequentialFile(); WinSequentialFile(const WinSequentialFile&) = delete; WinSequentialFile& operator=(const WinSequentialFile&) = delete; - virtual Status Read(size_t n, Slice* result, char* scratch) override; - virtual Status PositionedRead(uint64_t offset, size_t n, Slice* result, - char* scratch) override; + 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; - virtual Status Skip(uint64_t n) override; + IOStatus Skip(uint64_t n) override; - virtual Status InvalidateCache(size_t offset, size_t length) override; + IOStatus InvalidateCache(size_t offset, size_t length) override; - virtual bool use_direct_io() const override { return WinFileData::use_direct_io(); } + virtual bool use_direct_io() const override { + return WinFileData::use_direct_io(); + } }; // mmap() based random-access -class WinMmapReadableFile : private WinFileData, public RandomAccessFile { +class WinMmapReadableFile : private WinFileData, public FSRandomAccessFile { HANDLE hMap_; const void* mapped_region_; @@ -138,10 +142,11 @@ class WinMmapReadableFile : private WinFileData, public RandomAccessFile { WinMmapReadableFile(const WinMmapReadableFile&) = delete; WinMmapReadableFile& operator=(const WinMmapReadableFile&) = delete; - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const override; + IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, + Slice* result, char* scratch, + IODebugContext* dbg) const override; - virtual Status InvalidateCache(size_t offset, size_t length) override; + virtual IOStatus InvalidateCache(size_t offset, size_t length) override; virtual size_t GetUniqueId(char* id, size_t max_size) const override; }; @@ -150,7 +155,7 @@ class WinMmapReadableFile : private WinFileData, public RandomAccessFile { // data to the file. This is safe since we either properly close the // file before reading from it, or for log files, the reading code // knows enough to skip zero suffixes. -class WinMmapFile : private WinFileData, public WritableFile { +class WinMmapFile : private WinFileData, public FSWritableFile { private: HANDLE hMap_; @@ -179,51 +184,59 @@ class WinMmapFile : private WinFileData, public WritableFile { // Can only truncate or reserve to a sector size aligned if // used on files that are opened with Unbuffered I/O - Status TruncateFile(uint64_t toSize); + IOStatus TruncateFile(uint64_t toSize); - Status UnmapCurrentRegion(); + IOStatus UnmapCurrentRegion(); - Status MapNewRegion(); + IOStatus MapNewRegion(const IOOptions& options, IODebugContext* dbg); - virtual Status PreallocateInternal(uint64_t spaceToReserve); + virtual IOStatus PreallocateInternal(uint64_t spaceToReserve); public: WinMmapFile(const std::string& fname, HANDLE hFile, size_t page_size, - size_t allocation_granularity, const EnvOptions& options); + size_t allocation_granularity, const FileOptions& options); ~WinMmapFile(); WinMmapFile(const WinMmapFile&) = delete; WinMmapFile& operator=(const WinMmapFile&) = delete; - virtual Status Append(const Slice& data) override; + IOStatus Append(const Slice& data, const IOOptions& options, + IODebugContext* dbg) override; + IOStatus Append(const Slice& data, const IOOptions& opts, + const DataVerificationInfo& /* verification_info */, + IODebugContext* dbg) override { + return Append(data, opts, dbg); + } // Means Close() will properly take care of truncate // and it does not need any additional information - virtual Status Truncate(uint64_t size) override; + IOStatus Truncate(uint64_t size, const IOOptions& options, + IODebugContext* dbg) override; - virtual Status Close() override; + IOStatus Close(const IOOptions& options, IODebugContext* dbg) override; - virtual Status Flush() override; + IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override; // Flush only data - virtual Status Sync() override; + IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override; /** - * Flush data as well as metadata to stable storage. - */ - virtual Status Fsync() override; + * Flush data as well as metadata to stable storage. + */ + IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override; /** - * Get the size of valid data in the file. This will not match the - * size that is returned from the filesystem because we use mmap - * to extend file by map_size every time. - */ - virtual uint64_t GetFileSize() override; + * Get the size of valid data in the file. This will not match the + * size that is returned from the filesystem because we use mmap + * to extend file by map_size every time. + */ + uint64_t GetFileSize(const IOOptions& options, IODebugContext* dbg) override; - virtual Status InvalidateCache(size_t offset, size_t length) override; + IOStatus InvalidateCache(size_t offset, size_t length) override; - virtual Status Allocate(uint64_t offset, uint64_t len) override; + IOStatus Allocate(uint64_t offset, uint64_t len, const IOOptions& options, + IODebugContext* dbg) override; virtual size_t GetUniqueId(char* id, size_t max_size) const override; }; @@ -231,24 +244,24 @@ class WinMmapFile : private WinFileData, public WritableFile { class WinRandomAccessImpl { protected: WinFileData* file_base_; - size_t alignment_; + size_t alignment_; // Override for behavior change when creating a custom env - virtual Status PositionedReadInternal(char* src, size_t numBytes, - uint64_t offset, size_t& bytes_read) const; + virtual IOStatus PositionedReadInternal(char* src, size_t numBytes, + uint64_t offset, + size_t& bytes_read) const; WinRandomAccessImpl(WinFileData* file_base, size_t alignment, - const EnvOptions& options); + const FileOptions& options); virtual ~WinRandomAccessImpl() {} - Status ReadImpl(uint64_t offset, size_t n, Slice* result, - char* scratch) const; + IOStatus ReadImpl(uint64_t offset, size_t n, Slice* result, + char* scratch) const; size_t GetAlignment() const { return alignment_; } public: - WinRandomAccessImpl(const WinRandomAccessImpl&) = delete; WinRandomAccessImpl& operator=(const WinRandomAccessImpl&) = delete; }; @@ -258,21 +271,24 @@ class WinRandomAccessFile : private WinFileData, protected WinRandomAccessImpl, // Want to be able to override // PositionedReadInternal - public RandomAccessFile { + public FSRandomAccessFile { public: WinRandomAccessFile(const std::string& fname, HANDLE hFile, size_t alignment, - const EnvOptions& options); + const FileOptions& options); ~WinRandomAccessFile(); - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const override; + IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, + Slice* result, char* scratch, + IODebugContext* dbg) const override; virtual size_t GetUniqueId(char* id, size_t max_size) const override; - virtual bool use_direct_io() const override { return WinFileData::use_direct_io(); } + virtual bool use_direct_io() const override { + return WinFileData::use_direct_io(); + } - virtual Status InvalidateCache(size_t offset, size_t length) override; + IOStatus InvalidateCache(size_t offset, size_t length) override; virtual size_t GetRequiredBufferAlignment() const override; }; @@ -293,10 +309,11 @@ class WinWritableImpl { protected: WinFileData* file_data_; const uint64_t alignment_; - uint64_t next_write_offset_; // Needed because Windows does not support O_APPEND + uint64_t + next_write_offset_; // Needed because Windows does not support O_APPEND uint64_t reservedsize_; // how far we have reserved space - virtual Status PreallocateInternal(uint64_t spaceToReserve); + virtual IOStatus PreallocateInternal(uint64_t spaceToReserve); WinWritableImpl(WinFileData* file_data, size_t alignment); @@ -304,17 +321,17 @@ class WinWritableImpl { uint64_t GetAlignement() const { return alignment_; } - Status AppendImpl(const Slice& data); + IOStatus AppendImpl(const Slice& data); // Requires that the data is aligned as specified by // GetRequiredBufferAlignment() - Status PositionedAppendImpl(const Slice& data, uint64_t offset); + IOStatus PositionedAppendImpl(const Slice& data, uint64_t offset); - Status TruncateImpl(uint64_t size); + IOStatus TruncateImpl(uint64_t size); - Status CloseImpl(); + IOStatus CloseImpl(); - Status SyncImpl(); + IOStatus SyncImpl(const IOOptions& options, IODebugContext* dbg); uint64_t GetFileNextWriteOffset() { // Double accounting now here with WritableFileWriter @@ -326,7 +343,7 @@ class WinWritableImpl { return next_write_offset_; } - Status AllocateImpl(uint64_t offset, uint64_t len); + IOStatus AllocateImpl(uint64_t offset, uint64_t len); public: WinWritableImpl(const WinWritableImpl&) = delete; @@ -335,32 +352,47 @@ class WinWritableImpl { class WinWritableFile : private WinFileData, protected WinWritableImpl, - public WritableFile { + public FSWritableFile { public: WinWritableFile(const std::string& fname, HANDLE hFile, size_t alignment, - size_t capacity, const EnvOptions& options); + size_t capacity, const FileOptions& options); ~WinWritableFile(); - virtual Status Append(const Slice& data) override; + IOStatus Append(const Slice& data, const IOOptions& options, + IODebugContext* dbg) override; + IOStatus Append(const Slice& data, const IOOptions& opts, + const DataVerificationInfo& /* verification_info */, + IODebugContext* dbg) override { + return Append(data, opts, dbg); + } // Requires that the data is aligned as specified by // GetRequiredBufferAlignment() - virtual Status PositionedAppend(const Slice& data, uint64_t offset) override; + IOStatus PositionedAppend(const Slice& data, uint64_t offset, + const IOOptions& options, + IODebugContext* dbg) override; + IOStatus PositionedAppend(const Slice& data, uint64_t offset, + const IOOptions& opts, + const DataVerificationInfo& /* verification_info */, + IODebugContext* dbg) override { + return PositionedAppend(data, offset, opts, dbg); + } // Need to implement this so the file is truncated correctly // when buffered and unbuffered mode - virtual Status Truncate(uint64_t size) override; + IOStatus Truncate(uint64_t size, const IOOptions& options, + IODebugContext* dbg) override; - virtual Status Close() override; + IOStatus Close(const IOOptions& options, IODebugContext* dbg) override; // write out the cached data to the OS cache // This is now taken care of the WritableFileWriter - virtual Status Flush() override; + IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override; - virtual Status Sync() override; + IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override; - virtual Status Fsync() override; + IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override; virtual bool IsSyncThreadSafe() const override; @@ -370,9 +402,10 @@ class WinWritableFile : private WinFileData, virtual size_t GetRequiredBufferAlignment() const override; - virtual uint64_t GetFileSize() override; + uint64_t GetFileSize(const IOOptions& options, IODebugContext* dbg) override; - virtual Status Allocate(uint64_t offset, uint64_t len) override; + IOStatus Allocate(uint64_t offset, uint64_t len, const IOOptions& options, + IODebugContext* dbg) override; virtual size_t GetUniqueId(char* id, size_t max_size) const override; }; @@ -380,10 +413,10 @@ class WinWritableFile : private WinFileData, class WinRandomRWFile : private WinFileData, protected WinRandomAccessImpl, protected WinWritableImpl, - public RandomRWFile { + public FSRandomRWFile { public: WinRandomRWFile(const std::string& fname, HANDLE hFile, size_t alignment, - const EnvOptions& options); + const FileOptions& options); ~WinRandomRWFile() {} @@ -397,45 +430,50 @@ class WinRandomRWFile : private WinFileData, // Write bytes in `data` at offset `offset`, Returns Status::OK() on success. // Pass aligned buffer when use_direct_io() returns true. - virtual Status Write(uint64_t offset, const Slice& data) override; + IOStatus Write(uint64_t offset, const Slice& data, const IOOptions& options, + IODebugContext* dbg) override; // Read up to `n` bytes starting from offset `offset` and store them in // result, provided `scratch` size should be at least `n`. // Returns Status::OK() on success. - virtual Status Read(uint64_t offset, size_t n, Slice* result, - char* scratch) const override; + IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, + Slice* result, char* scratch, + IODebugContext* dbg) const override; - virtual Status Flush() override; + IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override; - virtual Status Sync() override; + IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override; - virtual Status Fsync() override { return Sync(); } + IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override { + return Sync(options, dbg); + } - virtual Status Close() override; + IOStatus Close(const IOOptions& options, IODebugContext* dbg) override; }; class WinMemoryMappedBuffer : public MemoryMappedFileBuffer { -private: - HANDLE file_handle_; - HANDLE map_handle_; -public: - WinMemoryMappedBuffer(HANDLE file_handle, HANDLE map_handle, void* base, size_t size) : - MemoryMappedFileBuffer(base, size), - file_handle_(file_handle), - map_handle_(map_handle) {} + private: + HANDLE file_handle_; + HANDLE map_handle_; + + public: + WinMemoryMappedBuffer(HANDLE file_handle, HANDLE map_handle, void* base, + size_t size) + : MemoryMappedFileBuffer(base, size), + file_handle_(file_handle), + map_handle_(map_handle) {} ~WinMemoryMappedBuffer() override; }; -class WinDirectory : public Directory { +class WinDirectory : public FSDirectory { HANDLE handle_; + public: explicit WinDirectory(HANDLE h) noexcept : handle_(h) { assert(handle_ != INVALID_HANDLE_VALUE); } - ~WinDirectory() { - ::CloseHandle(handle_); - } - virtual Status Fsync() override; + ~WinDirectory() { ::CloseHandle(handle_); } + IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override; size_t GetUniqueId(char* id, size_t max_size) const override; }; @@ -452,5 +490,5 @@ class WinFileLock : public FileLock { private: HANDLE hFile_; }; -} +} // namespace port } // namespace ROCKSDB_NAMESPACE diff --git a/port/win/win_logger.cc b/port/win/win_logger.cc index a9b10c04b..aee78b771 100644 --- a/port/win/win_logger.cc +++ b/port/win/win_logger.cc @@ -13,31 +13,33 @@ #if defined(OS_WIN) #include "port/win/win_logger.h" -#include "port/win/io_win.h" -#include +#include #include #include -#include -#include -#include "rocksdb/env.h" +#include +#include #include "monitoring/iostats_context_imp.h" #include "port/sys_time.h" +#include "port/win/env_win.h" +#include "port/win/io_win.h" +#include "rocksdb/env.h" namespace ROCKSDB_NAMESPACE { namespace port { -WinLogger::WinLogger(uint64_t (*gettid)(), Env* env, HANDLE file, +WinLogger::WinLogger(uint64_t (*gettid)(), + const std::shared_ptr& clock, HANDLE file, const InfoLogLevel log_level) : Logger(log_level), file_(file), gettid_(gettid), log_size_(0), last_flush_micros_(0), - env_(env), + clock_(clock), flush_pending_(false) { assert(file_ != NULL); assert(file_ != INVALID_HANDLE_VALUE); @@ -88,7 +90,7 @@ void WinLogger::Flush() { // for perf reasons. } - last_flush_micros_ = env_->NowMicros(); + last_flush_micros_ = clock_->NowMicros(); } void WinLogger::Logv(const char* format, va_list ap) { diff --git a/port/win/win_logger.h b/port/win/win_logger.h index 116e7898d..a11b7b864 100644 --- a/port/win/win_logger.h +++ b/port/win/win_logger.h @@ -12,22 +12,23 @@ #pragma once +#include +#include + #include +#include #include "rocksdb/env.h" -#include -#include - namespace ROCKSDB_NAMESPACE { -class Env; - namespace port { +class WinClock; class WinLogger : public ROCKSDB_NAMESPACE::Logger { public: - WinLogger(uint64_t (*gettid)(), Env* env, HANDLE file, + WinLogger(uint64_t (*gettid)(), const std::shared_ptr& clock, + HANDLE file, const InfoLogLevel log_level = InfoLogLevel::ERROR_LEVEL); virtual ~WinLogger(); @@ -54,7 +55,7 @@ protected: uint64_t (*gettid_)(); // Return the thread id for the current thread std::atomic_size_t log_size_; std::atomic_uint_fast64_t last_flush_micros_; - Env* env_; + std::shared_ptr clock_; bool flush_pending_; Status CloseInternal(); diff --git a/test_util/testutil.cc b/test_util/testutil.cc index f0df928f1..6a7c10e4b 100644 --- a/test_util/testutil.cc +++ b/test_util/testutil.cc @@ -452,6 +452,26 @@ bool IsDirectIOSupported(Env* env, const std::string& dir) { return s.ok(); } +bool IsPrefetchSupported(const std::shared_ptr& fs, + const std::string& dir) { + bool supported = false; + std::string tmp = TempFileName(dir, 999); + Random rnd(301); + std::string test_string = rnd.RandomString(4096); + Slice data(test_string); + Status s = WriteStringToFile(fs.get(), data, tmp, true); + if (s.ok()) { + std::unique_ptr file; + auto io_s = fs->NewRandomAccessFile(tmp, FileOptions(), &file, nullptr); + if (io_s.ok()) { + supported = !(file->Prefetch(0, data.size(), IOOptions(), nullptr) + .IsNotSupported()); + } + s = fs->DeleteFile(tmp, IOOptions(), nullptr); + } + return s.ok() && supported; +} + size_t GetLinesCount(const std::string& fname, const std::string& pattern) { std::stringstream ssbuf; std::string line; diff --git a/test_util/testutil.h b/test_util/testutil.h index 00a768d50..c53c35944 100644 --- a/test_util/testutil.h +++ b/test_util/testutil.h @@ -26,6 +26,7 @@ #include "util/mutexlock.h" namespace ROCKSDB_NAMESPACE { +class FileSystem; class Random; class SequentialFile; class SequentialFileReader; @@ -861,6 +862,9 @@ std::string RandomName(Random* rnd, const size_t len); bool IsDirectIOSupported(Env* env, const std::string& dir); +bool IsPrefetchSupported(const std::shared_ptr& fs, + const std::string& dir); + // Return the number of lines where a given pattern was found in a file. size_t GetLinesCount(const std::string& fname, const std::string& pattern); diff --git a/tools/db_bench_tool_test.cc b/tools/db_bench_tool_test.cc index cd1c41e85..af9a72493 100644 --- a/tools/db_bench_tool_test.cc +++ b/tools/db_bench_tool_test.cc @@ -32,7 +32,6 @@ class DBBenchTest : public testing::Test { Env::Default()->CreateDir(test_path_); db_path_ = test_path_ + "/db"; wal_path_ = test_path_ + "/wal"; - fs_.reset(new LegacyFileSystemWrapper(Env::Default())); } ~DBBenchTest() { @@ -114,7 +113,6 @@ class DBBenchTest : public testing::Test { std::string db_path_; std::string test_path_; std::string wal_path_; - std::unique_ptr fs_; char arg_buffer_[kArgBufferSize]; char* argv_[kMaxArgCount]; @@ -130,7 +128,7 @@ TEST_F(DBBenchTest, OptionsFile) { Options opt = GetDefaultOptions(); ASSERT_OK(PersistRocksDBOptions(DBOptions(opt), {"default"}, {ColumnFamilyOptions()}, kOptionsFileName, - fs_.get())); + opt.env->GetFileSystem().get())); // override the following options as db_bench will not take these // options from the options file @@ -149,7 +147,7 @@ TEST_F(DBBenchTest, OptionsFileUniversal) { ASSERT_OK(PersistRocksDBOptions(DBOptions(opt), {"default"}, {ColumnFamilyOptions(opt)}, kOptionsFileName, - fs_.get())); + opt.env->GetFileSystem().get())); // override the following options as db_bench will not take these // options from the options file diff --git a/utilities/blob_db/blob_db_test.cc b/utilities/blob_db/blob_db_test.cc index f6d834790..f2a8146c0 100644 --- a/utilities/blob_db/blob_db_test.cc +++ b/utilities/blob_db/blob_db_test.cc @@ -824,10 +824,10 @@ TEST_F(BlobDBTest, SstFileManagerRestart) { Close(); // Create 3 dummy trash files under the blob_dir - LegacyFileSystemWrapper fs(db_options.env); - CreateFile(&fs, blob_dir + "/000666.blob.trash", "", false); - CreateFile(&fs, blob_dir + "/000888.blob.trash", "", true); - CreateFile(&fs, blob_dir + "/something_not_match.trash", "", false); + const auto &fs = db_options.env->GetFileSystem(); + CreateFile(fs, blob_dir + "/000666.blob.trash", "", false); + CreateFile(fs, blob_dir + "/000888.blob.trash", "", true); + CreateFile(fs, blob_dir + "/something_not_match.trash", "", false); // Make sure that reopening the DB rescan the existing trash files Open(bdb_options, db_options); diff --git a/utilities/options/options_util.cc b/utilities/options/options_util.cc index 353725552..2a6a83aee 100644 --- a/utilities/options/options_util.cc +++ b/utilities/options/options_util.cc @@ -7,7 +7,6 @@ #include "rocksdb/utilities/options_util.h" -#include "env/composite_env_wrapper.h" #include "file/filename.h" #include "options/options_parser.h" #include "rocksdb/convenience.h" @@ -34,8 +33,8 @@ Status LoadOptionsFromFile(const ConfigOptions& config_options, std::vector* cf_descs, std::shared_ptr* cache) { RocksDBOptionsParser parser; - LegacyFileSystemWrapper fs(config_options.env); - Status s = parser.Parse(config_options, file_name, &fs); + const auto& fs = config_options.env->GetFileSystem(); + Status s = parser.Parse(config_options, file_name, fs.get()); if (!s.ok()) { return s; } @@ -149,12 +148,11 @@ Status CheckOptionsCompatibility( cf_opts.push_back(cf_desc.options); } - LegacyFileSystemWrapper fs(config_options.env); + const auto& fs = config_options.env->GetFileSystem(); return RocksDBOptionsParser::VerifyRocksDBOptionsFromFile( - config_options, db_options, cf_names, cf_opts, - dbpath + "/" + options_file_name, &fs); + dbpath + "/" + options_file_name, fs.get()); } } // namespace ROCKSDB_NAMESPACE