forked from facebook/rocksdb
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Charge blob cache usage against the global memory limit (facebook#10321)
Summary: To help service owners to manage their memory budget effectively, we have been working towards counting all major memory users inside RocksDB towards a single global memory limit (see e.g. https://github.com/facebook/rocksdb/wiki/Write-Buffer-Manager#cost-memory-used-in-memtable-to-block-cache). The global limit is specified by the capacity of the block-based table's block cache, and is technically implemented by inserting dummy entries ("reservations") into the block cache. The goal of this task is to support charging the memory usage of the new blob cache against this global memory limit when the backing cache of the blob cache and the block cache are different. This PR is a part of facebook#10156 Pull Request resolved: facebook#10321 Reviewed By: ltamasi Differential Revision: D37913590 Pulled By: gangliao fbshipit-source-id: eaacf23907f82dc7d18964a3f24d7039a2937a72
- Loading branch information
1 parent
18a61a1
commit 0b6bc10
Showing
20 changed files
with
661 additions
and
74 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// Copyright (c) Meta Platforms, Inc. and affiliates. | ||
// This source code is licensed under both the GPLv2 (found in the | ||
// COPYING file in the root directory) and Apache 2.0 License | ||
// (found in the LICENSE.Apache file in the root directory). | ||
|
||
#include "cache/charged_cache.h" | ||
|
||
#include "cache/cache_reservation_manager.h" | ||
|
||
namespace ROCKSDB_NAMESPACE { | ||
|
||
ChargedCache::ChargedCache(std::shared_ptr<Cache> cache, | ||
std::shared_ptr<Cache> block_cache) | ||
: cache_(cache), | ||
cache_res_mgr_(std::make_shared<ConcurrentCacheReservationManager>( | ||
std::make_shared< | ||
CacheReservationManagerImpl<CacheEntryRole::kBlobCache>>( | ||
block_cache))) {} | ||
|
||
Status ChargedCache::Insert(const Slice& key, void* value, size_t charge, | ||
DeleterFn deleter, Handle** handle, | ||
Priority priority) { | ||
Status s = cache_->Insert(key, value, charge, deleter, handle, priority); | ||
if (s.ok()) { | ||
// Insert may cause the cache entry eviction if the cache is full. So we | ||
// directly call the reservation manager to update the total memory used | ||
// in the cache. | ||
assert(cache_res_mgr_); | ||
cache_res_mgr_->UpdateCacheReservation(cache_->GetUsage()) | ||
.PermitUncheckedError(); | ||
} | ||
return s; | ||
} | ||
|
||
Status ChargedCache::Insert(const Slice& key, void* value, | ||
const CacheItemHelper* helper, size_t charge, | ||
Handle** handle, Priority priority) { | ||
Status s = cache_->Insert(key, value, helper, charge, handle, priority); | ||
if (s.ok()) { | ||
// Insert may cause the cache entry eviction if the cache is full. So we | ||
// directly call the reservation manager to update the total memory used | ||
// in the cache. | ||
assert(cache_res_mgr_); | ||
cache_res_mgr_->UpdateCacheReservation(cache_->GetUsage()) | ||
.PermitUncheckedError(); | ||
} | ||
return s; | ||
} | ||
|
||
Cache::Handle* ChargedCache::Lookup(const Slice& key, Statistics* stats) { | ||
return cache_->Lookup(key, stats); | ||
} | ||
|
||
Cache::Handle* ChargedCache::Lookup(const Slice& key, | ||
const CacheItemHelper* helper, | ||
const CreateCallback& create_cb, | ||
Priority priority, bool wait, | ||
Statistics* stats) { | ||
auto handle = cache_->Lookup(key, helper, create_cb, priority, wait, stats); | ||
// Lookup may promote the KV pair from the secondary cache to the primary | ||
// cache. So we directly call the reservation manager to update the total | ||
// memory used in the cache. | ||
assert(cache_res_mgr_); | ||
cache_res_mgr_->UpdateCacheReservation(cache_->GetUsage()) | ||
.PermitUncheckedError(); | ||
return handle; | ||
} | ||
|
||
bool ChargedCache::Release(Cache::Handle* handle, bool useful, | ||
bool erase_if_last_ref) { | ||
size_t memory_used_delta = cache_->GetUsage(handle); | ||
bool erased = cache_->Release(handle, useful, erase_if_last_ref); | ||
if (erased) { | ||
assert(cache_res_mgr_); | ||
cache_res_mgr_ | ||
->UpdateCacheReservation(memory_used_delta, /* increase */ false) | ||
.PermitUncheckedError(); | ||
} | ||
return erased; | ||
} | ||
|
||
bool ChargedCache::Release(Cache::Handle* handle, bool erase_if_last_ref) { | ||
size_t memory_used_delta = cache_->GetUsage(handle); | ||
bool erased = cache_->Release(handle, erase_if_last_ref); | ||
if (erased) { | ||
assert(cache_res_mgr_); | ||
cache_res_mgr_ | ||
->UpdateCacheReservation(memory_used_delta, /* increase */ false) | ||
.PermitUncheckedError(); | ||
} | ||
return erased; | ||
} | ||
|
||
void ChargedCache::Erase(const Slice& key) { | ||
cache_->Erase(key); | ||
assert(cache_res_mgr_); | ||
cache_res_mgr_->UpdateCacheReservation(cache_->GetUsage()) | ||
.PermitUncheckedError(); | ||
} | ||
|
||
void ChargedCache::EraseUnRefEntries() { | ||
cache_->EraseUnRefEntries(); | ||
assert(cache_res_mgr_); | ||
cache_res_mgr_->UpdateCacheReservation(cache_->GetUsage()) | ||
.PermitUncheckedError(); | ||
} | ||
|
||
void ChargedCache::SetCapacity(size_t capacity) { | ||
cache_->SetCapacity(capacity); | ||
// SetCapacity can result in evictions when the cache capacity is decreased, | ||
// so we would want to update the cache reservation here as well. | ||
assert(cache_res_mgr_); | ||
cache_res_mgr_->UpdateCacheReservation(cache_->GetUsage()) | ||
.PermitUncheckedError(); | ||
} | ||
|
||
} // namespace ROCKSDB_NAMESPACE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// Copyright (c) Meta Platforms, Inc. and affiliates. | ||
// This source code is licensed under both the GPLv2 (found in the | ||
// COPYING file in the root directory) and Apache 2.0 License | ||
// (found in the LICENSE.Apache file in the root directory). | ||
|
||
#pragma once | ||
|
||
#include <string> | ||
|
||
#include "port/port.h" | ||
#include "rocksdb/cache.h" | ||
|
||
namespace ROCKSDB_NAMESPACE { | ||
|
||
class ConcurrentCacheReservationManager; | ||
|
||
// A cache interface which wraps around another cache and takes care of | ||
// reserving space in block cache towards a single global memory limit, and | ||
// forwards all the calls to the underlying cache. | ||
class ChargedCache : public Cache { | ||
public: | ||
ChargedCache(std::shared_ptr<Cache> cache, | ||
std::shared_ptr<Cache> block_cache); | ||
~ChargedCache() override = default; | ||
|
||
Status Insert(const Slice& key, void* value, size_t charge, DeleterFn deleter, | ||
Handle** handle, Priority priority) override; | ||
Status Insert(const Slice& key, void* value, const CacheItemHelper* helper, | ||
size_t charge, Handle** handle = nullptr, | ||
Priority priority = Priority::LOW) override; | ||
|
||
Cache::Handle* Lookup(const Slice& key, Statistics* stats) override; | ||
Cache::Handle* Lookup(const Slice& key, const CacheItemHelper* helper, | ||
const CreateCallback& create_cb, Priority priority, | ||
bool wait, Statistics* stats = nullptr) override; | ||
|
||
bool Release(Cache::Handle* handle, bool useful, | ||
bool erase_if_last_ref = false) override; | ||
bool Release(Cache::Handle* handle, bool erase_if_last_ref = false) override; | ||
|
||
void Erase(const Slice& key) override; | ||
void EraseUnRefEntries() override; | ||
|
||
static const char* kClassName() { return "ChargedCache"; } | ||
const char* Name() const override { return kClassName(); } | ||
|
||
uint64_t NewId() override { return cache_->NewId(); } | ||
|
||
void SetCapacity(size_t capacity) override; | ||
|
||
void SetStrictCapacityLimit(bool strict_capacity_limit) override { | ||
cache_->SetStrictCapacityLimit(strict_capacity_limit); | ||
} | ||
|
||
bool HasStrictCapacityLimit() const override { | ||
return cache_->HasStrictCapacityLimit(); | ||
} | ||
|
||
void* Value(Cache::Handle* handle) override { return cache_->Value(handle); } | ||
|
||
bool IsReady(Cache::Handle* handle) override { | ||
return cache_->IsReady(handle); | ||
} | ||
|
||
void Wait(Cache::Handle* handle) override { cache_->Wait(handle); } | ||
|
||
void WaitAll(std::vector<Handle*>& handles) override { | ||
cache_->WaitAll(handles); | ||
} | ||
|
||
bool Ref(Cache::Handle* handle) override { return cache_->Ref(handle); } | ||
|
||
size_t GetCapacity() const override { return cache_->GetCapacity(); } | ||
|
||
size_t GetUsage() const override { return cache_->GetUsage(); } | ||
|
||
size_t GetUsage(Cache::Handle* handle) const override { | ||
return cache_->GetUsage(handle); | ||
} | ||
|
||
size_t GetPinnedUsage() const override { return cache_->GetPinnedUsage(); } | ||
|
||
size_t GetCharge(Cache::Handle* handle) const override { | ||
return cache_->GetCharge(handle); | ||
} | ||
|
||
Cache::DeleterFn GetDeleter(Cache::Handle* handle) const override { | ||
return cache_->GetDeleter(handle); | ||
} | ||
|
||
void ApplyToAllEntries( | ||
const std::function<void(const Slice& key, void* value, size_t charge, | ||
Cache::DeleterFn deleter)>& callback, | ||
const Cache::ApplyToAllEntriesOptions& opts) override { | ||
cache_->ApplyToAllEntries(callback, opts); | ||
} | ||
|
||
void ApplyToAllCacheEntries(void (*callback)(void* value, size_t charge), | ||
bool thread_safe) override { | ||
cache_->ApplyToAllCacheEntries(callback, thread_safe); | ||
} | ||
|
||
std::string GetPrintableOptions() const override { | ||
return cache_->GetPrintableOptions(); | ||
} | ||
|
||
void DisownData() override { return cache_->DisownData(); } | ||
|
||
inline Cache* GetCache() const { return cache_.get(); } | ||
|
||
inline ConcurrentCacheReservationManager* TEST_GetCacheReservationManager() | ||
const { | ||
return cache_res_mgr_.get(); | ||
} | ||
|
||
private: | ||
std::shared_ptr<Cache> cache_; | ||
std::shared_ptr<ConcurrentCacheReservationManager> cache_res_mgr_; | ||
}; | ||
|
||
} // namespace ROCKSDB_NAMESPACE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.