diff options
Diffstat (limited to 'src/rocksdb/cache/compressed_secondary_cache.h')
-rw-r--r-- | src/rocksdb/cache/compressed_secondary_cache.h | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/rocksdb/cache/compressed_secondary_cache.h b/src/rocksdb/cache/compressed_secondary_cache.h new file mode 100644 index 000000000..4dee38802 --- /dev/null +++ b/src/rocksdb/cache/compressed_secondary_cache.h @@ -0,0 +1,139 @@ +// 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 <array> +#include <cstddef> +#include <memory> + +#include "cache/lru_cache.h" +#include "memory/memory_allocator.h" +#include "rocksdb/secondary_cache.h" +#include "rocksdb/slice.h" +#include "rocksdb/status.h" +#include "util/compression.h" +#include "util/mutexlock.h" + +namespace ROCKSDB_NAMESPACE { + +class CompressedSecondaryCacheResultHandle : public SecondaryCacheResultHandle { + public: + CompressedSecondaryCacheResultHandle(void* value, size_t size) + : value_(value), size_(size) {} + ~CompressedSecondaryCacheResultHandle() override = default; + + CompressedSecondaryCacheResultHandle( + const CompressedSecondaryCacheResultHandle&) = delete; + CompressedSecondaryCacheResultHandle& operator=( + const CompressedSecondaryCacheResultHandle&) = delete; + + bool IsReady() override { return true; } + + void Wait() override {} + + void* Value() override { return value_; } + + size_t Size() override { return size_; } + + private: + void* value_; + size_t size_; +}; + +// The CompressedSecondaryCache is a concrete implementation of +// rocksdb::SecondaryCache. +// +// When a block is found from CompressedSecondaryCache::Lookup, we check whether +// there is a dummy block with the same key in the primary cache. +// 1. If the dummy block exits, we erase the block from +// CompressedSecondaryCache and insert it into the primary cache. +// 2. If not, we just insert a dummy block into the primary cache +// (charging the actual size of the block) and don not erase the block from +// CompressedSecondaryCache. A standalone handle is returned to the caller. +// +// When a block is evicted from the primary cache, we check whether +// there is a dummy block with the same key in CompressedSecondaryCache. +// 1. If the dummy block exits, the block is inserted into +// CompressedSecondaryCache. +// 2. If not, we just insert a dummy block (size 0) in CompressedSecondaryCache. +// +// Users can also cast a pointer to CompressedSecondaryCache and call methods on +// it directly, especially custom methods that may be added +// in the future. For example - +// std::unique_ptr<rocksdb::SecondaryCache> cache = +// NewCompressedSecondaryCache(opts); +// static_cast<CompressedSecondaryCache*>(cache.get())->Erase(key); + +class CompressedSecondaryCache : public SecondaryCache { + public: + CompressedSecondaryCache( + size_t capacity, int num_shard_bits, bool strict_capacity_limit, + double high_pri_pool_ratio, double low_pri_pool_ratio, + std::shared_ptr<MemoryAllocator> memory_allocator = nullptr, + bool use_adaptive_mutex = kDefaultToAdaptiveMutex, + CacheMetadataChargePolicy metadata_charge_policy = + kDefaultCacheMetadataChargePolicy, + CompressionType compression_type = CompressionType::kLZ4Compression, + uint32_t compress_format_version = 2, + bool enable_custom_split_merge = false); + ~CompressedSecondaryCache() override; + + const char* Name() const override { return "CompressedSecondaryCache"; } + + Status Insert(const Slice& key, void* value, + const Cache::CacheItemHelper* helper) override; + + std::unique_ptr<SecondaryCacheResultHandle> Lookup( + const Slice& key, const Cache::CreateCallback& create_cb, bool /*wait*/, + bool advise_erase, bool& is_in_sec_cache) override; + + bool SupportForceErase() const override { return true; } + + void Erase(const Slice& key) override; + + void WaitAll(std::vector<SecondaryCacheResultHandle*> /*handles*/) override {} + + Status SetCapacity(size_t capacity) override; + + Status GetCapacity(size_t& capacity) override; + + std::string GetPrintableOptions() const override; + + private: + friend class CompressedSecondaryCacheTest; + static constexpr std::array<uint16_t, 8> malloc_bin_sizes_{ + 128, 256, 512, 1024, 2048, 4096, 8192, 16384}; + + struct CacheValueChunk { + // TODO try "CacheAllocationPtr next;". + CacheValueChunk* next; + size_t size; + // Beginning of the chunk data (MUST BE THE LAST FIELD IN THIS STRUCT!) + char data[1]; + + void Free() { delete[] reinterpret_cast<char*>(this); } + }; + + // Split value into chunks to better fit into jemalloc bins. The chunks + // are stored in CacheValueChunk and extra charge is needed for each chunk, + // so the cache charge is recalculated here. + CacheValueChunk* SplitValueIntoChunks(const Slice& value, + CompressionType compression_type, + size_t& charge); + + // After merging chunks, the extra charge for each chunk is removed, so + // the charge is recalculated. + CacheAllocationPtr MergeChunksIntoValue(const void* chunks_head, + size_t& charge); + + // An implementation of Cache::DeleterFn. + static Cache::DeleterFn GetDeletionCallback(bool enable_custom_split_merge); + std::shared_ptr<Cache> cache_; + CompressedSecondaryCacheOptions cache_options_; + mutable port::Mutex capacity_mutex_; +}; + +} // namespace ROCKSDB_NAMESPACE |