lru_cache.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  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. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. #pragma once
  10. #include <memory>
  11. #include <string>
  12. #include "cache/sharded_cache.h"
  13. #include "port/lang.h"
  14. #include "port/likely.h"
  15. #include "port/malloc.h"
  16. #include "port/port.h"
  17. #include "util/autovector.h"
  18. #include "util/distributed_mutex.h"
  19. namespace ROCKSDB_NAMESPACE {
  20. namespace lru_cache {
  21. // LRU cache implementation. This class is not thread-safe.
  22. // An entry is a variable length heap-allocated structure.
  23. // Entries are referenced by cache and/or by any external entity.
  24. // The cache keeps all its entries in a hash table. Some elements
  25. // are also stored on LRU list.
  26. //
  27. // LRUHandle can be in these states:
  28. // 1. Referenced externally AND in hash table.
  29. // In that case the entry is *not* in the LRU list
  30. // (refs >= 1 && in_cache == true)
  31. // 2. Not referenced externally AND in hash table.
  32. // In that case the entry is in the LRU list and can be freed.
  33. // (refs == 0 && in_cache == true)
  34. // 3. Referenced externally AND not in hash table.
  35. // In that case the entry is not in the LRU list and not in hash table.
  36. // The entry must be freed if refs becomes 0 in this state.
  37. // (refs >= 1 && in_cache == false)
  38. // If you call LRUCacheShard::Release enough times on an entry in state 1, it
  39. // will go into state 2. To move from state 1 to state 3, either call
  40. // LRUCacheShard::Erase or LRUCacheShard::Insert with the same key (but
  41. // possibly different value). To move from state 2 to state 1, use
  42. // LRUCacheShard::Lookup.
  43. // While refs > 0, public properties like value and deleter must not change.
  44. struct LRUHandle : public Cache::Handle {
  45. Cache::ObjectPtr value;
  46. const Cache::CacheItemHelper* helper;
  47. LRUHandle* next_hash;
  48. LRUHandle* next;
  49. LRUHandle* prev;
  50. size_t total_charge; // TODO(opt): Only allow uint32_t?
  51. size_t key_length;
  52. // The hash of key(). Used for fast sharding and comparisons.
  53. uint32_t hash;
  54. // The number of external refs to this entry. The cache itself is not counted.
  55. uint32_t refs;
  56. // Mutable flags - access controlled by mutex
  57. // The m_ and M_ prefixes (and im_ and IM_ later) are to hopefully avoid
  58. // checking an M_ flag on im_flags or an IM_ flag on m_flags.
  59. uint8_t m_flags;
  60. enum MFlags : uint8_t {
  61. // Whether this entry is referenced by the hash table.
  62. M_IN_CACHE = (1 << 0),
  63. // Whether this entry has had any lookups (hits).
  64. M_HAS_HIT = (1 << 1),
  65. // Whether this entry is in high-pri pool.
  66. M_IN_HIGH_PRI_POOL = (1 << 2),
  67. // Whether this entry is in low-pri pool.
  68. M_IN_LOW_PRI_POOL = (1 << 3),
  69. };
  70. // "Immutable" flags - only set in single-threaded context and then
  71. // can be accessed without mutex
  72. uint8_t im_flags;
  73. enum ImFlags : uint8_t {
  74. // Whether this entry is high priority entry.
  75. IM_IS_HIGH_PRI = (1 << 0),
  76. // Whether this entry is low priority entry.
  77. IM_IS_LOW_PRI = (1 << 1),
  78. // Marks result handles that should not be inserted into cache
  79. IM_IS_STANDALONE = (1 << 2),
  80. };
  81. // Beginning of the key (MUST BE THE LAST FIELD IN THIS STRUCT!)
  82. char key_data[1];
  83. Slice key() const { return Slice(key_data, key_length); }
  84. // For HandleImpl concept
  85. uint32_t GetHash() const { return hash; }
  86. // Increase the reference count by 1.
  87. void Ref() { refs++; }
  88. // Just reduce the reference count by 1. Return true if it was last reference.
  89. bool Unref() {
  90. assert(refs > 0);
  91. refs--;
  92. return refs == 0;
  93. }
  94. // Return true if there are external refs, false otherwise.
  95. bool HasRefs() const { return refs > 0; }
  96. bool InCache() const { return m_flags & M_IN_CACHE; }
  97. bool IsHighPri() const { return im_flags & IM_IS_HIGH_PRI; }
  98. bool InHighPriPool() const { return m_flags & M_IN_HIGH_PRI_POOL; }
  99. bool IsLowPri() const { return im_flags & IM_IS_LOW_PRI; }
  100. bool InLowPriPool() const { return m_flags & M_IN_LOW_PRI_POOL; }
  101. bool HasHit() const { return m_flags & M_HAS_HIT; }
  102. bool IsStandalone() const { return im_flags & IM_IS_STANDALONE; }
  103. void SetInCache(bool in_cache) {
  104. if (in_cache) {
  105. m_flags |= M_IN_CACHE;
  106. } else {
  107. m_flags &= ~M_IN_CACHE;
  108. }
  109. }
  110. void SetPriority(Cache::Priority priority) {
  111. if (priority == Cache::Priority::HIGH) {
  112. im_flags |= IM_IS_HIGH_PRI;
  113. im_flags &= ~IM_IS_LOW_PRI;
  114. } else if (priority == Cache::Priority::LOW) {
  115. im_flags &= ~IM_IS_HIGH_PRI;
  116. im_flags |= IM_IS_LOW_PRI;
  117. } else {
  118. im_flags &= ~IM_IS_HIGH_PRI;
  119. im_flags &= ~IM_IS_LOW_PRI;
  120. }
  121. }
  122. void SetInHighPriPool(bool in_high_pri_pool) {
  123. if (in_high_pri_pool) {
  124. m_flags |= M_IN_HIGH_PRI_POOL;
  125. } else {
  126. m_flags &= ~M_IN_HIGH_PRI_POOL;
  127. }
  128. }
  129. void SetInLowPriPool(bool in_low_pri_pool) {
  130. if (in_low_pri_pool) {
  131. m_flags |= M_IN_LOW_PRI_POOL;
  132. } else {
  133. m_flags &= ~M_IN_LOW_PRI_POOL;
  134. }
  135. }
  136. void SetHit() { m_flags |= M_HAS_HIT; }
  137. void SetIsStandalone(bool is_standalone) {
  138. if (is_standalone) {
  139. im_flags |= IM_IS_STANDALONE;
  140. } else {
  141. im_flags &= ~IM_IS_STANDALONE;
  142. }
  143. }
  144. void Free(MemoryAllocator* allocator) {
  145. assert(refs == 0);
  146. assert(helper);
  147. if (helper->del_cb) {
  148. helper->del_cb(value, allocator);
  149. }
  150. free(this);
  151. }
  152. inline size_t CalcuMetaCharge(
  153. CacheMetadataChargePolicy metadata_charge_policy) const {
  154. if (metadata_charge_policy != kFullChargeCacheMetadata) {
  155. return 0;
  156. } else {
  157. #ifdef ROCKSDB_MALLOC_USABLE_SIZE
  158. return malloc_usable_size(
  159. const_cast<void*>(static_cast<const void*>(this)));
  160. #else
  161. // This is the size that is used when a new handle is created.
  162. return sizeof(LRUHandle) - 1 + key_length;
  163. #endif
  164. }
  165. }
  166. // Calculate the memory usage by metadata.
  167. inline void CalcTotalCharge(
  168. size_t charge, CacheMetadataChargePolicy metadata_charge_policy) {
  169. total_charge = charge + CalcuMetaCharge(metadata_charge_policy);
  170. }
  171. inline size_t GetCharge(
  172. CacheMetadataChargePolicy metadata_charge_policy) const {
  173. size_t meta_charge = CalcuMetaCharge(metadata_charge_policy);
  174. assert(total_charge >= meta_charge);
  175. return total_charge - meta_charge;
  176. }
  177. };
  178. // We provide our own simple hash table since it removes a whole bunch
  179. // of porting hacks and is also faster than some of the built-in hash
  180. // table implementations in some of the compiler/runtime combinations
  181. // we have tested. E.g., readrandom speeds up by ~5% over the g++
  182. // 4.4.3's builtin hashtable.
  183. class LRUHandleTable {
  184. public:
  185. explicit LRUHandleTable(int max_upper_hash_bits, MemoryAllocator* allocator);
  186. ~LRUHandleTable();
  187. LRUHandle* Lookup(const Slice& key, uint32_t hash);
  188. LRUHandle* Insert(LRUHandle* h);
  189. LRUHandle* Remove(const Slice& key, uint32_t hash);
  190. template <typename T>
  191. void ApplyToEntriesRange(T func, size_t index_begin, size_t index_end) {
  192. for (size_t i = index_begin; i < index_end; i++) {
  193. LRUHandle* h = list_[i];
  194. while (h != nullptr) {
  195. auto n = h->next_hash;
  196. assert(h->InCache());
  197. func(h);
  198. h = n;
  199. }
  200. }
  201. }
  202. int GetLengthBits() const { return length_bits_; }
  203. size_t GetOccupancyCount() const { return elems_; }
  204. MemoryAllocator* GetAllocator() const { return allocator_; }
  205. private:
  206. // Return a pointer to slot that points to a cache entry that
  207. // matches key/hash. If there is no such cache entry, return a
  208. // pointer to the trailing slot in the corresponding linked list.
  209. LRUHandle** FindPointer(const Slice& key, uint32_t hash);
  210. void Resize();
  211. // Number of hash bits (upper because lower bits used for sharding)
  212. // used for table index. Length == 1 << length_bits_
  213. int length_bits_;
  214. // The table consists of an array of buckets where each bucket is
  215. // a linked list of cache entries that hash into the bucket.
  216. std::unique_ptr<LRUHandle*[]> list_;
  217. // Number of elements currently in the table.
  218. uint32_t elems_;
  219. // Set from max_upper_hash_bits (see constructor).
  220. const int max_length_bits_;
  221. // From Cache, needed for delete
  222. MemoryAllocator* const allocator_;
  223. };
  224. // A single shard of sharded cache.
  225. class ALIGN_AS(CACHE_LINE_SIZE) LRUCacheShard final : public CacheShardBase {
  226. public:
  227. // NOTE: the eviction_callback ptr is saved, as is it assumed to be kept
  228. // alive in Cache.
  229. LRUCacheShard(size_t capacity, bool strict_capacity_limit,
  230. double high_pri_pool_ratio, double low_pri_pool_ratio,
  231. bool use_adaptive_mutex,
  232. CacheMetadataChargePolicy metadata_charge_policy,
  233. int max_upper_hash_bits, MemoryAllocator* allocator,
  234. const Cache::EvictionCallback* eviction_callback);
  235. public: // Type definitions expected as parameter to ShardedCache
  236. using HandleImpl = LRUHandle;
  237. using HashVal = uint32_t;
  238. using HashCref = uint32_t;
  239. public: // Function definitions expected as parameter to ShardedCache
  240. static inline HashVal ComputeHash(const Slice& key, uint32_t seed) {
  241. return Lower32of64(GetSliceNPHash64(key, seed));
  242. }
  243. // Separate from constructor so caller can easily make an array of LRUCache
  244. // if current usage is more than new capacity, the function will attempt to
  245. // free the needed space.
  246. void SetCapacity(size_t capacity);
  247. // Set the flag to reject insertion if cache if full.
  248. void SetStrictCapacityLimit(bool strict_capacity_limit);
  249. // Set percentage of capacity reserved for high-pri cache entries.
  250. void SetHighPriorityPoolRatio(double high_pri_pool_ratio);
  251. // Set percentage of capacity reserved for low-pri cache entries.
  252. void SetLowPriorityPoolRatio(double low_pri_pool_ratio);
  253. // Like Cache methods, but with an extra "hash" parameter.
  254. Status Insert(const Slice& key, uint32_t hash, Cache::ObjectPtr value,
  255. const Cache::CacheItemHelper* helper, size_t charge,
  256. LRUHandle** handle, Cache::Priority priority);
  257. LRUHandle* CreateStandalone(const Slice& key, uint32_t hash,
  258. Cache::ObjectPtr obj,
  259. const Cache::CacheItemHelper* helper,
  260. size_t charge, bool allow_uncharged);
  261. LRUHandle* Lookup(const Slice& key, uint32_t hash,
  262. const Cache::CacheItemHelper* helper,
  263. Cache::CreateContext* create_context,
  264. Cache::Priority priority, Statistics* stats);
  265. bool Release(LRUHandle* handle, bool useful, bool erase_if_last_ref);
  266. bool Ref(LRUHandle* handle);
  267. void Erase(const Slice& key, uint32_t hash);
  268. // Although in some platforms the update of size_t is atomic, to make sure
  269. // GetUsage() and GetPinnedUsage() work correctly under any platform, we'll
  270. // protect them with mutex_.
  271. size_t GetUsage() const;
  272. size_t GetPinnedUsage() const;
  273. size_t GetOccupancyCount() const;
  274. size_t GetTableAddressCount() const;
  275. void ApplyToSomeEntries(
  276. const std::function<void(const Slice& key, Cache::ObjectPtr value,
  277. size_t charge,
  278. const Cache::CacheItemHelper* helper)>& callback,
  279. size_t average_entries_per_lock, size_t* state);
  280. void EraseUnRefEntries();
  281. public: // other function definitions
  282. void TEST_GetLRUList(LRUHandle** lru, LRUHandle** lru_low_pri,
  283. LRUHandle** lru_bottom_pri);
  284. // Retrieves number of elements in LRU, for unit test purpose only.
  285. // Not threadsafe.
  286. size_t TEST_GetLRUSize();
  287. // Retrieves high pri pool ratio
  288. double GetHighPriPoolRatio();
  289. // Retrieves low pri pool ratio
  290. double GetLowPriPoolRatio();
  291. void AppendPrintableOptions(std::string& /*str*/) const;
  292. private:
  293. friend class LRUCache;
  294. // Insert an item into the hash table and, if handle is null, insert into
  295. // the LRU list. Older items are evicted as necessary. Frees `item` on
  296. // non-OK status.
  297. Status InsertItem(LRUHandle* item, LRUHandle** handle);
  298. void LRU_Remove(LRUHandle* e);
  299. void LRU_Insert(LRUHandle* e);
  300. // Overflow the last entry in high-pri pool to low-pri pool until size of
  301. // high-pri pool is no larger than the size specify by high_pri_pool_pct.
  302. void MaintainPoolSize();
  303. // Free some space following strict LRU policy until enough space
  304. // to hold (usage_ + charge) is freed or the lru list is empty
  305. // This function is not thread safe - it needs to be executed while
  306. // holding the mutex_.
  307. void EvictFromLRU(size_t charge, autovector<LRUHandle*>* deleted);
  308. void NotifyEvicted(const autovector<LRUHandle*>& evicted_handles);
  309. LRUHandle* CreateHandle(const Slice& key, uint32_t hash,
  310. Cache::ObjectPtr value,
  311. const Cache::CacheItemHelper* helper, size_t charge);
  312. // Initialized before use.
  313. size_t capacity_;
  314. // Memory size for entries in high-pri pool.
  315. size_t high_pri_pool_usage_;
  316. // Memory size for entries in low-pri pool.
  317. size_t low_pri_pool_usage_;
  318. // Whether to reject insertion if cache reaches its full capacity.
  319. bool strict_capacity_limit_;
  320. // Ratio of capacity reserved for high priority cache entries.
  321. double high_pri_pool_ratio_;
  322. // High-pri pool size, equals to capacity * high_pri_pool_ratio.
  323. // Remember the value to avoid recomputing each time.
  324. double high_pri_pool_capacity_;
  325. // Ratio of capacity reserved for low priority cache entries.
  326. double low_pri_pool_ratio_;
  327. // Low-pri pool size, equals to capacity * low_pri_pool_ratio.
  328. // Remember the value to avoid recomputing each time.
  329. double low_pri_pool_capacity_;
  330. // Dummy head of LRU list.
  331. // lru.prev is newest entry, lru.next is oldest entry.
  332. // LRU contains items which can be evicted, ie reference only by cache
  333. LRUHandle lru_;
  334. // Pointer to head of low-pri pool in LRU list.
  335. LRUHandle* lru_low_pri_;
  336. // Pointer to head of bottom-pri pool in LRU list.
  337. LRUHandle* lru_bottom_pri_;
  338. // ------------^^^^^^^^^^^^^-----------
  339. // Not frequently modified data members
  340. // ------------------------------------
  341. //
  342. // We separate data members that are updated frequently from the ones that
  343. // are not frequently updated so that they don't share the same cache line
  344. // which will lead into false cache sharing
  345. //
  346. // ------------------------------------
  347. // Frequently modified data members
  348. // ------------vvvvvvvvvvvvv-----------
  349. LRUHandleTable table_;
  350. // Memory size for entries residing in the cache.
  351. size_t usage_;
  352. // Memory size for entries residing only in the LRU list.
  353. size_t lru_usage_;
  354. // mutex_ protects the following state.
  355. // We don't count mutex_ as the cache's internal state so semantically we
  356. // don't mind mutex_ invoking the non-const actions.
  357. mutable DMutex mutex_;
  358. // A reference to Cache::eviction_callback_
  359. const Cache::EvictionCallback& eviction_callback_;
  360. };
  361. class LRUCache
  362. #ifdef NDEBUG
  363. final
  364. #endif
  365. : public ShardedCache<LRUCacheShard> {
  366. public:
  367. explicit LRUCache(const LRUCacheOptions& opts);
  368. const char* Name() const override { return "LRUCache"; }
  369. ObjectPtr Value(Handle* handle) override;
  370. size_t GetCharge(Handle* handle) const override;
  371. const CacheItemHelper* GetCacheItemHelper(Handle* handle) const override;
  372. void ApplyToHandle(
  373. Cache* cache, Handle* handle,
  374. const std::function<void(const Slice& key, ObjectPtr obj, size_t charge,
  375. const CacheItemHelper* helper)>& callback)
  376. override;
  377. // Retrieves number of elements in LRU, for unit test purpose only.
  378. size_t TEST_GetLRUSize();
  379. // Retrieves high pri pool ratio.
  380. double GetHighPriPoolRatio();
  381. };
  382. } // namespace lru_cache
  383. using LRUCache = lru_cache::LRUCache;
  384. using LRUHandle = lru_cache::LRUHandle;
  385. using LRUCacheShard = lru_cache::LRUCacheShard;
  386. } // namespace ROCKSDB_NAMESPACE