From 0d04a8434a4faf13be8ecf4289bedbc2b7a44d5c Mon Sep 17 00:00:00 2001 From: Levi Tamasi Date: Wed, 22 Jul 2020 17:24:07 -0700 Subject: [PATCH] Sync blob files before closing them (#7160) Summary: BlobDB currently syncs each blob file periodically after writing a certain amount of data (as specified by the configuration option `BlobDBOptions::bytes_per_sync`) and all open blob files when the base DB's memtables are flushed. With the patch, in addition to the above, blob files are also synced right before being closed, after the footer has been written. This will be beneficial for the new integrated blob file write path as well. Pull Request resolved: https://github.com/facebook/rocksdb/pull/7160 Test Plan: `make check` Reviewed By: riversand963 Differential Revision: D22672646 Pulled By: ltamasi fbshipit-source-id: 62b34263543a7e74abcbb7adf011daa1e699998f --- db/blob/blob_log_writer.cc | 8 ++++- utilities/blob_db/blob_db_test.cc | 51 +++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/db/blob/blob_log_writer.cc b/db/blob/blob_log_writer.cc index d86de7425..27b94a343 100644 --- a/db/blob/blob_log_writer.cc +++ b/db/blob/blob_log_writer.cc @@ -13,6 +13,7 @@ #include "file/writable_file_writer.h" #include "monitoring/statistics.h" #include "rocksdb/env.h" +#include "test_util/sync_point.h" #include "util/coding.h" #include "util/stop_watch.h" @@ -30,6 +31,8 @@ BlobLogWriter::BlobLogWriter(std::unique_ptr&& dest, last_elem_type_(kEtNone) {} Status BlobLogWriter::Sync() { + TEST_SYNC_POINT("BlobLogWriter::Sync"); + StopWatch sync_sw(env_, statistics_, BLOB_DB_BLOB_FILE_SYNC_MICROS); Status s = dest_->Sync(use_fsync_); RecordTick(statistics_, BLOB_DB_BLOB_FILE_SYNCED); @@ -63,7 +66,10 @@ Status BlobLogWriter::AppendFooter(BlobLogFooter& footer) { Status s = dest_->Append(Slice(str)); if (s.ok()) { block_offset_ += str.size(); - s = dest_->Close(); + s = Sync(); + if (s.ok()) { + s = dest_->Close(); + } dest_.reset(); } diff --git a/utilities/blob_db/blob_db_test.cc b/utilities/blob_db/blob_db_test.cc index 95533cd6a..a2e3d39d5 100644 --- a/utilities/blob_db/blob_db_test.cc +++ b/utilities/blob_db/blob_db_test.cc @@ -2127,6 +2127,57 @@ TEST_F(BlobDBTest, ShutdownWait) { SyncPoint::GetInstance()->DisableProcessing(); } +TEST_F(BlobDBTest, SyncBlobFileBeforeClose) { + Options options; + options.statistics = CreateDBStatistics(); + + BlobDBOptions blob_options; + blob_options.min_blob_size = 0; + blob_options.bytes_per_sync = 1 << 20; + blob_options.disable_background_tasks = true; + + Open(blob_options, options); + + Put("foo", "bar"); + + auto blob_files = blob_db_impl()->TEST_GetBlobFiles(); + ASSERT_EQ(blob_files.size(), 1); + + ASSERT_OK(blob_db_impl()->TEST_CloseBlobFile(blob_files[0])); + ASSERT_EQ(options.statistics->getTickerCount(BLOB_DB_BLOB_FILE_SYNCED), 1); +} + +TEST_F(BlobDBTest, SyncBlobFileBeforeCloseIOError) { + Options options; + options.env = fault_injection_env_.get(); + + BlobDBOptions blob_options; + blob_options.min_blob_size = 0; + blob_options.bytes_per_sync = 1 << 20; + blob_options.disable_background_tasks = true; + + Open(blob_options, options); + + Put("foo", "bar"); + + auto blob_files = blob_db_impl()->TEST_GetBlobFiles(); + ASSERT_EQ(blob_files.size(), 1); + + SyncPoint::GetInstance()->SetCallBack( + "BlobLogWriter::Sync", [this](void * /* arg */) { + fault_injection_env_->SetFilesystemActive(false, Status::IOError()); + }); + SyncPoint::GetInstance()->EnableProcessing(); + + const Status s = blob_db_impl()->TEST_CloseBlobFile(blob_files[0]); + + fault_injection_env_->SetFilesystemActive(true); + SyncPoint::GetInstance()->DisableProcessing(); + SyncPoint::GetInstance()->ClearAllCallBacks(); + + ASSERT_TRUE(s.IsIOError()); +} + } // namespace blob_db } // namespace ROCKSDB_NAMESPACE