diff --git a/cache/cache_test.cc b/cache/cache_test.cc index 462c2ec7410..12bcfe6cd43 100644 --- a/cache/cache_test.cc +++ b/cache/cache_test.cc @@ -886,6 +886,32 @@ TEST_P(CacheTest, ApplyToAllEntriesDuringResize) { ASSERT_EQ(special_count, kSpecialCount); } +TEST_P(CacheTest, ApplyToHandleTest) { + std::string callback_state; + const auto callback = [&](const Slice& key, Cache::ObjectPtr value, + size_t charge, + const Cache::CacheItemHelper* helper) { + callback_state = std::to_string(DecodeKey(key)) + "," + + std::to_string(DecodeValue(value)) + "," + + std::to_string(charge); + assert(helper == &CacheTest::kHelper); + }; + + std::vector inserted; + + for (int i = 0; i < 10; ++i) { + Insert(i, i * 2, i + 1); + inserted.push_back(std::to_string(i) + "," + std::to_string(i * 2) + "," + + std::to_string(i + 1)); + } + for (int i = 0; i < 10; ++i) { + Cache::Handle* handle = cache_->Lookup(EncodeKey(i)); + cache_->ApplyToHandle(cache_.get(), handle, callback); + EXPECT_EQ(inserted[i], callback_state); + cache_->Release(handle); + } +} + TEST_P(CacheTest, DefaultShardBits) { // Prevent excessive allocation (to save time & space) estimated_value_size_ = 100000; diff --git a/cache/clock_cache.cc b/cache/clock_cache.cc index 078b922dd31..090213cb0d0 100644 --- a/cache/clock_cache.cc +++ b/cache/clock_cache.cc @@ -1444,6 +1444,22 @@ const Cache::CacheItemHelper* BaseHyperClockCache::GetCacheItemHelper( return h->helper; } +template +void BaseHyperClockCache
::ApplyToHandle( + Cache* cache, Handle* handle, + const std::function& + callback) { + BaseHyperClockCache
* cache_ptr = + static_cast*>(cache); + auto h = static_cast(handle); + UniqueId64x2 unhashed; + auto hash_seed = cache_ptr->GetShard(h->GetHash()).GetTable().GetHashSeed(); + callback( + ClockCacheShard
::ReverseHash(h->hashed_key, &unhashed, hash_seed), + h->value, h->GetTotalCharge(), h->helper); +} + namespace { // For each cache shard, estimate what the table load factor would be if diff --git a/cache/clock_cache.h b/cache/clock_cache.h index 7423fa1f417..2d5d0d9eef3 100644 --- a/cache/clock_cache.h +++ b/cache/clock_cache.h @@ -1128,6 +1128,12 @@ class BaseHyperClockCache : public ShardedCache> { const CacheItemHelper* GetCacheItemHelper(Handle* handle) const override; + void ApplyToHandle( + Cache* cache, Handle* handle, + const std::function& + callback) override; + void ReportProblems( const std::shared_ptr& /*info_log*/) const override; }; diff --git a/cache/lru_cache.cc b/cache/lru_cache.cc index 79c46bcc5c0..230a6726cad 100644 --- a/cache/lru_cache.cc +++ b/cache/lru_cache.cc @@ -677,6 +677,17 @@ const Cache::CacheItemHelper* LRUCache::GetCacheItemHelper( return h->helper; } +void LRUCache::ApplyToHandle( + Cache* cache, Handle* handle, + const std::function& callback) { + auto cache_ptr = static_cast(cache); + auto h = static_cast(handle); + callback(h->key(), h->value, + h->GetCharge(cache_ptr->GetShard(0).metadata_charge_policy_), + h->helper); +} + size_t LRUCache::TEST_GetLRUSize() { return SumOverShards([](LRUCacheShard& cs) { return cs.TEST_GetLRUSize(); }); } diff --git a/cache/lru_cache.h b/cache/lru_cache.h index 045480fbcf1..7fb2a88a006 100644 --- a/cache/lru_cache.h +++ b/cache/lru_cache.h @@ -452,6 +452,12 @@ class LRUCache size_t GetCharge(Handle* handle) const override; const CacheItemHelper* GetCacheItemHelper(Handle* handle) const override; + void ApplyToHandle( + Cache* cache, Handle* handle, + const std::function& callback) + override; + // Retrieves number of elements in LRU, for unit test purpose only. size_t TEST_GetLRUSize(); // Retrieves high pri pool ratio. diff --git a/include/rocksdb/advanced_cache.h b/include/rocksdb/advanced_cache.h index e2aefdd0112..ab9f722a05e 100644 --- a/include/rocksdb/advanced_cache.h +++ b/include/rocksdb/advanced_cache.h @@ -411,6 +411,14 @@ class Cache { const CacheItemHelper* helper)>& callback, const ApplyToAllEntriesOptions& opts) = 0; + // Apply a callback to a cache handle. The Cache must ensure the lifetime + // of the key passed to the callback is valid for the duration of the + // callback. The handle may not belong to the cache, but is guaranteed to + // be type compatible. + virtual void ApplyToHandle( + Cache* cache, Handle* handle, + const std::function& callback) = 0; // Remove all entries. // Prerequisite: no entry is referenced. virtual void EraseUnRefEntries() = 0; @@ -636,6 +644,15 @@ class CacheWrapper : public Cache { target_->ApplyToAllEntries(callback, opts); } + virtual void ApplyToHandle( + Cache* cache, Handle* handle, + const std::function& callback) + override { + auto cache_ptr = static_cast(cache); + target_->ApplyToHandle(cache_ptr->target_.get(), handle, callback); + } + void EraseUnRefEntries() override { target_->EraseUnRefEntries(); } void StartAsyncLookup(AsyncLookupHandle& async_handle) override {