mirror of
https://github.com/facebook/rocksdb.git
synced 2024-11-29 18:33:58 +00:00
3cacd4b4ec
Summary: The definition of the Cache class should not be needed by the vast majority of RocksDB users, so I think it is just distracting to include it in cache.h, which is primarily needed for configuring and creating caches. This change moves the class to a new header advanced_cache.h. It is just cut-and-paste except for modifying the class API comment. In general, operations on shared_ptr<Cache> should continue to work when only a forward declaration of Cache is available, as long as all the Cache instances provided are already shared_ptr. See https://stackoverflow.com/a/17650101/454544 Also, the most common way to customize a Cache is by wrapping an existing implementation, so it makes sense to provide CacheWrapper in the public API. This was a cut-and-paste job except removing the implementation of Name() so that derived classes must provide it. Intended follow-up: consolidate Release() into one function to reduce customization bugs / confusion Pull Request resolved: https://github.com/facebook/rocksdb/pull/11192 Test Plan: `make check` Reviewed By: anand1976 Differential Revision: D43055487 Pulled By: pdillinger fbshipit-source-id: 7b05492df35e0f30b581b4c24c579bc275b6d110
140 lines
4 KiB
C++
140 lines
4 KiB
C++
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
|
// 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 <cassert>
|
|
|
|
#include "rocksdb/advanced_cache.h"
|
|
#include "rocksdb/rocksdb_namespace.h"
|
|
|
|
namespace ROCKSDB_NAMESPACE {
|
|
|
|
// Returns the cached value given a cache handle.
|
|
template <typename T>
|
|
T* GetFromCacheHandle(Cache* cache, Cache::Handle* handle) {
|
|
assert(cache);
|
|
assert(handle);
|
|
return static_cast<T*>(cache->Value(handle));
|
|
}
|
|
|
|
// Turns a T* into a Slice so it can be used as a key with Cache.
|
|
template <typename T>
|
|
Slice GetSliceForKey(const T* t) {
|
|
return Slice(reinterpret_cast<const char*>(t), sizeof(T));
|
|
}
|
|
|
|
void ReleaseCacheHandleCleanup(void* arg1, void* arg2);
|
|
|
|
// Generic resource management object for cache handles that releases the handle
|
|
// when destroyed. Has unique ownership of the handle, so copying it is not
|
|
// allowed, while moving it transfers ownership.
|
|
template <typename T>
|
|
class CacheHandleGuard {
|
|
public:
|
|
CacheHandleGuard() = default;
|
|
|
|
CacheHandleGuard(Cache* cache, Cache::Handle* handle)
|
|
: cache_(cache),
|
|
handle_(handle),
|
|
value_(GetFromCacheHandle<T>(cache, handle)) {
|
|
assert(cache_ && handle_ && value_);
|
|
}
|
|
|
|
CacheHandleGuard(const CacheHandleGuard&) = delete;
|
|
CacheHandleGuard& operator=(const CacheHandleGuard&) = delete;
|
|
|
|
CacheHandleGuard(CacheHandleGuard&& rhs) noexcept
|
|
: cache_(rhs.cache_), handle_(rhs.handle_), value_(rhs.value_) {
|
|
assert((!cache_ && !handle_ && !value_) || (cache_ && handle_ && value_));
|
|
|
|
rhs.ResetFields();
|
|
}
|
|
|
|
CacheHandleGuard& operator=(CacheHandleGuard&& rhs) noexcept {
|
|
if (this == &rhs) {
|
|
return *this;
|
|
}
|
|
|
|
ReleaseHandle();
|
|
|
|
cache_ = rhs.cache_;
|
|
handle_ = rhs.handle_;
|
|
value_ = rhs.value_;
|
|
|
|
assert((!cache_ && !handle_ && !value_) || (cache_ && handle_ && value_));
|
|
|
|
rhs.ResetFields();
|
|
|
|
return *this;
|
|
}
|
|
|
|
~CacheHandleGuard() { ReleaseHandle(); }
|
|
|
|
bool IsEmpty() const { return !handle_; }
|
|
|
|
Cache* GetCache() const { return cache_; }
|
|
Cache::Handle* GetCacheHandle() const { return handle_; }
|
|
T* GetValue() const { return value_; }
|
|
|
|
void TransferTo(Cleanable* cleanable) {
|
|
if (cleanable) {
|
|
if (handle_ != nullptr) {
|
|
assert(cache_);
|
|
cleanable->RegisterCleanup(&ReleaseCacheHandleCleanup, cache_, handle_);
|
|
}
|
|
}
|
|
ResetFields();
|
|
}
|
|
|
|
void Reset() {
|
|
ReleaseHandle();
|
|
ResetFields();
|
|
}
|
|
|
|
private:
|
|
void ReleaseHandle() {
|
|
if (IsEmpty()) {
|
|
return;
|
|
}
|
|
|
|
assert(cache_);
|
|
cache_->Release(handle_);
|
|
}
|
|
|
|
void ResetFields() {
|
|
cache_ = nullptr;
|
|
handle_ = nullptr;
|
|
value_ = nullptr;
|
|
}
|
|
|
|
private:
|
|
Cache* cache_ = nullptr;
|
|
Cache::Handle* handle_ = nullptr;
|
|
T* value_ = nullptr;
|
|
};
|
|
|
|
// Build an aliasing shared_ptr that keeps `handle` in cache while there
|
|
// are references, but the pointer is to the value for that cache entry,
|
|
// which must be of type T. This is copyable, unlike CacheHandleGuard, but
|
|
// does not provide access to caching details.
|
|
template <typename T>
|
|
std::shared_ptr<T> MakeSharedCacheHandleGuard(Cache* cache,
|
|
Cache::Handle* handle) {
|
|
auto wrapper = std::make_shared<CacheHandleGuard<T>>(cache, handle);
|
|
return std::shared_ptr<T>(wrapper, GetFromCacheHandle<T>(cache, handle));
|
|
}
|
|
|
|
// Given the persistable data (saved) for a block cache entry, parse that
|
|
// into a cache entry object and insert it into the given cache. The charge
|
|
// of the new entry can be returned to the caller through `out_charge`.
|
|
Status WarmInCache(Cache* cache, const Slice& key, const Slice& saved,
|
|
Cache::CreateContext* create_context,
|
|
const Cache::CacheItemHelper* helper,
|
|
Cache::Priority priority = Cache::Priority::LOW,
|
|
size_t* out_charge = nullptr);
|
|
|
|
} // namespace ROCKSDB_NAMESPACE
|