github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/util/lru_cache.h (about) 1 // Copyright (C) 2018 go-nebulas authors 2 // 3 // This file is part of the go-nebulas library. 4 // 5 // the go-nebulas library is free software: you can redistribute it and/or 6 // modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation, either version 3 of the License, or 9 // (at your option) any later version. 10 // 11 // the go-nebulas library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with the go-nebulas library. If not, see 18 // <http://www.gnu.org/licenses/>. 19 // 20 21 #pragma once 22 23 #include "common/common.h" 24 #include <atomic> 25 #include <list> 26 #include <mutex> 27 #include <thread> 28 29 namespace neb { 30 namespace util { 31 32 template <class Key, class Value, class Lock = std::mutex, 33 int32_t CacheCleanPeriod = 1, int32_t CacheCleanCounter = 64> 34 class lru_cache { 35 public: 36 typedef std::unordered_map<Key, Value> map_t; 37 typedef Lock lock_t; 38 using guard_t = std::lock_guard<lock_t>; 39 40 lru_cache() : m_thread_exit_flag(0) { 41 m_thread = std::make_unique<std::thread>([&]() { 42 while (!m_thread_exit_flag) { 43 decrease_counter_and_clean_cache(); 44 std::this_thread::sleep_for(std::chrono::seconds(CacheCleanPeriod)); 45 } 46 }); 47 } 48 virtual ~lru_cache() { 49 m_thread_exit_flag = 1; 50 m_thread->join(); 51 }; 52 53 size_t size() const { 54 guard_t __l(m_lock); 55 return m_cache_map.size(); 56 } 57 58 bool empty() const { 59 guard_t __l(m_lock); 60 return m_cache_map.empty(); 61 } 62 63 void clear() { 64 guard_t __l(m_lock); 65 m_cache_map.clear(); 66 m_counter.clear(); 67 } 68 69 void set(const Key &k, const Value &v) { 70 guard_t __l(m_lock); 71 const auto iter = m_cache_map.find(k); 72 if (iter != m_cache_map.end()) { 73 return; 74 } 75 76 m_cache_map[k] = v; 77 m_counter[k] = CacheCleanCounter; 78 } 79 80 bool get(const Key &k, Value &v) { 81 guard_t __l(m_lock); 82 const auto iter = m_cache_map.find(k); 83 if (iter == m_cache_map.end()) { 84 return false; 85 } 86 v = iter->second; 87 m_counter[k] = CacheCleanCounter; 88 89 return true; 90 } 91 92 bool exists(const Key &k) const { 93 guard_t __l(m_lock); 94 return m_cache_map.find(k) != m_cache_map.end(); 95 } 96 97 template <typename F> void watch(F &&f) const { 98 guard_t __l(m_lock); 99 std::for_each( 100 m_cache_map.begin(), m_cache_map.end(), 101 [&f](const std::pair<Key, Value> &it) { f(it.first, it.second); }); 102 } 103 104 protected: 105 void decrease_counter_and_clean_cache() { 106 guard_t __l(m_lock); 107 std::unordered_set<Key> to_remove_sets; 108 for (auto it = m_counter.begin(); it != m_counter.end(); ++it) { 109 it->second--; 110 if (it->second <= 0) { 111 to_remove_sets.insert(it->first); 112 } 113 } 114 for (auto key : to_remove_sets) { 115 m_cache_map.erase(key); 116 m_counter.erase(key); 117 } 118 } 119 120 private: 121 mutable Lock m_lock; 122 map_t m_cache_map; 123 std::unordered_map<Key, int32_t> m_counter; 124 std::unique_ptr<std::thread> m_thread; 125 std::atomic_int m_thread_exit_flag; 126 }; 127 } // namespace util 128 } // namespace neb