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