// 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 #include "rocksdb/cache.h" #include "rocksdb/rocksdb_namespace.h" namespace ROCKSDB_NAMESPACE { // Returns the cached value given a cache handle. template T* GetFromCacheHandle(Cache* cache, Cache::Handle* handle) { assert(cache); assert(handle); return static_cast(cache->Value(handle)); } // Simple generic deleter for Cache (to be used with Cache::Insert). template void DeleteCacheEntry(const Slice& /* key */, void* value) { delete static_cast(value); } // Turns a T* into a Slice so it can be used as a key with Cache. template Slice GetSlice(const T* t) { return Slice(reinterpret_cast(t), sizeof(T)); } // 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 class CacheHandleGuard { public: CacheHandleGuard() = default; CacheHandleGuard(Cache* cache, Cache::Handle* handle) : cache_(cache), handle_(handle), value_(GetFromCacheHandle(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 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 std::shared_ptr MakeSharedCacheHandleGuard(Cache* cache, Cache::Handle* handle) { auto wrapper = std::make_shared>(cache, handle); return std::shared_ptr(wrapper, static_cast(cache->Value(handle))); } } // namespace ROCKSDB_NAMESPACE