From 564520775894fb85c4d454e8e5eebb123cac158a Mon Sep 17 00:00:00 2001 From: Levi Tamasi Date: Wed, 13 Apr 2022 13:36:30 -0700 Subject: [PATCH] Expose the amount of garbage in live blob files as a dedicated DB property (#9835) Summary: This information has been already available as part of the `rocksdb.blob-stats` string property. The patch adds a dedicated integer property to make it easier to surface this information in monitoring systems. Pull Request resolved: https://github.com/facebook/rocksdb/pull/9835 Test Plan: `make check` Reviewed By: riversand963 Differential Revision: D35619495 Pulled By: ltamasi fbshipit-source-id: 03fb0b228aa27d3859a1e3783bcb7eca095607f8 --- HISTORY.md | 1 + db/blob/db_blob_basic_test.cc | 16 ++++++++++++++++ db/internal_stats.cc | 28 ++++++++++++++++++++++++++++ db/internal_stats.h | 3 +++ include/rocksdb/db.h | 4 ++++ 5 files changed, 52 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 4d2990ad8..7d19e52d1 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -19,6 +19,7 @@ * Add new stat ASYNC_READ_BYTES that calculates number of bytes read during async read call and users can check if async code path is being called by RocksDB internal automatic prefetching for sequential reads. * Enable async prefetching if ReadOptions.readahead_size is set along with ReadOptions.async_io in FilePrefetchBuffer. * Add event listener support on remote compaction compactor side. +* Added a dedicated integer DB property `rocksdb.live-blob-file-garbage-size` that exposes the total amount of garbage in the blob files in the current version. ### Behavior changes * Disallow usage of commit-time-write-batch for write-prepared/write-unprepared transactions if TransactionOptions::use_only_the_last_commit_time_batch_for_recovery is false to prevent two (or more) uncommitted versions of the same key in the database. Otherwise, bottommost compaction may violate the internal key uniqueness invariant of SSTs if the sequence numbers of both internal keys are zeroed out (#9794). diff --git a/db/blob/db_blob_basic_test.cc b/db/blob/db_blob_basic_test.cc index d3845eec6..89dd77a9d 100644 --- a/db/blob/db_blob_basic_test.cc +++ b/db/blob/db_blob_basic_test.cc @@ -733,6 +733,14 @@ TEST_F(DBBlobBasicTest, Properties) { &live_blob_file_size)); ASSERT_EQ(live_blob_file_size, total_expected_size); + // Total amount of garbage in live blob files + { + uint64_t live_blob_file_garbage_size = 0; + ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kLiveBlobFileGarbageSize, + &live_blob_file_garbage_size)); + ASSERT_EQ(live_blob_file_garbage_size, 0); + } + // Total size of all blob files across all versions // Note: this should be the same as above since we only have one // version at this point. @@ -768,6 +776,14 @@ TEST_F(DBBlobBasicTest, Properties) { << "\nBlob file space amplification: " << expected_space_amp << '\n'; ASSERT_EQ(blob_stats, oss.str()); + + // Total amount of garbage in live blob files + { + uint64_t live_blob_file_garbage_size = 0; + ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kLiveBlobFileGarbageSize, + &live_blob_file_garbage_size)); + ASSERT_EQ(live_blob_file_garbage_size, expected_garbage_size); + } } TEST_F(DBBlobBasicTest, PropertiesMultiVersion) { diff --git a/db/internal_stats.cc b/db/internal_stats.cc index a3d8113aa..8a2a6f93f 100644 --- a/db/internal_stats.cc +++ b/db/internal_stats.cc @@ -305,6 +305,8 @@ static const std::string num_blob_files = "num-blob-files"; static const std::string blob_stats = "blob-stats"; static const std::string total_blob_file_size = "total-blob-file-size"; static const std::string live_blob_file_size = "live-blob-file-size"; +static const std::string live_blob_file_garbage_size = + "live-blob-file-garbage-size"; const std::string DB::Properties::kNumFilesAtLevelPrefix = rocksdb_prefix + num_files_at_level_prefix; @@ -405,6 +407,8 @@ const std::string DB::Properties::kTotalBlobFileSize = rocksdb_prefix + total_blob_file_size; const std::string DB::Properties::kLiveBlobFileSize = rocksdb_prefix + live_blob_file_size; +const std::string DB::Properties::kLiveBlobFileGarbageSize = + rocksdb_prefix + live_blob_file_garbage_size; const UnorderedMap InternalStats::ppt_name_to_info = { @@ -563,6 +567,9 @@ const UnorderedMap {DB::Properties::kLiveBlobFileSize, {false, nullptr, &InternalStats::HandleLiveBlobFileSize, nullptr, nullptr}}, + {DB::Properties::kLiveBlobFileGarbageSize, + {false, nullptr, &InternalStats::HandleLiveBlobFileGarbageSize, + nullptr, nullptr}}, }; InternalStats::InternalStats(int num_levels, SystemClock* clock, @@ -758,6 +765,7 @@ bool InternalStats::HandleLiveSstFilesSizeAtTemperature(std::string* value, bool InternalStats::HandleNumBlobFiles(uint64_t* value, DBImpl* /*db*/, Version* /*version*/) { + assert(value); assert(cfd_); const auto* current = cfd_->current(); @@ -774,6 +782,7 @@ bool InternalStats::HandleNumBlobFiles(uint64_t* value, DBImpl* /*db*/, } bool InternalStats::HandleBlobStats(std::string* value, Slice /*suffix*/) { + assert(value); assert(cfd_); const auto* current = cfd_->current(); @@ -798,6 +807,7 @@ bool InternalStats::HandleBlobStats(std::string* value, Slice /*suffix*/) { bool InternalStats::HandleTotalBlobFileSize(uint64_t* value, DBImpl* /*db*/, Version* /*version*/) { + assert(value); assert(cfd_); *value = cfd_->GetTotalBlobFileSize(); @@ -807,6 +817,7 @@ bool InternalStats::HandleTotalBlobFileSize(uint64_t* value, DBImpl* /*db*/, bool InternalStats::HandleLiveBlobFileSize(uint64_t* value, DBImpl* /*db*/, Version* /*version*/) { + assert(value); assert(cfd_); const auto* current = cfd_->current(); @@ -820,6 +831,23 @@ bool InternalStats::HandleLiveBlobFileSize(uint64_t* value, DBImpl* /*db*/, return true; } +bool InternalStats::HandleLiveBlobFileGarbageSize(uint64_t* value, + DBImpl* /*db*/, + Version* /*version*/) { + assert(value); + assert(cfd_); + + const auto* current = cfd_->current(); + assert(current); + + const auto* vstorage = current->storage_info(); + assert(vstorage); + + *value = vstorage->GetBlobStats().total_garbage_size; + + return true; +} + const DBPropertyInfo* GetPropertyInfo(const Slice& property) { std::string ppt_name = GetPropertyNameAndArg(property).first.ToString(); auto ppt_info_iter = InternalStats::ppt_name_to_info.find(ppt_name); diff --git a/db/internal_stats.h b/db/internal_stats.h index dbf15d98e..713a12c59 100644 --- a/db/internal_stats.h +++ b/db/internal_stats.h @@ -691,6 +691,9 @@ class InternalStats { bool HandleBlobStats(std::string* value, Slice suffix); bool HandleTotalBlobFileSize(uint64_t* value, DBImpl* db, Version* version); bool HandleLiveBlobFileSize(uint64_t* value, DBImpl* db, Version* version); + bool HandleLiveBlobFileGarbageSize(uint64_t* value, DBImpl* db, + Version* version); + // Total number of background errors encountered. Every time a flush task // or compaction task fails, this counter is incremented. The failure can // be caused by any possible reason, including file system errors, out of diff --git a/include/rocksdb/db.h b/include/rocksdb/db.h index 2172f21cd..f7c0e3be9 100644 --- a/include/rocksdb/db.h +++ b/include/rocksdb/db.h @@ -1066,6 +1066,10 @@ class DB { // "rocksdb.live-blob-file-size" - returns the total size of all blob // files in the current version. static const std::string kLiveBlobFileSize; + + // "rocksdb.live-blob-file-garbage-size" - returns the total amount of + // garbage in the blob files in the current version. + static const std::string kLiveBlobFileGarbageSize; }; #endif /* ROCKSDB_LITE */