From 33ceea9b766c879d1ef02cb24d9bb23dafd8b9a9 Mon Sep 17 00:00:00 2001 From: Andrew Kryczka Date: Thu, 20 Oct 2022 15:04:29 -0700 Subject: [PATCH] Add DB property for fast block cache stats collection (#10832) Summary: This new property allows users to trigger the background block cache stats collection mode through the `GetProperty()` and `GetMapProperty()` APIs. The background mode has much lower overhead at the expense of returning stale values in more cases. Pull Request resolved: https://github.com/facebook/rocksdb/pull/10832 Test Plan: updated unit test Reviewed By: pdillinger Differential Revision: D40497883 Pulled By: ajkr fbshipit-source-id: bdcc93402f426463abb2153756aad9e295447343 --- HISTORY.md | 1 + db/db_block_cache_test.cc | 38 ++++++++++++++++++++++++++++---------- db/internal_stats.cc | 39 +++++++++++++++++++++++++++++++++------ db/internal_stats.h | 6 ++++++ include/rocksdb/db.h | 4 ++++ 5 files changed, 72 insertions(+), 16 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index e8cc3077c..c3dac417a 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -4,6 +4,7 @@ * `DeleteRange()` now supports user-defined timestamp. * Provide support for async_io with tailing iterators when ReadOptions.tailing is enabled during scans. * Tiered Storage: allow data moving up from the last level to the penultimate level if the input level is penultimate level or above. +* Added `DB::Properties::kFastBlockCacheEntryStats`, which is similar to `DB::Properties::kBlockCacheEntryStats`, except returns cached (stale) values in more cases to reduce overhead. * FIFO compaction now supports migrating from a multi-level DB via DB::Open(). During the migration phase, FIFO compaction picker will: * picks the sst file with the smallest starting key in the bottom-most non-empty level. * Note that during the migration phase, the file purge order will only be an approximation of "FIFO" as files in lower-level might sometime contain newer keys than files in upper-level. diff --git a/db/db_block_cache_test.cc b/db/db_block_cache_test.cc index 6c335febc..38ecd7a81 100644 --- a/db/db_block_cache_test.cc +++ b/db/db_block_cache_test.cc @@ -170,13 +170,16 @@ class DBBlockCacheTest : public DBTestBase { #ifndef ROCKSDB_LITE const std::array GetCacheEntryRoleCountsBg() { // Verify in cache entry role stats - ColumnFamilyHandleImpl* cfh = - static_cast(dbfull()->DefaultColumnFamily()); - InternalStats* internal_stats_ptr = cfh->cfd()->internal_stats(); - InternalStats::CacheEntryRoleStats stats; - internal_stats_ptr->TEST_GetCacheEntryRoleStats(&stats, - /*foreground=*/false); - return stats.entry_counts; + std::array cache_entry_role_counts; + std::map values; + EXPECT_TRUE(db_->GetMapProperty(DB::Properties::kFastBlockCacheEntryStats, + &values)); + for (size_t i = 0; i < kNumCacheEntryRoles; ++i) { + auto role = static_cast(i); + cache_entry_role_counts[i] = + ParseSizeT(values[BlockCacheEntryStatsMapKeys::EntryCount(role)]); + } + return cache_entry_role_counts; } #endif // ROCKSDB_LITE }; @@ -1500,23 +1503,38 @@ TEST_F(DBBlockCacheTest, CacheEntryRoleStats) { dbfull()->DumpStats(); ASSERT_EQ(scan_count, 1); - env_->MockSleepForSeconds(10000); + env_->MockSleepForSeconds(60); + ASSERT_TRUE(db_->GetMapProperty(DB::Properties::kFastBlockCacheEntryStats, + &values)); + ASSERT_EQ(scan_count, 1); ASSERT_TRUE( db_->GetMapProperty(DB::Properties::kBlockCacheEntryStats, &values)); ASSERT_EQ(scan_count, 2); env_->MockSleepForSeconds(10000); + ASSERT_TRUE(db_->GetMapProperty(DB::Properties::kFastBlockCacheEntryStats, + &values)); + ASSERT_EQ(scan_count, 3); + + env_->MockSleepForSeconds(60); std::string value_str; + ASSERT_TRUE(db_->GetProperty(DB::Properties::kFastBlockCacheEntryStats, + &value_str)); + ASSERT_EQ(scan_count, 3); ASSERT_TRUE( db_->GetProperty(DB::Properties::kBlockCacheEntryStats, &value_str)); - ASSERT_EQ(scan_count, 3); + ASSERT_EQ(scan_count, 4); env_->MockSleepForSeconds(10000); + ASSERT_TRUE(db_->GetProperty(DB::Properties::kFastBlockCacheEntryStats, + &value_str)); + ASSERT_EQ(scan_count, 5); + ASSERT_TRUE(db_->GetProperty(DB::Properties::kCFStats, &value_str)); // To match historical speed, querying this property no longer triggers // a scan, even if results are old. But periodic dump stats should keep // things reasonably updated. - ASSERT_EQ(scan_count, /*unchanged*/ 3); + ASSERT_EQ(scan_count, /*unchanged*/ 5); SyncPoint::GetInstance()->DisableProcessing(); SyncPoint::GetInstance()->ClearAllCallBacks(); diff --git a/db/internal_stats.cc b/db/internal_stats.cc index 5a8a24324..dfe7e6e70 100644 --- a/db/internal_stats.cc +++ b/db/internal_stats.cc @@ -247,6 +247,8 @@ static const std::string cf_file_histogram = "cf-file-histogram"; static const std::string dbstats = "dbstats"; static const std::string levelstats = "levelstats"; static const std::string block_cache_entry_stats = "block-cache-entry-stats"; +static const std::string fast_block_cache_entry_stats = + "fast-block-cache-entry-stats"; static const std::string num_immutable_mem_table = "num-immutable-mem-table"; static const std::string num_immutable_mem_table_flushed = "num-immutable-mem-table-flushed"; @@ -326,6 +328,8 @@ const std::string DB::Properties::kDBStats = rocksdb_prefix + dbstats; const std::string DB::Properties::kLevelStats = rocksdb_prefix + levelstats; const std::string DB::Properties::kBlockCacheEntryStats = rocksdb_prefix + block_cache_entry_stats; +const std::string DB::Properties::kFastBlockCacheEntryStats = + rocksdb_prefix + fast_block_cache_entry_stats; const std::string DB::Properties::kNumImmutableMemTable = rocksdb_prefix + num_immutable_mem_table; const std::string DB::Properties::kNumImmutableMemTableFlushed = @@ -446,6 +450,9 @@ const UnorderedMap {DB::Properties::kBlockCacheEntryStats, {true, &InternalStats::HandleBlockCacheEntryStats, nullptr, &InternalStats::HandleBlockCacheEntryStatsMap, nullptr}}, + {DB::Properties::kFastBlockCacheEntryStats, + {true, &InternalStats::HandleFastBlockCacheEntryStats, nullptr, + &InternalStats::HandleFastBlockCacheEntryStatsMap, nullptr}}, {DB::Properties::kSSTables, {false, &InternalStats::HandleSsTables, nullptr, nullptr, nullptr}}, {DB::Properties::kAggregatedTableProperties, @@ -739,30 +746,50 @@ void InternalStats::CacheEntryRoleStats::ToMap( } } -bool InternalStats::HandleBlockCacheEntryStats(std::string* value, - Slice /*suffix*/) { +bool InternalStats::HandleBlockCacheEntryStatsInternal(std::string* value, + bool fast) { if (!cache_entry_stats_collector_) { return false; } - CollectCacheEntryStats(/*foreground*/ true); + CollectCacheEntryStats(!fast /* foreground */); CacheEntryRoleStats stats; cache_entry_stats_collector_->GetStats(&stats); *value = stats.ToString(clock_); return true; } -bool InternalStats::HandleBlockCacheEntryStatsMap( - std::map* values, Slice /*suffix*/) { +bool InternalStats::HandleBlockCacheEntryStatsMapInternal( + std::map* values, bool fast) { if (!cache_entry_stats_collector_) { return false; } - CollectCacheEntryStats(/*foreground*/ true); + CollectCacheEntryStats(!fast /* foreground */); CacheEntryRoleStats stats; cache_entry_stats_collector_->GetStats(&stats); stats.ToMap(values, clock_); return true; } +bool InternalStats::HandleBlockCacheEntryStats(std::string* value, + Slice /*suffix*/) { + return HandleBlockCacheEntryStatsInternal(value, false /* fast */); +} + +bool InternalStats::HandleBlockCacheEntryStatsMap( + std::map* values, Slice /*suffix*/) { + return HandleBlockCacheEntryStatsMapInternal(values, false /* fast */); +} + +bool InternalStats::HandleFastBlockCacheEntryStats(std::string* value, + Slice /*suffix*/) { + return HandleBlockCacheEntryStatsInternal(value, true /* fast */); +} + +bool InternalStats::HandleFastBlockCacheEntryStatsMap( + std::map* values, Slice /*suffix*/) { + return HandleBlockCacheEntryStatsMapInternal(values, true /* fast */); +} + bool InternalStats::HandleLiveSstFilesSizeAtTemperature(std::string* value, Slice suffix) { uint64_t temperature; diff --git a/db/internal_stats.h b/db/internal_stats.h index 7091877bb..386eef42d 100644 --- a/db/internal_stats.h +++ b/db/internal_stats.h @@ -793,9 +793,15 @@ class InternalStats { bool HandleBlockCacheUsage(uint64_t* value, DBImpl* db, Version* version); bool HandleBlockCachePinnedUsage(uint64_t* value, DBImpl* db, Version* version); + bool HandleBlockCacheEntryStatsInternal(std::string* value, bool fast); + bool HandleBlockCacheEntryStatsMapInternal( + std::map* values, bool fast); bool HandleBlockCacheEntryStats(std::string* value, Slice suffix); bool HandleBlockCacheEntryStatsMap(std::map* values, Slice suffix); + bool HandleFastBlockCacheEntryStats(std::string* value, Slice suffix); + bool HandleFastBlockCacheEntryStatsMap( + std::map* values, Slice suffix); bool HandleLiveSstFilesSizeAtTemperature(std::string* value, Slice suffix); bool HandleNumBlobFiles(uint64_t* value, DBImpl* db, Version* version); bool HandleBlobStats(std::string* value, Slice suffix); diff --git a/include/rocksdb/db.h b/include/rocksdb/db.h index 6d8048d9d..a16db3b54 100644 --- a/include/rocksdb/db.h +++ b/include/rocksdb/db.h @@ -911,6 +911,10 @@ class DB { // available in the map form. static const std::string kBlockCacheEntryStats; + // "rocksdb.fast-block-cache-entry-stats" - same as above, but returns + // stale values more frequently to reduce overhead and latency. + static const std::string kFastBlockCacheEntryStats; + // "rocksdb.num-immutable-mem-table" - returns number of immutable // memtables that have not yet been flushed. static const std::string kNumImmutableMemTable;