]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | // This source code is licensed under both the GPLv2 (found in the | |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
5 | ||
6 | #pragma once | |
7 | ||
8 | #include <array> | |
9 | #include <cstddef> | |
10 | #include <memory> | |
11 | ||
12 | #include "cache/lru_cache.h" | |
13 | #include "memory/memory_allocator.h" | |
14 | #include "rocksdb/secondary_cache.h" | |
15 | #include "rocksdb/slice.h" | |
16 | #include "rocksdb/status.h" | |
17 | #include "util/compression.h" | |
18 | #include "util/mutexlock.h" | |
19 | ||
20 | namespace ROCKSDB_NAMESPACE { | |
21 | ||
22 | class CompressedSecondaryCacheResultHandle : public SecondaryCacheResultHandle { | |
23 | public: | |
24 | CompressedSecondaryCacheResultHandle(void* value, size_t size) | |
25 | : value_(value), size_(size) {} | |
26 | ~CompressedSecondaryCacheResultHandle() override = default; | |
27 | ||
28 | CompressedSecondaryCacheResultHandle( | |
29 | const CompressedSecondaryCacheResultHandle&) = delete; | |
30 | CompressedSecondaryCacheResultHandle& operator=( | |
31 | const CompressedSecondaryCacheResultHandle&) = delete; | |
32 | ||
33 | bool IsReady() override { return true; } | |
34 | ||
35 | void Wait() override {} | |
36 | ||
37 | void* Value() override { return value_; } | |
38 | ||
39 | size_t Size() override { return size_; } | |
40 | ||
41 | private: | |
42 | void* value_; | |
43 | size_t size_; | |
44 | }; | |
45 | ||
46 | // The CompressedSecondaryCache is a concrete implementation of | |
47 | // rocksdb::SecondaryCache. | |
48 | // | |
49 | // When a block is found from CompressedSecondaryCache::Lookup, we check whether | |
50 | // there is a dummy block with the same key in the primary cache. | |
51 | // 1. If the dummy block exits, we erase the block from | |
52 | // CompressedSecondaryCache and insert it into the primary cache. | |
53 | // 2. If not, we just insert a dummy block into the primary cache | |
54 | // (charging the actual size of the block) and don not erase the block from | |
55 | // CompressedSecondaryCache. A standalone handle is returned to the caller. | |
56 | // | |
57 | // When a block is evicted from the primary cache, we check whether | |
58 | // there is a dummy block with the same key in CompressedSecondaryCache. | |
59 | // 1. If the dummy block exits, the block is inserted into | |
60 | // CompressedSecondaryCache. | |
61 | // 2. If not, we just insert a dummy block (size 0) in CompressedSecondaryCache. | |
62 | // | |
63 | // Users can also cast a pointer to CompressedSecondaryCache and call methods on | |
64 | // it directly, especially custom methods that may be added | |
65 | // in the future. For example - | |
66 | // std::unique_ptr<rocksdb::SecondaryCache> cache = | |
67 | // NewCompressedSecondaryCache(opts); | |
68 | // static_cast<CompressedSecondaryCache*>(cache.get())->Erase(key); | |
69 | ||
70 | class CompressedSecondaryCache : public SecondaryCache { | |
71 | public: | |
72 | CompressedSecondaryCache( | |
73 | size_t capacity, int num_shard_bits, bool strict_capacity_limit, | |
74 | double high_pri_pool_ratio, double low_pri_pool_ratio, | |
75 | std::shared_ptr<MemoryAllocator> memory_allocator = nullptr, | |
76 | bool use_adaptive_mutex = kDefaultToAdaptiveMutex, | |
77 | CacheMetadataChargePolicy metadata_charge_policy = | |
78 | kDefaultCacheMetadataChargePolicy, | |
79 | CompressionType compression_type = CompressionType::kLZ4Compression, | |
80 | uint32_t compress_format_version = 2, | |
81 | bool enable_custom_split_merge = false); | |
82 | ~CompressedSecondaryCache() override; | |
83 | ||
84 | const char* Name() const override { return "CompressedSecondaryCache"; } | |
85 | ||
86 | Status Insert(const Slice& key, void* value, | |
87 | const Cache::CacheItemHelper* helper) override; | |
88 | ||
89 | std::unique_ptr<SecondaryCacheResultHandle> Lookup( | |
90 | const Slice& key, const Cache::CreateCallback& create_cb, bool /*wait*/, | |
91 | bool advise_erase, bool& is_in_sec_cache) override; | |
92 | ||
93 | bool SupportForceErase() const override { return true; } | |
94 | ||
95 | void Erase(const Slice& key) override; | |
96 | ||
97 | void WaitAll(std::vector<SecondaryCacheResultHandle*> /*handles*/) override {} | |
98 | ||
99 | Status SetCapacity(size_t capacity) override; | |
100 | ||
101 | Status GetCapacity(size_t& capacity) override; | |
102 | ||
103 | std::string GetPrintableOptions() const override; | |
104 | ||
105 | private: | |
106 | friend class CompressedSecondaryCacheTest; | |
107 | static constexpr std::array<uint16_t, 8> malloc_bin_sizes_{ | |
108 | 128, 256, 512, 1024, 2048, 4096, 8192, 16384}; | |
109 | ||
110 | struct CacheValueChunk { | |
111 | // TODO try "CacheAllocationPtr next;". | |
112 | CacheValueChunk* next; | |
113 | size_t size; | |
114 | // Beginning of the chunk data (MUST BE THE LAST FIELD IN THIS STRUCT!) | |
115 | char data[1]; | |
116 | ||
117 | void Free() { delete[] reinterpret_cast<char*>(this); } | |
118 | }; | |
119 | ||
120 | // Split value into chunks to better fit into jemalloc bins. The chunks | |
121 | // are stored in CacheValueChunk and extra charge is needed for each chunk, | |
122 | // so the cache charge is recalculated here. | |
123 | CacheValueChunk* SplitValueIntoChunks(const Slice& value, | |
124 | CompressionType compression_type, | |
125 | size_t& charge); | |
126 | ||
127 | // After merging chunks, the extra charge for each chunk is removed, so | |
128 | // the charge is recalculated. | |
129 | CacheAllocationPtr MergeChunksIntoValue(const void* chunks_head, | |
130 | size_t& charge); | |
131 | ||
132 | // An implementation of Cache::DeleterFn. | |
133 | static Cache::DeleterFn GetDeletionCallback(bool enable_custom_split_merge); | |
134 | std::shared_ptr<Cache> cache_; | |
135 | CompressedSecondaryCacheOptions cache_options_; | |
136 | mutable port::Mutex capacity_mutex_; | |
137 | }; | |
138 | ||
139 | } // namespace ROCKSDB_NAMESPACE |